USART, die 4220.

OP #2635931
Lesenswert?

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.
Angehängte Dateien:
OP #2636134
Lesenswert?

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.
(Firma: guloshop.de) #2636694
Lesenswert?

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?
#2636739
Lesenswert?

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
OP #2637309
Lesenswert?

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:
1
ISR(V_USART_TXC_vect)
2
{
3
 V_UCSRB &= ~(1 << B_TXCIE);
4
 IRStatus |= 1 << B_USART_TXC;
5
 IRStatus &= ~(1 << B_USART_BUSY);
6
};

in der Hauptschleife:
1
...
2
  if (IRStatus & (1 << B_USART_TXC))
3
  {
4
   IRStatus &= ~(1 << B_USART_TXC);
5
 /* TEST */ PORTB |= (1 << 5);
6
  }
7
...
Wieso kann das gelegentlich passieren, dass die if-Abfrage 
abgearbeitet wird - also das Bit
1
B_USART_TXC
 gesetzt ist - aber das
1
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:
1
...
2
  if ( !(IRStatus & (1 << B_USART_BUSY)) )
3
  {
4
 /* TEST */ if (!verz)
5
 /* TEST */ PORTB ^= (1 << 7);
6
...

An das Ende der while-Schleife habe ich zum Rücksetzen nochmal mit 
eingefügt:
1
  if ( TasteGedrueckt1(0,2) )
2
  {
3
   IRStatus &= ~(1 << B_USART_BUSY);
4
 /* TEST */ PORTB &= ~(1 << 5);
5
   _delay_ms(200);
6
 /* TEST */ PORTB |= (1 << 5);
7
  }
#2637384
Lesenswert?

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.
OP #2637531
Lesenswert?

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.
#2637560
Lesenswert?

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.
OP #2637585
Lesenswert?

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 ;-)
#2637645
Lesenswert?

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.
OP #2637665
Lesenswert?

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.
#2637693
Lesenswert?

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.
OP #2637709
Lesenswert?

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.
#2637723
Lesenswert?

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren