Ich bin grad dabei, mich in die AVRs einzuarbeiten. Das Programm soll
jetzt erstmal eine Phasenanschnittsteuerung sein.
Nach der AN von Atmel hab ich die Netzspannung über 100k an nem Portpin
und die Masse über 100k an der Netzerde. Das liefert saubere Interrupts
ohne Aussetzer(getestet).
Nach dem Pin-Change-Int warte ich eine bestimmte Zeit, schalte dann ein
SSR ein und nach einer kleinen Wartezeit wieder aus.
Der Controller(Mega32) läuft mit 16Mhz.
Ich setze im Pin-Change-Int ein Flag(Periodenanfang). Dieses Flag wollte
ich in ein Bitfeld ("bits") setzen, damit für 1/0 kein ganzes Byte
verschwendet wird. Mache ich das, kommt es beim Phasenanschnitt
reproduzierbar eine gewisse Zeit nach nem Reset zu kurzen Aussetzern. Es
scheint ab und zu mindestens eine Halbwelle nicht durchgeschaltet zu
werden. Die Zeitabstände der Aussetzer zueinander und zum Resetzeitpunkt
bleibt nach jedem Reset gleich.
Nach langer Fehlersuche hab ich das Flag dann mal probeweise als ganzes
Byte realisiert. Und dann geht es völlig problemlos.
Hier jetzt mal der funktionierende Code:
So wird das Flag dann überall im Programm angesprochen:
1
bits.periodenanfang
Die Bitfelder hab ich aus dem Tutorium übernommen.
Und nun meine Frage: WARUM??
Braucht das Rotieren und Maskieren der Bits wirklich soo viel Zeit, dass
der Timer-Interrupt manchmal nicht mehr nachkommt?
Thomas B. wrote:
> Ich setze im Pin-Change-Int ein Flag(Periodenanfang). Dieses Flag wollte> ich in ein Bitfeld ("bits") setzen, damit für 1/0 kein ganzes Byte> verschwendet wird.
Das lohnt sich eigentlich nur, wenn deine RAM-Auslastung schon knapp
an der Grenze ist. Du erkaufst nämlich damit RAM-Platz durch ROM
und Laufzeit.
> Mache ich das, kommt es beim Phasenanschnitt> reproduzierbar eine gewisse Zeit nach nem Reset zu kurzen Aussetzern.
Ohne bis zu Ende durch deinen Code durchsteigen zu wollen, würde ich
einfach mal vermuten, dass du eine race condition drin hast. Das
Testen eines Bytes ist praktisch atomar, das Testen eines Bits (bis
auf Ausnahmen in niedrigen IO-Registern) ist es nicht. Das Bit
könnte also mitten in deinem Test verändert werden. (Ähnliches trifft
auf 16-bit-Variable zu.)
Jörg Wunsch wrote:
> Thomas B. wrote:>>> Ich setze im Pin-Change-Int ein Flag(Periodenanfang). Dieses Flag wollte>> ich in ein Bitfeld ("bits") setzen, damit für 1/0 kein ganzes Byte>> verschwendet wird.>> Das lohnt sich eigentlich nur, wenn deine RAM-Auslastung schon knapp> an der Grenze ist. Du erkaufst nämlich damit RAM-Platz durch ROM> und Laufzeit.
RAM hab ich eigentlich schon noch genug, ist wohl eher die schwäbische
Sparsamkeit ;)
Hab mittlerweile auch eingesehen, dass es an dieser Stelle keinen Sinn
macht.
>>> Mache ich das, kommt es beim Phasenanschnitt>> reproduzierbar eine gewisse Zeit nach nem Reset zu kurzen Aussetzern.>> Ohne bis zu Ende durch deinen Code durchsteigen zu wollen, würde ich> einfach mal vermuten, dass du eine race condition drin hast. Das> Testen eines Bytes ist praktisch atomar, das Testen eines Bits (bis> auf Ausnahmen in niedrigen IO-Registern) ist es nicht. Das Bit> könnte also mitten in deinem Test verändert werden. (Ähnliches trifft> auf 16-bit-Variable zu.)
Klingt erstmal logisch, aber gelesen und beschrieben wird ja
ausschliesslich in den beiden Interrupts. Die können sich gegenseitig
nicht unterbrechen, da keine Prioritäten beim AVR, das Lesen bzw.
Schreiben sollte also gekapselt sein...
Thomas B. wrote:
> RAM hab ich eigentlich schon noch genug, ist wohl eher die schwäbische> Sparsamkeit ;)
Atmel gibt dir kein Geld zurück, wenn du den RAM nicht komplett
benutzt. ;-)
> Klingt erstmal logisch, aber gelesen und beschrieben wird ja> ausschliesslich in den beiden Interrupts. Die können sich gegenseitig> nicht unterbrechen, da keine Prioritäten beim AVR, das Lesen bzw.> Schreiben sollte also gekapselt sein...
Dann wundert es mich auch, stimmt.
> Ohne bis zu Ende durch deinen Code durchsteigen zu wollen, würde ich> einfach mal vermuten, dass du eine race condition drin hast. Das> Testen eines Bytes ist praktisch atomar, das Testen eines Bits (bis> auf Ausnahmen in niedrigen IO-Registern) ist es nicht. Das Bit> könnte also mitten in deinem Test verändert werden. (Ähnliches trifft> auf 16-bit-Variable zu.)
Könnte man daraus folgern, dass zur Kommunikation zwischen ISR und
Hauptprogramm eigentlich nur uint8_t oder int8_t geeignet ist?
(vorausgesetzt man ergreift nicht andere Maßnahmen wie Sperren des
Interrupts während der Abfrage im Hauptprogramm oder sowas)
Klaus W. wrote:
>> Ohne bis zu Ende durch deinen Code durchsteigen zu wollen, würde ich>> einfach mal vermuten, dass du eine race condition drin hast. Das>> Testen eines Bytes ist praktisch atomar, das Testen eines Bits (bis>> auf Ausnahmen in niedrigen IO-Registern) ist es nicht. Das Bit>> könnte also mitten in deinem Test verändert werden. (Ähnliches trifft>> auf 16-bit-Variable zu.)>> Könnte man daraus folgern, dass zur Kommunikation zwischen ISR und> Hauptprogramm eigentlich nur uint8_t oder int8_t geeignet ist?>> (vorausgesetzt man ergreift nicht andere Maßnahmen wie Sperren des> Interrupts während der Abfrage im Hauptprogramm oder sowas)
Hm, mal ausprobiert:
Aus dem C-Code macht der Compiler folgende Assembler Befehle:
Hier in der ISR:
pending_msg.condition=1;
130: 80 91 a1 00 lds r24, 0x00A1
134: 82 60 ori r24, 0x02 ; 2
136: 80 93 a1 00 sts 0x00A1, r24
Hier im Hauptprogramm:
if (pending_msg.condition == 1)
470: 80 91 a1 00 lds r24, 0x00A1
474: 81 ff sbrs r24, 1
476: 05 c0 rjmp .+10 ; 0x482
<main+0x46>
Selbst wenn ich im Hauptprogramm schreibend zugreifen würde und die ISR
unterbricht, wären doch die lds/sts Befehle als solche atomar. Es kann
natürlich sein, dass das Hauptprogramm noch den alten Zustand des
Bitfelds liest und die ISR vor dem Vergleich einen neuen schreibt, aber
das merke ich ja dann bei der nächsten Abfrage.
Allerdings... grübel
Ich muss das Flag im Hauptprogramm irgendwann wieder zurücksetzen. Dann
könnte es natürlich passieren, dass ich ein anderes Flag mit
zurücksetze, welches die ISR zwischen lds und sts des Hauptprogramms
gesetzt hat.
Ich sehe schon, man muss sich wohl recht genau überlegen was man macht
:-(.
viele Grüße,
Klaus