Forum: Compiler & IDEs Problem mit UART/UDRE


von Michael Prader (Gast)


Lesenswert?

Hallo!

Ich habe ein Problem mit meiner Routine zum Senden der Daten im Buffer
tx_buffer. Das Programm läuft auf einem mega8515 mit 16MHz, der
Vorteiler für Timer0 ist 8 (=zählt 1/2 mikrosekunden).
Folgende Interruptfunktion habe ich erstellt:
So: Wie ihr seht, ist ein Delay eingebaut, das 2x bis AF zählt, macht
insgesamt 175 Mikrosekunden. Das liegt knapp ober der Bytelänge (8N1),
die bei 57600 173µs beträgt. Wenn ich das Delay verkürze (z.B. auf 9F),
sind die Daten korrumpiert, d.h. Checksumme meist fehlerhaft.
Kann es sein, dass das UDRE-Flag in meiner Routine nicht gelöscht wird
und sofort nach Verlassen wieder der Interrupt ausgelöst wird? Wie kann
ich eventuell manuell das Flag rücksetzen?


SIGNAL(SIG_UART_DATA)
{
  UDR = tx_buffer[tx_index++];
  troppo=0x00;
  while (troppo < 0x02)
  {
  outp(0x00, TCNT0);
  while (TCNT0 < 0xAF);
  troppo++;
  }
}

Im Voraus danke für jegliche Hilfe!

Grüße
Michael

von Jörg Wunsch (Gast)


Lesenswert?

Ich denke, du rennst in eine Endlosschleife.  Eine UDRE-ISR sollte
immer Vorkehrungen haben, um am Ende des Puffers dann diese
Interruptquelle wieder abzuschalten, ansonsten generierst du endlos
Interrupts.

Die Verzögerung ist nicht nötig.  Beim ersten Mal wird der Interrupt
zweimal hintereinander aufgerufen, da das erste Byte ja sofort ins
Sende-Schieberegister gehen kann, damit ist das Sendepuffer-Register
wieder leer und kann sofort nochmal beschrieben werden.

Zeichenkorruption sollte ohnehin nicht durch Überschreiben des UDR
enstehen können, da das Datenblatt aussagt, dass ein Beschreiben von
UDR bei UDRE=0 ignoriert wird.  Wenn du also eine Korruption
beobachtest, dann denke ich eher, dass du irgendwie einen CPU-Reset
hervorrufst, den du durch die Warteschleife nur maskierst indem du ihn
so weit rauszögerst, dass dadurch zumindest keine Korruption mehr
beobachtbar ist.  Beseitigung von Symptomen ist nicht immer der Weg
zum Erfolg. ;-)

von thkais (Gast)


Lesenswert?

Ich benutze für die Versendung per Interrupt SIG_UART_TRANS, dieser
Interrupt wird immer dann ausgelöst, wenn ein Byte versendet ist. Ist
der Sendepuffer leer, gräbt sich der Intterupt selbst das Wasser ab.

von Jörg Wunsch (Gast)


Lesenswert?

SIG_UART_DATA ist schon die besser Variante: damit kann man die
Doppelpufferung des Senders (Tx shift register und Tx buffer register)
ausnutzen und die Frames kommen garantiert ,,Rücken an Rücken''
raus,
also direkt nach dem Stopbit das nächste Startbit.  SIG_UART_TRANS
löst erst nach dem vollständigen Herausschieben aus dem Tx shift
register aus, damit entsteht eine Lücke.

Man darf bei SIG_UART_DATA eben nur nicht vergessen, die
Interruptquelle wieder abzuschalten, da dort ,,Interrupt wird
ausgelöst'' (d.h. Sendepuffer ist leer) ja gewissermaßen die
Ruhelage
ist.

von Michael Prader (Gast)


Angehängte Dateien:

Lesenswert?

@Jörg: Vorkehrung zum Beenden der Senderoutine habe ich eingebaut, nur
leider nicht erwähnt, sorry. Deshalb habe ich die gesamte Busdatei
bus.c angehängt, ab Zeile 200 steht die ISR.
UDRIE wird deaktiviert, sobald tx_index >= BUFFER_SIZE oder Paketlänge
ist.

Dass am Beginn 2x ein Int ausgelöst wird, leuchtet mir ein, das habe
ich nicht bedacht.
UDRIE wird außerhalb dieser Busdatei im Hauptprogramm gesetzt, falls
xmit_packet() eine 0 zurückgibt (d.h. erfolgreiche Übernahme des
Busses).
Ach ja, es ist RS485, wobei RS485TXEN die TXenable-Leitung des
Transmitters steuert und die !RXenable ständig low ist. Während des
Sendens ist RXCIE nicht gesetzt, wird aber bei Deaktivierung von UDRIE
gesetzt. Während des Sendens wird RS485TXEN auch nicht low gezogen,
sonder ist immer aktiv.

Wäre es möglich, dass im Empfänger die REceive-ISR zu langsam ist?? Bei
16MHz wohl ein idiotischer Gedanke...

Zur Verzögerung: Weil in der Testphase des Projekts die
Datenübertragung nicht zustandekam, habe ich an allen möglichen Stellen
Delays eingebaut, an denen mir der Status über einen LED-Char ausgegeben
wurde, ich konnte somit in Ruhe alle Schritte des Programms verfolgen.
Nun, übrig geblieben ist nur dieses letzte in der SendeISR.
Es treten ohne Delay am Empfänger keine Overruns auf und auch keine
Framing errors, und genau das verstehe ich nicht! 2
übereinandergelagerte Bytes würden wahrscheinlich letztere produzieren,
außer sie sind sehr nahe zusammen.
Wenn ich ein OSzi hätte, könnte ich die Pegel direkt verfolgen, so kann
man eben nur raten.
CPU-Reset scheidet mit hoher Wahrscheinlichkeit aus, weil dort PORTC
auf 0x03 gesetzt wird, was ich hätte erkennen können. Werde aber
trotzdem morgen nochmal in diese Richtung kontrollieren.

Vielen Dank derweil
Grüße Michael

von Michael Prader (Gast)


Lesenswert?

Mir ist gerade etwas eingefallen: Zu Testzwecken habe ich einmal die
Bytelänge erhöht (2 Stopbits , 8N2 = 11 Bits). Danach traten auch mit
der Warteschleife, die bei 10 Bits einwandfrei funkt, diesselben
Probleme auf. Erst als ich die Warteschleife auf 0xC2 erhöhte, lief er
Übertrag wieder. Nun, C2 entspricht 194µs und ist damit ein wenig
länger als die Bytelänge 190µsec. Das machte mich stutzig und brachte
mich auf die Idee, es könnte ein Zusammenhang bestehen...
Wie gesagt, morgen wird alles mögliche getestet.

Gute Nacht
Michael

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.