Forum: Mikrocontroller und Digitale Elektronik AVR SPI mehre Bytes senden


von Ivo K. (masterofeye)


Lesenswert?

Hallo an alle,

ich habe ein kleines Problem. Ich schreibe gerade einen Linux Treiber 
auf der anderen Seite ist ein Atmega128rf1a. Die Linuxkiste sendet eine 
SPI Message (0xac) daraufhin soll der Atmega etwas zurücksenden. Die 
Linuxkiste ist der Master. Weiterhin wird der CS zwischen den 8 Bit 
Packeten nicht getriggert bleibt also immer low während der Übertragung.
Beispielcode:

static int ui8Frame_Counter;
static u8 ui8Message_Buffer[250];

ISR (SPI_STC_vect)
{
  if (SPDR == 0xac){
    status = 1;
    ui8Frame_Counter=0;
  }

  if (status== 1){
    ui8Frame_Counter++;
    while(!(SPSR & (1<<SPIF)));
    get();
  }


}

uint8_t get(){

  SPDR = ui8Message_Buffer[ui8Frame_Counter];
}

Wenn die SPI ISR das magische Kommando 0xac bekommt sollen die Daten die 
im Buffer ui8Message_Buffer stehen gesendet werden. Die Funktion get 
besorgt sicht einfach das nächte Byte aus dem Buffer und schreibt es in 
das Register. Nun kommt aber folgendes an meiner Linuxmaschine an:
0x05
0xac
0x06
0xac

rauskommen sollte aber:

0x05
0x06
0x07
0x08 ...

Merkwürdiger weise wird die ISR nicht immer aufgerufen! Nur jedes zweite 
Packet kommt richtig an. Ich weiß einfach nicht warum. WEitere Infos: 
AUf dem Atmega läuft der AMTEL MAC Stack. Ich habe mal die Zeit zwischen 
zwei Packeten holen vergrößert -> Ergebnis war das gleiche. Weiß jemand 
woran das liegen kann? Wenn mehr infos benötigt werden liefer ich die 
gerne nach.

LG

MOE

von Karl H. (kbuchegg)


Lesenswert?

1
    while(!(SPSR & (1<<SPIF)));

in einer ISR auf das AUftreten eines Interrupt Flags zu warten, muss 
einem immer seltsam vorkommen.

Die ISR ist aufgerufen worden, #WEIL# vom Master ein Byte angekommen 
ist. Du brauchst da nicht noch zusätzlich warten. Das Byte ist schon da! 
Mit Sicherheit. Sonst wäre die ISR nicht aufgerufen worden.
Ganz im Gegenteil. MIt dem Betreten der ISR ist dieses Flag gelöscht 
worden, so dass du hier effektiv bereits auf das eintreffen des jeweils 
nächsten Bytes wartest.

(Und ich denke genau das ist der Grund, warum du nur jeden 2.ten 
Interrupt siehst.)

von Ivo K. (masterofeye)


Lesenswert?

Karl Heinz Buchegger schrieb:
>
1
>     while(!(SPSR & (1<<SPIF)));
2
>
>
> in einer ISR auf das AUftreten eines Interrupt Flags zu warten, muss
> einem immer seltsam vorkommen.
>
> Die ISR ist aufgerufen worden, #WEIL# vom Master ein Byte angekommen
> ist. Du brauchst da nicht noch zusätzlich warten. Das Byte ist schon da!
> Mit Sicherheit. Sonst wäre die ISR nicht aufgerufen worden.
> Ganz im Gegenteil. MIt dem Betreten der ISR ist dieses Flag gelöscht
> worden, so dass du hier effektiv bereits auf das eintreffen des jeweils
> nächsten Bytes wartest.
>
> (Und ich denke genau das ist der Grund, warum du nur jeden 2.ten
> Interrupt siehst.)

Ach Kopfschüttel. Alles klar!
Vielen Dank

von Ivo K. (masterofeye)


Lesenswert?

ICh muss nochmal stören ^^. Nun werden die Daten einfach nicht in das 
SPDR Register eingetragen ...

Ergebnis ist:

0xac   richtig
0xac   falsch ...
0
0
0
0
0

Darf ich den in der ISR keine Funktion aufrufen, die das SPDR Register 
setzt?

LG

MOE

von Karl H. (kbuchegg)


Lesenswert?

Ivo Kunadt schrieb:

> Darf ich den in der ISR keine Funktion aufrufen, die das SPDR Register
> setzt?

Der Satz aus dem Datasheet zb des Mega8 macht mir Sorgen
1
The system is single buffered in the transmit direction and double
2
buffered in the receive direction.
3
This means that bytes to be transmitted cannot be written to the SPI Data
4
Register before the entire shift cycle is completed.

Mir ist nicht ganz klar, ob mit 'cannot be written ... before completed' 
eine aktive Verriegelung des Shift-Registers gemeint ist oder nicht.
Das würde IMHO Bedeuten, dass der Master nach jedem Byte sinnvollerweise 
eine kleine Pause einlegen sollte, um so dem Slave die Zeit zu geben, 
das jeweils nächste Byte bereitzustellen, welches er sich mit der 
nächsten Übertragung des nächsten Bytes dann abholt.
Ich würde das probehalber auf Linux-Seite mal so machen.

Ansonsten gilt wie immer:
aktueller Code muss her.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Das würde IMHO Bedeuten, dass der Master nach jedem Byte sinnvollerweise
> eine kleine Pause einlegen sollte, um so dem Slave die Zeit zu geben,
> das jeweils nächste Byte bereitzustellen, welches er sich mit der
> nächsten Übertragung des nächsten Bytes dann abholt.

Ja, das geht letztlich nur so.

Microcontroller sind miserable SPI-Slaves, da beim SPI der Master
komplett das Timing vorgibt und der Slave keine Chance hat, die
weiße Flagge zu hissen und keuchend zu röcheln: "Ich kann gar nicht
so schnell!"

Braucbare SPI-Slaves muss man in Hardware implementieren, denn es ist
weiter nichts als ein Schieberegister.

Für Microcontroller und Software eignet sich I²C viel besser als
Protokoll, denn dort kann der Slave (durch Festklemmen der SCL-
Leitung) den Bus blockieren, bis er fertig ist.

von Ivo K. (masterofeye)


Lesenswert?

HEHE ja wir wollten schon I2C nehmen aber SPI war schon im Kerneln von 
Linux für unser Board ...

So nun mit ein wenig Delay funktionierts .... Sch ... DING!

Vielen Dank für die ausführlich Hilfe!!!!!

LG

MOE

von MCUA (Gast)


Lesenswert?

Das ist wie bei anderen Bussystemen auch.
Der Master muss/sollte das (WorstCase) Timing der angeschl. Teilnehmer 
kennen, und danach handeln. (synchr)
Optional kann (asynchr) der Slave ein Wait o.ä. zum Master schicken.

IIC ist nur was für Stricknadel-Frequenzen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.