Datum:
Angehängte Dateien:Mahlzeit - ich häng' fest! Ein Master (atmega162) soll ein Datenpaket über RS485 an einen Slave (attiny2313) schicken. Nach dem Einschalten und auf Tastendruck funktioniert das auch genau einmal. Gaaanz selten mehrmals hintereinander. Danach kommen (am meisten) nur noch (Datenlänge-1)Bytes (kontrolliert mit Pinwackeln an PIND6 vom tiny) oder weniger an. Extrem selten mal ein komplettes Datenpaket. Ein Übertragungsfehler (DatenUSARTin() mit 'return false') wird nie angezeigt. Nach längerer Pause (ca. 1min kein Tastendruck) hängt sogar die Senderoutine (kontrolliert mit PINB7 am mega). Die obigen Dateien gehören folgendermaßen zusammen: - Projekt 'Master': MainMaster.c, Timer0.c, USART.c - Projekt 'Slave': MainSlave.c, USART.c Ist alles etwas amateurmäßig, vielleicht kann trotzdem mal jemand drüberschauen und mich auf die richtige Fährte schicken. Vielen Dank.
Datum:
Neue Erkenntnis: Es muss (müsste) am Master liegen. Habe den Slave 'im laufenden Betrieb' neu geflasht: Master gestartet - Taste - ordentliche Datenübertragung - Taste - Slave schließt Empfang nicht ab, da letztes Byte fehlt - Slave neu beschrieben - Taste - Slave schließt Empfang nicht ab, da letztes Byte fehlt ... - Taste - Master schließt Senden nicht ab, bleibt im USART-Busy-Status. Also alles wie immer.
Datum:
Noch was neues: Es kommt im Fall der Übertragung von (n-1)Bytes immer das 3.Byte nicht an!?
Datum:
Ralf G. schrieb: > Noch was neues: Es kommt im Fall der Übertragung von (n-1)Bytes immer > das 3.Byte nicht an!? Moin! Ich hab zwar keine Ahnung, aber ich werf mal Fragen in den Raum: - Zeitbasis verlässlich (Quarzoszillator bei beiden AVR)? - Anzahl der Stoppbits mal verändert (verschiedene Kombinationen probieren)? P.S.: Hast du einen Schaltplan zur Hand?
Datum:
Ralf G. schrieb: > Ein Master (atmega162) soll ein Datenpaket über RS485 an einen Slave > (attiny2313) schicken. Welche RS485-Treiber benutzt du denn? Ich habe vor kurzem ein RS485 Bussystem mit dem SN75176 als Treiber aufgebaut. An den Slaves kam nurnoch Murks raus. Die Ursache war ziemlich einfach: Die Ausgangsspannung des SN75176 war zu niedrig. Der MC hat das nur sporadisch als High erkannt. Abhilfe hat das einschalten des Pullups des Rx-Pins geschaffen. Seitdem geht das Problemlos (mittlerweile 2 Monate). Gruss Stefan
Datum:
Ich teste dann mal weiter. Markus W. schrieb: > Ich hab zwar keine Ahnung, aber ich werf mal Fragen in den Raum: > - Zeitbasis verlässlich (Quarzoszillator bei beiden AVR)? ja, die 6.144MHz > - Anzahl der Stoppbits mal verändert (verschiedene Kombinationen > probieren)? noch nicht. Stefan M. schrieb: > Welche RS485-Treiber benutzt du denn? MAX485 > Ich habe vor kurzem ein RS485 Bussystem mit dem SN75176 als Treiber > aufgebaut. An den Slaves kam nurnoch Murks raus. > Die Ursache war ziemlich einfach: Die Ausgangsspannung des SN75176 war > zu niedrig. Der MC hat das nur sporadisch als High erkannt. > Abhilfe hat das einschalten des Pullups des Rx-Pins geschaffen. auch mit Pullups dasselbe. Micht wundert eins sehr stark: ISR:
ISR(V_USART_TXC_vect)
{
V_UCSRB &= ~(1 << B_TXCIE);
IRStatus |= 1 << B_USART_TXC;
IRStatus &= ~(1 << B_USART_BUSY);
};
|
in der Hauptschleife:
... if (IRStatus & (1 << B_USART_TXC)) { IRStatus &= ~(1 << B_USART_TXC); /* TEST */ PORTB |= (1 << 5); } ... |
Wieso kann das gelegentlich passieren, dass die if-Abfrage abgearbeitet wird - also das Bit
B_USART_TXC |
gesetzt ist - aber das
B_USART_BUSY |
-Bit nicht gelöscht wird? Erkennbar daran, dass die LED an PINB7 nicht mehr blinkt und die Taste nicht mehr reagiert. In der Hauptschleife am Anfang:
... if ( !(IRStatus & (1 << B_USART_BUSY)) ) { /* TEST */ if (!verz) /* TEST */ PORTB ^= (1 << 7); ... |
An das Ende der while-Schleife habe ich zum Rücksetzen nochmal mit eingefügt:
if ( TasteGedrueckt1(0,2) ) { IRStatus &= ~(1 << B_USART_BUSY); /* TEST */ PORTB &= ~(1 << 5); _delay_ms(200); /* TEST */ PORTB |= (1 << 5); } |
Datum:
Ich habe das Ganze nur überflogen (also nicht bis ins letzte Detail nachvollzogen), dabei sind mir drei Dinge aufgefallen: 1) IRStatus wird sowohl im Interrupt-Kontext, als auch im Main-Kontext verändert, aber keiner der Main-Kontext-RMW-Zugriffe ist geschützt. 2) Der TXC-Interrupt wird verwendet, ist aber nur zeitweise eingeschaltet. Es wird aber nirgendwo das Interrupt-Flag "von Hand" gelöscht. Wenn also zum Zeitpunkt des Einschaltens das Flag bereits gesetzt ist (*), dann hast du ein Problem. (*): z.B. weil ein UDRE-Interrupt so lange verzögert wurde, dass der UART "zwischendrin" schon mal "leer gelaufen" ist. 3) Du verwendest sleep_mode(), was potenzielle Race-Conditions beinhaltet. Überhaupt bringt man so was erst mal ohne Sleep zum laufen, und baut das dann danach ein.
Datum:
Stefan Ernst schrieb: > 1) IRStatus wird sowohl im Interrupt-Kontext, als auch im Main-Kontext > verändert, aber keiner der Main-Kontext-RMW-Zugriffe ist geschützt. Könnte sein. Ist auf jeden Fall sicherer, wenn ich mal eine Interruptsperre einbaue. > 2) Der TXC-Interrupt wird verwendet, ist aber nur zeitweise > eingeschaltet. Es wird aber nirgendwo das Interrupt-Flag "von Hand" > gelöscht. Wenn also zum Zeitpunkt des Einschaltens das Flag bereits > gesetzt ist (*), dann hast du ein Problem. > (*): z.B. weil ein UDRE-Interrupt so lange verzögert wurde, dass der > UART "zwischendrin" schon mal "leer gelaufen" ist. Der TXC-Interrupt wird nach Übernahme des letzten Bytes nach UDR eingeschaltet und der UDRE-Interrupt abgeschaltet. Das TXCIE-Bit wird im TXC-Interrupt wieder gelöscht. Ist nach meiner Ansicht erstmal eine logische Reihenfolge. > 3) Du verwendest sleep_mode(), was potenzielle Race-Conditions > beinhaltet. Überhaupt bringt man so was erst mal ohne Sleep zum laufen, > und baut das dann danach ein. Ich habe da gleich in den Sendepausen den Timer0-Interrupt (Tastenentprellung) als Zeitbasis für Kontrollblinken der LEDs. Also, ich leg dann mal los.
Datum:
Ralf G. schrieb: > Der TXC-Interrupt wird nach Übernahme des letzten Bytes nach UDR > eingeschaltet und der UDRE-Interrupt abgeschaltet. Das TXCIE-Bit wird im > TXC-Interrupt wieder gelöscht. Ist nach meiner Ansicht erstmal eine > logische Reihenfolge. Ich habe auch nichts anderes behauptet. Aber ich an deiner Stelle würde auf Nummer sicher gehen und zusätzlich das TXC-Flag direkt nach dem Schreiben des letzten Bytes nach UDR löschen.
Datum:
Stefan Ernst schrieb: > 1) IRStatus wird sowohl im Interrupt-Kontext, als auch im Main-Kontext > verändert, aber keiner der Main-Kontext-RMW-Zugriffe ist geschützt. Äähm... Das war's! Der Timer-Interrupt hat mir dazwischengefunkt. Dort wird auch ein Bit gesetzt. (Brauch ich später noch, habe das Programm zur Fehlersuche erstmal eingekürzt) Hab' ich völlig ignoriert. Vielen Dank, für den Hinweis. Liest man (also ich) zwar ständig, dass man sowas beachten muss, aber es betrifft einen ja nicht ;-)
Datum:
Stefan Ernst schrieb: > Aber ich an deiner Stelle würde auf Nummer sicher gehen und zusätzlich > das TXC-Flag direkt nach dem Schreiben des letzten Bytes nach UDR > löschen. Da ist es doch aber noch gar nicht gesetzt? An der Stelle schalte ich den Interrupt doch erst ein. Denk' ich jedenfalls.
Datum:
Ralf G. schrieb: > Da ist es doch aber noch gar nicht gesetzt? An der Stelle schalte ich > den Interrupt doch erst ein. Denk' ich jedenfalls. Du verwechselst hier Interrupt-Flag mit Interrupt-Enable-Bit. Das Flag wird immer beim Eintreten des entsprechenden Ereignisses gesetzt, egal ob der dazugehörige Interrupt gerade eingeschaltet ist, oder nicht. Und wenn das Flag dann schon gesetzt ist, wenn der entsprechende Interrupt eingeschaltet wird, kommt der Interrupt sofort. Daher zur Sicherheit vor dem Einschalten das Flag löschen.
Datum:
Stefan Ernst schrieb: > Du verwechselst hier Interrupt-Flag mit Interrupt-Enable-Bit. Ich meinte: Der TXC-Interrupt ist ja noch gar nicht aktiviert! Wird erst im UDRE-Interrupt eingeschaltet um sich dann selbst in der ISR wieder auszuschalten. Meinst du IR aktivieren und gleich das Interrupt-Flag löschen? Aber ich will doch gerade sicher sein, dass ich die Meldung vom µC bekomme, dass die Daten richtig raus sind. Wegen späterer Sende-/Empfangsumschaltung.
Datum:
Ralf G. schrieb: > Ich meinte: Der TXC-Interrupt ist ja noch gar nicht aktiviert! Spielt keine Rolle. Auch ohne aktivierten Interrupt wird das TXC-Flag gesetzt, falls mal die Daten nicht schnell genug nach UDR nachgeliefert werden können, so dass auch zwischendurch der Zustand "alles ist raus" (aus Sicht des µC) eintrifft. Und wenn du dann den TXC-Interrupt einschaltest, kommt er sofort (weil das Flag ja gesetzt ist), obwohl zu dem Zeitpunkt dann noch gesendet wird.
Datum:
Aaaah! Also, das (jedes?) IR-Flag wird gesetzt, wenn das entsprechende Ereignis eintritt. Mit dem entsprechenden Enable-Flag zeige ich sozusagen nur an, ob's mich interessiert. Wenn das so ist, dann verstehe ich deine Erklärung. Ich bin davon ausgegangen, dass das Eintreten eines IR durch das Enable-Flag gesteuert wird.
Datum:
Ralf G. schrieb: > Also, das (jedes?) IR-Flag wird gesetzt, wenn das entsprechende Ereignis > eintritt. Mit dem entsprechenden Enable-Flag zeige ich sozusagen nur an, > ob's mich interessiert. Richtig. Das sind im Grunde zwei unabhängige Vorgänge: a) Ereignis tritt auf -> Flag wird gesetzt b) Flag und Enable-Bit gleichzeitig 1 -> Interrupt wird ausgelöst
Datum:
Stefan Ernst schrieb: > Das sind im Grunde zwei unabhängige Vorgänge: > a) Ereignis tritt auf -> Flag wird gesetzt > b) Flag und Enable-Bit gleichzeitig 1 -> Interrupt wird ausgelöst Na, da hat sich die Zusatzstunde doch gelohnt :-)