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
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. ;-)
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.
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.
@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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.