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
Du schreibst im Slave Interrupt die Variable i_spi ungeschützt. Wird diese eventuell in einem Main Thread gelesen oder geschrieben?
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.
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
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.
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.
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 ;-)
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.
Was irgendwie nicht durchkam : - wie hoch ist der SPI Clock ? - Wieviel Zeit hat der slave um zu antworten.
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.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.