Archiv verlassen und diese Seite im Standarddesign anzeigen : Software-SPI-Slave mit Tiny13V
ExKluski
18.01.2012, 12:29
Hy zusammen,
ich versuche ein SW-SPI-Slave zu schreiben, aber es haut nicht hin.
Ne Master Version habe ich gefunden und die wollte ich zum Slave umschreiben.
unsigned int SPI_Write_Word(unsigned int word)
{
unsigned char i;
unsigned int mask;
unsigned int temp;
SPI_SS_PORT &= ~(1<<SPI_SS_PIN); //SS auf Low Schalten Start der Übertragung
mask = 0x8000;
temp = 0;
for(i=0;i<15;i++)
{
if(mask | word) SPI_MOSI_PORT|=(1<<SPI_MOSI_PIN);
else SPI_MOSI_PORT&=~(1<<SPI_MOSI_PIN);
if(SPI_MISO_PIN == 1) temp |= mask;
SPI_CLK_PORT |=(1<<SPI_CLK_PIN); //CLK-Takt HIGH
SPI_CLK_PORT &=~(1<<SPI_CLK_PIN); //CLK LOW
mask >>= 1;
}
SPI_SS_PORT |= (1<<SPI_SS_PIN); //SS auf High Schalten Ende der Übertragung
return(temp);
}
eigendlich dachte ich es wäre einfacher :(
Ports ändern von Ausgang auf eingang schalten und Bit-maske schieben (clk-Abhängig)
bei der Bitmaske habe ich jetzt das problem.
Hey ExKluski,
schau Dir mal diesen Slave Code an:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
volatile unsigned char data;
unsigned char status;
SIGNAL (SIG_SPI) {
data = SPDR;
if (data == '1') PORTD = 0x00; //LEDs an
if (data == '0') PORTD = 0xff; //LEDs aus
}
void slave_init (void) {
DDRB |= _BV(PB4); //MISO als Ausgang, der Rest als Eingang
SPCR = _BV(SPE) | _BV(SPIE); //Aktivierung des SPI + Interrupt
status = SPSR; //Status löschen
}
int main (void) {
DDRD = 0xff;
slave_init ();
sei ();
for (;;);
return 0;
}
Quelle: http://www.mikrocontroller.net/topic/12197
E (http://www.ermicro.com/blog/?p=1050)s ist schwer Deinem Code etwas zu entlocken, wie sieht der Rest aus, hast Du alle nötigen includes? Wie sieht Deine main() aus?
Ist Deine Schaltung korrekt?
Gruß
ExKluski
18.01.2012, 13:56
Danke für die schnelle antwort.
Den code kenne ich, aber läuft nicht auf den AtTiny13 weil er HW-SPI ist.
>>Es ist schwer Deinem Code etwas zu entlocken
klar sehe ich gerade auch. der code ist aus einer SW-SPI-Master code um ein AVR mit 2 MAX3100 als SPI-UART-brigde.
QUELLE: http://www.mikrocontroller.net/attachment/129087/microbus_application_note001dual_rs485.pdf
>> Du alle nötigen includes?
denke ich mal. habe zurzeit eine 1 IO.h werde später Interrupt.h noch ein binden als Taktgeber für CLK ex.INT0.
die main ist noch nicht fertig. Ich beschreibe mal was gemacht werden soll dann versteht man den code besser (hoffe ich)
der Tiny13 soll adc werte als slave an Attiny2313(Master) per spi schicken (AVR-CDC-SPI) und ma PC-terminal ausgeben.
So dachte ich mir wie SPI-Slave funktioniert SS schaltet Low. Tiny13 weiss es wird gesendet und schiebt immer ein Bit raus wenn CLK high wird. Bis alle Bits gesendet sind.
Die Schatung für den tiny2313 läuft und kann per command SS0 und SS1, High bzw Low geschalten werden.
Der Code für Tiny13
#include <avr/io.h> // Namen der IO Register
#include "adc-init.h"
#include "SPI-init.h"
unsigned int SPI_Write_Word(unsigned int word)
{
uint16_t MSB = 0b100000000000000; // Letzte bit
uint16_t temp = 0;
//CLK gibt den takt/übertagungsgeschwindigkeit vor MISO und MOSI halten sich daran
if(SPI_CLK_PB2 & (1<<SPI_CLK_PB2)) //wen sck auf High wird 1 bit gesende
{
if(MSB & word)SPI_MISO_PORT |= (1<<SPI_MISO_PB3); //Pin Miso high
else SPI_MISO_PORT &= ~(1<<SPI_MISO_PB3);
MSB <<=1; //MSB First
}
else //wenn clk low ist nichts machen
return (temp);
}
int main(void)
{
uint16_t adcval;
ADC_Init();
while( 1 ) {
adcval = ADC_Read(3); // Kanal 0
// mach was mit adcval
adcval = ADC_Read_Avg(2, 4); // Kanal 2, Mittelwert aus 4 Messungen
// mach was mit adcval
if(!(SPI_SS_PB1 & (1<<SPI_SS_PB1))) // Wenn SS(PB1) auf low geht start der Übertragung
{
SPI_Write_Word(adcval); //
}
else
{
}
}
return 0;
}
Mit dem code ADC-Init lief eigendlich ohne probleme auf mega8 habe die register für tiny13 angepasst
/* ADC initialisieren */
void ADC_Init(void) {
uint16_t result;
// ADMUX = (0<<REFS1) | (1<<REFS0); // AVcc als Referenz benutzen
ADMUX = (1<<REFS0)|(1<<MUX1)|(1<<MUX0); // interne Referenzspannung nutzen
// Bit ADFR ("free running") in ADCSRA steht beim Einschalten
// schon auf 0, also single conversion
ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
ADCSRA |= (1<<ADEN); // ADC aktivieren
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
while (ADCSRA & (1<<ADSC) ) {} // auf Abschluss der Konvertierung warten
/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
Wandlung nicht übernommen. */
result = ADCW;
}
/* ADC Einzelmessung */
uint16_t ADC_Read( uint8_t channel )
{
// Kanal waehlen, ohne andere Bits zu beeinflußen
ADMUX = (ADMUX & ~(0x0F)) | (channel & 0x0F); //ADC3 ist PB3
ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
while (ADCSRA & (1<<ADSC) ) {} // auf Abschluss der Konvertierung warten
return ADCW; // ADC auslesen und zurückgeben
}
/* ADC Mehrfachmessung mit Mittelwertbbildung */
uint16_t ADC_Read_Avg( uint8_t channel, uint8_t average )
{
uint32_t result = 0;
for (uint8_t i = 0; i < average; ++i )
result += ADC_Read( channel );
return (uint16_t)( result / average );
}
Der Spi-init ist nur die PORT deklaration
//DDRB
#define SPI_MOSI_DDR DDRB
#define SPI_CLK_DDR DDRB
#define SPI_MISO_DDR DDRB
#define SPI_SS_DDR DDRB
//PORTB
#define SPI_MOSI_PORT PORTB
#define SPI_CLK_PORT PORTB
#define SPI_MISO_PORT PORTB
#define SPI_SS_PORT PORTB
// PIN
#define SPI_MOSI_PB0 PB0
#define SPI_SS_PB1 PB1
#define SPI_CLK_PB2 PB2
#define SPI_MISO_PB3 PB3
//Slave-deklaration
void SPI_INIT(void)
{
// MOSI, CLK und SS auf Eingang setzen
SPI_MOSI_DDR = (1<<SPI_MOSI_PB0);
SPI_CLK_DDR = (1<<SPI_CLK_PB2);
SPI_SS_DDR = (1<<SPI_SS_PB1);
// MOSI, CLK und SS Internen Pull-Up aktivieren
SPI_MOSI_PORT |=(1<<SPI_MOSI_PB0);
SPI_CLK_PORT |=(1<<SPI_CLK_PB2);
SPI_SS_PORT |=(1<<SPI_SS_PB1);
// MISO auf Ausgang setzen
SPI_MISO_DDR |= (1<<SPI_MISO_PB3);
//MISO auf High setzten
SPI_MISO_PORT |= (1<<SPI_MISO_PB3);
}
hoffe Ihr erschlägt mich nicht für den langen Post bzw. schreckt nicht ab :)
Was ich so auf den ersten Blick sehe (also kein Anspruch auf Vollständigkeit):
1)
uint16_t MSB = 0b100000000000000; // Letzte bitFür solche Konstanten die binäre Schreibweise zu verwenden, ist meist keine so gute Idee. Bei den vielen Nullen verzählt man sich schon mal, und genau das hast du auch.
2)
if(SPI_CLK_PB2 & (1<<SPI_CLK_PB2))
if(!(SPI_SS_PB1 & (1<<SPI_SS_PB1)))Diese if-Bedingungen machen überhaupt keinen Sinn, und sind immer false.
3)
MSB <<=1;Falsche Richtung.
4)
Wo ist der Rest von SPI_Write_Word?
ExKluski
18.01.2012, 14:46
zu 1) :p
uint16_t MSB = 0x8000;
zu 2) Ich dachte als abfrage für die Pins.
SS Solange SS high nichts machen und sobald low ist mit dem senden anfangen
Und bei CLK fast genauso nur er soll schieben wenn CLK high ist.
zu 3) Er soll mit dem Höchsten bit anfangen?
zu 4) habe kein Rest nur die SW-SPI-Master Funktion von oben (1.post), da habe ich die sachen die ich nicht brauche (glaube ich zu mindestens) weg gelassen, Weil SS und CLK wird ja dem Tiny13 vom Tiny2313 geschickt.
MfG exkluski
zu 2) Ich dachte als abfrage für die Pins.Und wo in diesen Bedingungen wird irgendetwas abgefragt? Da steht einfach nur
if (2 & (1<<2)))
zu 3) Er soll mit dem Höchsten bit anfangen? Und? Wie sieht MSB nach dieser Operation aus?
zu 4) habe kein Rest nur die SW-SPI-Master Funktion von oben (1.post)Da wird also genau ein Bit ausgegeben. Was ist mit den anderen 15?
ExKluski
18.01.2012, 15:45
Mit der abfrage habe ich mich verlesen sollte so heißen
if(!(SPI_SS_PIN1 & (1<<SPI_SS_PB1)))
Und? Wie sieht MSB nach dieser Operation aus?
1 Bit weiter schieben und das dann ausgeben, mache ich das nicht mit
MSB<<=1;
es ist doch in einer schleife die Solange durchlaufen wird bis 16 bit raus geschoben sind.
MfG exkluski
Mit der abfrage habe ich mich verlesen sollte so heißen
if(!(SPI_SS_PIN1 & (1<<SPI_SS_PB1)))Ob das jetzt korrekt ist, hängt davon ab, wie SPI_SS_PIN1 definiert ist. Die 1 darin lässt allerdings nichts Gutes vermuten.
1 Bit weiter schieben und das dann ausgeben, mache ich das nicht mit
MSB<<=1;
es ist doch in einer schleife die Solange durchlaufen wird bis 16 bit raus geschoben sind.
MfG exkluskiNochmal: wenn MSB vorher 0x8000 ist, was ist es dann hinterher?
Und wo bitte ist diese Schleife?
ExKluski
18.01.2012, 16:09
hinterher ist er 0, wäre es dann nicht besser es als Globale Variable "volatile" und die Richtung zu ändern
Die Schleife meine ich
for(i=0;i<15;i++)
{
if(mask | word) SPI_MOSI_PORT|=(1<<SPI_MOSI_PIN);
else SPI_MOSI_PORT&=~(1<<SPI_MOSI_PIN);
if(SPI_MISO_PIN == 1) temp |= mask;
SPI_CLK_PORT |=(1<<SPI_CLK_PIN); //CLK-Takt HIGH
SPI_CLK_PORT &=~(1<<SPI_CLK_PIN); //CLK LOW
mask >>= 1;
}
Die Schleife meine ich
Und was hat diese Schleife mit deinem Slave-Code zu tun? Wo ist da eine Schleife?
ExKluski
18.01.2012, 16:21
Sorry mein fehler habe mich mit der schleife falsch ausgedrückt.
Klar im slave habe ich keine schleife
es ist doch in einer schleife die Solange durchlaufen wird bis 16 bit raus geschoben sind.
damit meinte ich den master-code der in einer Zählschleife ist und 16 mal schiebt.
Sorry mein fehler habe mich mit der schleife falsch ausgedrückt.
Klar im slave habe ich keine schleife
damit meinte ich den master-code der in einer Zählschleife ist und 16 mal schiebt.Das beantwortet aber nicht die Frage, was das jetzt mit dem Slave-Code zu tun haben soll? Dort wird nach wie vor nur ein Bit ausgegeben.
ExKluski
18.01.2012, 16:53
jetzt habe ich es glaube verstanden wie du das meinst. Klar im slave code ist keine schleife also wird auch nur einmal geschoben.
ExKluski
20.01.2012, 18:31
Nach längerem grübeln ist der Code entstanden ich würde mich freuen wenn sich jemand durchschaut und auf anhieb fehler erkennt bzw. ob es so richtig ist wie ich es mir vorgestellt habe.
bei der Warnung bin ich ratlos
../spi-tiny13.c:38: warning: suggest parentheses around assignment used as truth value
weiss aber nichts damit anzufangen.
Also das Programm soll ein SPI slave simulieren und ADC-werte schicken.
Am MISO(PB3) werden dann die Pegel Geschaltet,
Ich bin mir aber nicht Sicher ob der befehl das macht was ich will
while(GIMSK & (1<<INT0));
//warte bis am Externen Interrupt etwas passiert
Und das ist mein ganzer Code
#include <avr/io.h> // Namen der IO Register
#include <avr/Interrupt.h> // Interrupt register
#include "adc-init.h"
#include "SPI-init.h"
volatile char MISO_Byte;
volatile int MSB = 0x8000;
ISR(INT0_vect)
{
if(MISO_Byte == 1)SPI_MISO_PORT |= (1<<SPI_MISO_PB3); //Pin Miso high
else SPI_MISO_PORT &= ~(1<<SPI_MISO_PB3);
}
int main(void)
{
uint16_t adcval;
ADC_Init();
/*Externen Interrupt-Init*/
MCUCR = (1<<ISC01)|(1<<ISC00);
//Interrupt auslösen wenn Steigende flanke ist
GIMSK = (1<<INT0); // Interrupt erlauben
GIFR = (1<<INTF0);
while( 1 ) {
adcval = ADC_Read(0); // Kanal 0
// mach was mit adcval
adcval = ADC_Read_Avg(2, 4); // Kanal 2, Mittelwert aus 4 Messungen
// mach was mit adcval
MISO_Byte = MSB | adcval;
if(!(SPI_SS_PIN1 & (1<<SPI_SS_PB1)))// Wenn SS(PB1) auf low geht start der Übertragung
{
==>c35 for(uint16_t a =15 ; a = 0 ; a--)//Warning: suggest parentheses around assignment used as truth value
{
if(MISO_Byte & MSB)SPI_MISO_PORT |= (1<<SPI_MISO_PB3);
else SPI_MISO_PORT &= ~(1<<SPI_MISO_PB3);
while(GIMSK & (1<<INT0));
//warte bis am Externen Interrupt etwas passiert
MISO_Byte<<=1;// Bit nach Links schieben
}
}
else;
}
return 0;
}
Ich bedanke mich schonmal für die Kritik :P
MfG Kluski
radbruch
20.01.2012, 18:47
for(uint16_t a =15 ; a < 16 ; a--)
1)
if(!(SPI_SS_PIN1 & (1<<SPI_SS_PB1)))Da würde ich gerne mal die Definition von SPI_SS_PIN1 sehen.
2)
for(uint16_t a =15 ; a = 0 ; a--)"a = 0" ist eine Zuweisung, kein Vergleich. Aber auch wenn es ein Vergleich wäre, wäre es falsch, denn die Bedingung in einer for-Schleife ist eine "solange"-Bedingung, keine "bis"-Bedingung.
3)
while(GIMSK & (1<<INT0));
//warte bis am Externen Interrupt etwas passiertDa muss ich dich jetzt aber mal ernsthaft fragen: wie kommst du nur darauf? Was im Datenblatt lässt dich denken, dass dieses while das machen könnte, was im Kommentar steht?
4) Und last but not least, warum wird sowohl in einer Schleife in main, als auch in einer ISR etwas auf dem MISO-Pin ausgegeben?
5) Du willst 16 Bits aus einem Byte ausgeben?
Ich sehe gerade, dass du auch schon einen längeren Thread auf mikrocontroller.net hast. Damit bin ich raus. Ich habe schlicht keine Lust, zwei Threads zu checken, um zu sehen, ob ich meine Zeit nicht damit verschwende, Dinge zu schreiben, die vielleicht längst gesagt wurden.
Folgendes zum "Abschied":
Erst musst du dir mal darüber klar werden, ob das eigentliche Raustakten der Daten nun per Interrupt, oder per Polling erfolgen soll, und ob es 8 oder 16 Bit sind. Für 16 Bit Polling sieht der Pseudo-Code dann z.B so aus:
mache 16 mal {
warte bis Takteingang high
gebe Bit aus
schiebe zum nächsten Bit
warte bis Takteingang low
}
ExKluski
20.01.2012, 20:12
zu 1)
//DDRB
#define SPI_MOSI_DDR DDRB
#define SPI_CLK_DDR DDRB
#define SPI_MISO_DDR DDRB
#define SPI_SS_DDR DDRB
//PORTB
#define SPI_MOSI_PORT PORTB
#define SPI_CLK_PORT PORTB
#define SPI_MISO_PORT PORTB
#define SPI_SS_PORT PORTB
// PIN
#define SPI_MOSI_PIN0 PINB0
#define SPI_SS_PIN1 PINB1
#define SPI_CLK_PIN2 PINB2
#define SPI_MISO_PIN3 PINB3
//PB
#define SPI_MOSI_PB0 PB0
#define SPI_SS_PB1 PB1
#define SPI_CLK_PB2 PB2
#define SPI_MISO_PB3 PB3
//Slave-deklaration
void SPI_INIT(void)
{
// MOSI, CLK und SS auf Eingang setzen
SPI_MOSI_DDR = (1<<SPI_MOSI_PB0);
SPI_CLK_DDR = (1<<SPI_CLK_PB2);
SPI_SS_DDR = (1<<SPI_SS_PB1);
// MOSI, CLK und SS Internen Pull-Up aktivieren
SPI_MOSI_PORT |=(1<<SPI_MOSI_PB0);
SPI_CLK_PORT |=(1<<SPI_CLK_PB2);
SPI_SS_PORT |=(1<<SPI_SS_PB1);
// MISO auf Ausgang setzen
SPI_MISO_DDR |= (1<<SPI_MISO_PB3);
//MISO auf High setzten
SPI_MISO_PORT |= (1<<SPI_MISO_PB3);
}
zu 2) Mein fehler geändert in
for(uint16_t a =15 ; a > 0; a--)
zu3) Kennst du das nicht im Kopf Klang es logisch, eigentlich wollte ich damit erreichen das er an der stelle warten soll bist der externe Int0 ausgelöst wird.
zu4) Ne es soll nur etwas am miso-pin passieren wenn der der interrupt ausgelöst wird.
zu5) es werden 16-bit ausgegeben habe es nur byte genannt.
MfG Kluski
ExKluski
20.01.2012, 20:19
zu1 ) Bitte
//DDRB
#define SPI_MOSI_DDR DDRB
#define SPI_CLK_DDR DDRB
#define SPI_MISO_DDR DDRB
#define SPI_SS_DDR DDRB
//PORTB
#define SPI_MOSI_PORT PORTB
#define SPI_CLK_PORT PORTB
#define SPI_MISO_PORT PORTB
#define SPI_SS_PORT PORTB
// PIN
#define SPI_MOSI_PIN0 PINB0
#define SPI_SS_PIN1 PINB1
#define SPI_CLK_PIN2 PINB2
#define SPI_MISO_PIN3 PINB3
//PB
#define SPI_MOSI_PB0 PB0
#define SPI_SS_PB1 PB1
#define SPI_CLK_PB2 PB2
#define SPI_MISO_PB3 PB3
//Slave-deklaration
void SPI_INIT(void)
{
// MOSI, CLK und SS auf Eingang setzen
SPI_MOSI_DDR = (1<<SPI_MOSI_PB0);
SPI_CLK_DDR = (1<<SPI_CLK_PB2);
SPI_SS_DDR = (1<<SPI_SS_PB1);
// MOSI, CLK und SS Internen Pull-Up aktivieren
SPI_MOSI_PORT |=(1<<SPI_MOSI_PB0);
SPI_CLK_PORT |=(1<<SPI_CLK_PB2);
SPI_SS_PORT |=(1<<SPI_SS_PB1);
// MISO auf Ausgang setzen
SPI_MISO_DDR |= (1<<SPI_MISO_PB3);
//MISO auf High setzten
SPI_MISO_PORT |= (1<<SPI_MISO_PB3);
}
zu 2) mein fehler
for(uint16_t a =15 ; a > 0; a--)
zu3) Kennst du das nicht auch im Kopf Klang es Logisch :D damit meine ich er soll warten bis der Interrupt ausgelöst.
zu4) da wusste ich nicht wie ich das schreiben sollte. Ich will das er ein bit am MISO aus gibt wenn der Interrupt ausgelöst wird und ein bit weiter schiebt
zu5) er heisst nur Byte damit ich weiss es sind mehre bits
MfG Exkluski
Ok, meinetwegen noch einen letzten Post:
zu 1) Dann ist die if-Bedingung immer noch Unsinn.
zu 2) Die Schleife wird aber nur 15 mal durchlaufen.
zu 3 und 4 und auch noch 2) Siehe meinen vorigen Post.
zu 5) Du hast es nicht nur so genannt, im aktuellen Code ist es tatsächlich auch nur ein Byte.
ExKluski
20.01.2012, 21:50
Klar verstehe ich das es dich anpisst, aber danke für die hilfe.
Werde mir die posts mehrmals durchlesen bis ich es verstanden habe. ;)
Danke nochmals
mfg exkluski
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.