Beim Versuch einen Raspberry PI mit einem Atmega8 per USART zu verbinden
bin ich auf folgendes Problem gestoßen: Um die Programmierung des
Atmega8 zu testen habe ich den Atmega8 auf RXD mit seinem eigenen TXD
gefüttert. Das funktioniert auch im Prinzip, nur habe ich mit einer
seltsamen Zeichenverdopplung zu kämpfen. Dazu folgender Code (mit dem
Versuch nur das Wesentliche darzustellen):
Interruptroutine für USART RX
1
.def data = r20
2
.def flag = r21
3
4
usartrx: in data, UDR ; empfangenes Byte nach data sichern
display: tst flag ; Warten bis Interruptroutine das flag setzt
3
breq display
4
clr flag
5
mov temp, data
6
; ... Die übliche LCD Ansteuerung zur Anzeige von temp
7
rjmp display
Hauptprogramm Variante 2 (funktioniert):
1
loop: cli ; Auskommentieren führt auch hier zur Zeichenverdopplung
2
tst flag
3
brne display
4
sei ; Dem Interrupt auch eine Chance geben
5
rjmp loop
6
7
display: clr flag
8
mov temp, data
9
sei
10
; ... Die übliche LCD Ansteuerung zur Anzeige von temp
11
rjmp loop
Warum kommt es in Variante 1 zu diesen seltsamen Zeichenverdopplungen?
Klar, dass das Interrupt-Flag in Variante 2 ein Mutex für 'flag' und
'data' ist, nur kann ich mir nicht erklären, dass ich Zeichen doppelt
sehe (nein es ist nicht das Bier) sondern eher würde ich vermuten dass
welche verschluckt werden. Das ganze geschieht bei absolut moderaten
Bitraten (9600 Baud) und alle paar Sekunden ein Zeichen.
Peter Dannegger schrieb:> Klassischer Fehler, der Interrupt sichert das SREG nicht, ändert es> aber.
Nein, das ist es nicht. Weder 'in' noch 'ser' ändern das SREG. Die
Variante.
Cube S. schrieb:> eher würde ich vermuten dass> welche verschluckt werden
Ja denn da ist eine Race Condition zwischen Abfrage und Löschen des
Flags bei Variante 1. Wenn ich mal unterstelle, dass das cli eigentlich
ein sei ist? Oder wo ist das sei?
EDIT: so wie oben dürfte es ja eher zu gar keinem Zeichen kommen...
> EDIT: so wie oben dürfte es ja eher zu gar keinem Zeichen kommen...
Kommt es aber. Die 'sei' sind durchaus vorhanden (in Variante 1 habe ich
es allerdings fälschlicherweise als 'cli' getarnt (der Kommentar
widerspricht dem). Variante 2 funktioniert ohne Probleme.
Sprich: In Variante 1 sind Interrupts generell zugelassen, in Variante 2
ist es so, dass Zugriffe auf 'data' und 'flag' quasi atomar sind.
Genau so hatte ich das ja vermutet, umso mehr stimme ich Dir zu, dass da
eigentlich höchstens was verloren gehen kann. TOCTTOU in Bezug auf das
Flag selbst als auch die Daten:
1
tst flag
2
; ...
3
clr flag
4
mov temp, data
bei aktiviertem Interrupt sieht flasch aus.
Wie es stattdessen aber zu einer Verdopplung kommen kann, würde mich
auch interessieren. Blöde Neugier :)
Wird der ISR zu oft angesprungen oder sonstwie der Inhalt von r21
vermüllt?
Cube S. schrieb:> Dazu folgender Code (mit dem> Versuch nur das Wesentliche darzustellen):
Solange Du den Fehler nicht weißt, weißt Du auch nicht, was wesentlch
ist!
Zeig ein komplettes Programm (als Anhang) und nichts aus dem Gedächtnis,
sondern das exakte, getestete Programm mit stimmenden Kommentaren.
Sonst raten wir noch in 100 Jahren rum.
Gerne hier auch das komplette Programm so wie es fehlerlos funktioniert.
Allein das auskommentieren des 'cli' nach dem 'loop:'-Label zeigt den
Effekt der sporadischen Zeichenverdopplung.
Malte S. schrieb:> bei aktiviertem Interrupt sieht flasch aus.
Da stimme ich absolut zu, deswegen habe ich ja auch die Variante mit den
gesperrten Interrupts gegenübergestellt. Nur bei der Baudrate und der
Häufigkeit von selbst gesendeten Zeichen hätte ich das "durchgehen
lassen". Und ich finde einfach die Erklärung nicht warum es so ist wie
es ist.
wenn's das war, wovon ich erstmal ausgehe, dann war
Peter Dannegger schrieb:> Klassischer Fehler, der Interrupt sichert das SREG nicht, ändert es> aber.
ins schwarze. Nur ohne den schuldigen ISR auf dem Silbertablett :)
Malte S. schrieb:> ins schwarze
Treffer, versenkt. Das war's. Besten Dank auch. Gute Güte, das sollte ja
nur zum Testen sein. Naja gescheiter wird man durch scheitern.