Forum: Mikrocontroller und Digitale Elektronik Probleme mit SPI Uebertragung


von Egonwalter M. (heiner1234)


Angehängte Dateien:

Lesenswert?

Hallo
Ich habe ein Problem mit dem SPI, es werden sporadisch falsche Daten 
ausgegeben - im "Empfangsarray" = rec_byte[ARRAY_LEN] des Masters stehen 
nicht die Sendedaten des Slaves, sondern die eigenen Sendedaten um 1 
Byte verschoben.

Zu meinem Aufbau - 2 ATMega 328 mit 3,68 MHz; einer ist Master, einer 
ist Slave. Daten zwischen beiden werden per SPI ausgetauscht; beim 
Master erfolgt der SPI Aufruf per polling im Hauptprogramm alle ca 30ms, 
bei Slave per Interrupt. Die Daten werden je in ein 22 Byte großes Array 
geschrieben (rec_byte[22], sen_byte[22]). Die Datenausgabe per USART 
(Master) ebenfalls alle ca 30ms (beim Master zuerst Ausgabe der Sende- 
und Empfangsdaten, dann Aufruf der SPI Funktion).

In den SPI-Leitungen sind 1kOhm Widerstaende, die /SS Leitung ist mit 
10kOhm gegen Vcc geschaltet.

Hardware Verbindung vom Slave (PORTD, PD4) zum Master (INT1, PD3):
Slave generiert Interrupt beim Master ("Freigabe"), wenn Daten vom SPI 
gelesen werden koennen; der Master "wartet" auf "Freigabe", wenn er 
Daten vom Slave einliest.

Die SPI-Leitung ist ca 15cm lang, beide ATMega haengen an der gleichen 
Spannungsversorgung. Ausgegeben werden die gesendeten und empfangenen 
Daten per USART (115kB).

SLAVE:
- Die Sendedaten (sen_byte[ARRAY_LEN]) werden beim Slave gesendet und 
beim Master inden rec_byte[ARRAY_LEN] eingetragen
- Die Empfangsdaten (rec_byte[ARRAY_LEN]) werden beim Slave eingetragen 
(vom Master
als sen_byte[ARRAY_LEN]) gesendet

Master:
- dito umgekehrt.

==> sen_byte[ARRAY_LEN] MASTER = rec_byte[ARRAY_LEN] SLAVE.

==> sen_byte[ARRAY_LEN] SLAVE = rec_byte[ARRAY_LEN] MASTER.

Anbei:
master.c - Initialisierung des SPI und zykl. Aufruf
slave.c - Initialisierung des SPI und ISR
fehler_spi.txt

Vielleicht kennt jemand eine Loesung fuer das beschriebene Problem...

mfg

Egon

von Daniel A. (daniel_a32)


Lesenswert?

Du schreibst im Slave Interrupt die Variable i_spi ungeschützt. Wird 
diese eventuell in einem Main Thread gelesen oder geschrieben?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Egonwalter M. schrieb:
> Zu meinem Aufbau - 2 ATMega 328 ... einer ist Master, einer ist Slave.
Der SPI ist ein ungünstiger Bus, wenn der Slave ein µC ist. Denn der ist 
dann wirklich der Knecht seines Herrn und zu schneller Reaktion 
verdammt, denn er muss die Daten immer genau und rechtzeitig in dem 
Augenblick vorlegen, wenn der Master es verlangt.

> In den SPI-Leitungen sind 1kOhm Widerstaende.
Echt jetzt? Serienwiderstände mit 1k? Wie schnell taktest du den SPI?

> Vielleicht kennt jemand eine Loesung fuer das beschriebene Problem...
Also ich würde da mal das Oszi auspacken und schauen, ob die Bussignale 
direkt an den jeweiligen IC-Pins gut aussehen (Timing, Pegel, Flanken, 
Klingeln,...) und dann mal schauen, ob diese Bytes tatsächlich auf dem 
Bus zu sehen sind.

von Peter D. (peda)


Lesenswert?

Egonwalter M. schrieb:
> im "Empfangsarray" = rec_byte[ARRAY_LEN] des Masters stehen
> nicht die Sendedaten des Slaves, sondern die eigenen Sendedaten um 1
> Byte verschoben.

Dann war der Slave zu langsam oder mit anderen Tasks beschäftigt und 
konnte den Slaveinterrupt nicht schnell genug ausführen. SPI hat den 
großen Mangel, daß es kein Handshake kann.

SPI-Slave auf MCs geht nur zuverlässig, wenn der Slave-MC Sendepuffer, 
DMA oder Interruptlevel hat. Der AVR kann jedoch keines davon. Sprich, 
SPI-Slave auf dem AVR ist ne einzige Krücke.
Als Würg-Around müßte der Master nach /SS-low und nach jedem Byte lange 
Gedenkpausen einlegen. Z.B. man legt einen Puffer im Master an und der 
Timerinterrupt 1ms macht dann die einzelnen SPI-Aktionen. Ist natürlich 
nicht sonderlich schnell.
/SS-low muß per externem Interrupt das erste Byte in das SPI-Register 
stellen oder man definiert das erste Byte als Müll.

Nimm besser I2C oder UART.


P.S.:
Mit den Schnipselchen kann man wenig anfangen. Poste ein komplettes 
lauffähiges Main mit allen Variablen und Aufrufen.

: Bearbeitet durch User
von Harald (Gast)


Lesenswert?

Ein typischer Fall, wo einem der Einsatz eines Logic Analyzers (ab 5€) 
völlig neue Einblicke und Erkenntnisse bringen wird. Investiere es, Du 
wirst es nicht bereuen.

von Peter D. (peda)


Lesenswert?

Harald schrieb:
> Ein typischer Fall, wo einem der Einsatz eines Logic Analyzers (ab 5€)
> völlig neue Einblicke und Erkenntnisse bringen wird.

Nö, das Fehlerbild ist doch eindeutig. Das SPI-Register wird nicht 
schnell genug geladen. In diesem Fall, weil der AVR es nicht besser 
kann.

C-hater wird bestimmt gleich hervorpreschen und "nimm Assembler" sagen. 
Das wäre aber auch nur ein Würg-Around gegen grobe Designfehler des 
AVR-SPI.

von Supergast (Gast)


Lesenswert?

Der Tip mit dem Logic-Analyzer ist wirklich gut. wenn Du ein paar € 
drauflegst, bekommst Du auch einen, der die übertragenen Bits gleich 
dekodiert, und Dir den ASCII oder HEX Wert anzeigt.

Als Zweites solltest in den SPI Bus eine AC-Terminierung einbauen, dann 
sind die Reflexionen deutlich kleiner.


Zum Fehler selbst:
Das scheint für den Slave zu schnell zu gehen. Setze die 
Übertragungsgeschwindigkeit doch einfach mal sehr stark herab z.B. auf 
9600 ;-)

von Harald (Gast)


Lesenswert?

Peter D. schrieb:
> Nö, das Fehlerbild ist doch eindeutig.

Mag sein, neue Einblicke und Erkenntnisse bringt es aber in jedem Fall. 
Ist jedenfalls meine Erfahrung mit Zeitgenossen, die so ein Ding zum 
ersten Mal einsetzen. Ich wollte es jedenfalls nicht mehr missen, zeigt 
einem auch kritische Dinge auf, die vielleicht gerade mal so gutgehen, 
trotzdem aber verbesserungswürdig sind.

von Pandur S. (jetztnicht)


Lesenswert?

Was irgendwie nicht durchkam  :
- wie hoch ist der SPI Clock ?
- Wieviel Zeit hat der slave um zu antworten.

von Peter D. (peda)


Lesenswert?

Ein zusätzliches Handshake scheint implementiert zu sein. Nur wird im 
Slave Byte 0 sofort mit Byte 1 überschrieben.
Ob das erste Byte vom Slave Müll sein darf, geht nicht klar hervor.

von Egonwalter M. (heiner1234)


Lesenswert?

Hallo!

Vielen Dank für Eure Hinweise!

@Daniel A:
- die Variable i_spi ist beim Slave global deklariert=> static volatile 
uint8_t i_spi = 0 und
wird in main() ausgewertet und auf Null gesetzt.

@Lothar M:
- SPI taktet mit SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0); /* SPI Master 
Mode, SCK = CK/16 */,
3,686MHz = 230400
- 1kOhm in den Leitungen wurde mir in einem anderen Forum mal empfohlen, 
da ich den Slave per
ISP programmiere und die SPI- Leitungen nicht abziehen will.
- Oszi habe ich (leider) keinen (ja, ich weiß "Ohne Oszi kann man nicht 
...")

@Peda:
- USART und TWI/I2C verwende ich schon anderweitig. Bei beiden (Master 
und Slave) nutze ich
USART zum Debuggen, und ich habe mehrere Porterweiterungen (LCD beim 
Master und
6 7_segmentanzeigen beim Slave nebst diversen LEDs und Tastern).
Ausserdem wollte ich ausprobieren, ob ich eine funktionsfähige SPI 
Kommunikation zu Stande
bringe.
Die "Schnipselchen" sind ja nur Initialisierung und 
Funktionsdefinitionen für den SPI beim
Master und beim Slave; ich kann schon beide Programme hier reinstellen, 
kann mir aber beim
besten Willen nicht vorstellen, dass jemand Lust hat, jeweils mehr als 
1600 Zeilen Code
zu durchforsten.

@Harald:
- ich habe weder Oszi noch Logikanaylzer (ja, ich weiß "Ohne Oszi kann 
man nicht ...")

@Supergast
- was verstehst Du unter "AC Terminierung"? Und die 
Übertragungsgeschwindigkeit kann ich
gemaess Datenblatt ATMega328 nur auf 28800 runtersetzen, nicht auf 9600.

@Pandur S:
- SPI clock siehe @Lothar M: - 230400
- der Slave antwortet per Interrupt

@Peda
- ja eine Art Handshake ist implentiert (ist aber keine Hilfe beim 
dargestellten Problem).
Wg Handshake - wenn Slave seine Daten ins SPDR geschrieben hat, wird 
beim Master ein
Interrupt erzeugt - Bit gesetzt, welches dann beim Master abgefragt wird 
(while - warte) und
erst wenn die while-Bedingung erfüllt ist füllt der Master das SPDR mit 
dem Sendebyte.

mfg
Egon

: Bearbeitet durch User
von Egonwalter M. (heiner1234)


Lesenswert?

Hallo!

Kurzes Update: ich habe gemäß Vorschlag von:

Supergast schrieb:

> Zum Fehler selbst:
> Das scheint für den Slave zu schnell zu gehen. Setze die
> Übertragungsgeschwindigkeit doch einfach mal sehr stark herab z.B. auf
> 9600 ;-)

die Übertragungsgeschwindigkeit auf minimal gesetzt (28800) und siehe da 
- es funktioniert (mal für ca 4h getestet, keine Fehler).

Was noch bleibt ist dieses primitive Handshake korrekt zu implementieren 
und "zum Laufen" zu bringen.

mfg

Egon

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.