Hallo Forum, ich lasse Timer1 mit F-CPU laufen (TCCR1B=(1<<CS10); ) und zähle mit Timer0 externe Ereignisse (TCCR0=(1<<CS01)|(1<<CS02); ) Jetzt habe ich folgendes festgestellt: Wenn ich das ICF1-Bit lösche mit TIFR|=(1<<ICF1); und just im gleichen CPU-Zyklus läuft Timer0 über, geht das TOV0-Bit in TIFR verloren bzw. wird gar nicht gesetzt!? Kann das sein? Odr mache ich was falsch? Danke für Eure Antworten Hannes.
Bit löschen geht in diesem Fall mit TIFR = (1<<ICF1). Siehe: http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_intbits
Hannes schrieb: > Das war die Ursache. Und der Hintergrund? Im TIFR werden die Bits gelöscht, die mit einer '1' beschrieben werden. Wenn also im TIFR neben dem ICF1 auch das TOV0 gesetzt war, dann wird bei > TIFR|=(1<<ICF1); erst mal das TIFR eingelesen, dann ICF1 dazuverodert, und dann das Ganze wieder auf das TIFR rausgeschrieben.
1 | TIFR |
2 | Bit 7 6 5 4 3 2 1 0 |
3 | OCF2 TOV2 ICF1 OCF1A OCF1B TOV1 OCF0 TOV0 |
Wenn jetzt also im TIFR sowas steht "0010 0001" (ICF1 und TOV0 gesetzt), dann wird "0010 0000" dazuverodert, das gibt dann "0010 0001" (es ändert sich nichts). Und wenn das wieder auf TIFR rausgeschrieben wird, werden beide Bits gelöscht. Hoppla, der Overflow ist verschwunden... :-o Das wäre also das selbe wie wenn ich schreibe: > TIFR = TIFR; Mit > TIFR = (1<<ICF1); wird dagegen nur das ICF1 Flag gelöscht. Und das war gewünscht.
Lothar Miller schrieb: > Hannes schrieb: >> Das war die Ursache. > Und der Hintergrund? > > Im TIFR werden die Bits gelöscht, die mit einer '1' beschrieben > werden. Wenn also im TIFR neben dem ICF1 auch das TOV0 gesetzt war, dann > wird bei >> TIFR|=(1<<ICF1); > erst mal das TIFR eingelesen, dann ICF1 dazuverodert, und dann das Ganze > wieder auf das TIFR rausgeschrieben. Naja, und was ist wenn der compiler TIFR |= (1 << ICF1) zu sbi compiliert? Würde das immer noch nicht funktionieren?
Michael Buesch schrieb: >>> TIFR|=(1<<ICF1); >> erst mal das TIFR eingelesen, dann ICF1 dazuverodert, und dann das Ganze >> wieder auf das TIFR rausgeschrieben. > > Naja, und was ist wenn der compiler TIFR |= (1 << ICF1) zu sbi > compiliert? Würde das immer noch nicht funktionieren? Gute Frage. Sogar eine sehr gute Frage. Die tiefer liegende Frage lautet: Darf er das überhaupt? Das Problem: Die ganze Operation ist auf C Ebene nur schlecht definiert, wenn überhaupt. Man beschreibt ein Register (eine spezielle Variable) mit einem Wert und hinterher steht hardwarebedingt etwas ganz anderes in diesem Register. Das alleine widerspricht doch schon allem was in C vorausgesetzt wird. Die daraus abgeleitete Frage lautet: Wenn die oberste Prämisse für den Optimizer die 'As If' Regel ist, woran muss er sich dann orientieren? An dem was das C-Statement aussagt, nämlich das ein Bit zu einem Wert hinzugeodert wird. Dann darf er zu einem sbi optimieren, selbst wenn das auf der Hardware nicht dieselben Auswirkungen hat, wie bei einer reinen Betrachtung auf C Ebene. Oder muss er sich an den Auswirkungen orientieren? Dann dar er die Optimierung nicht durchführen, weil sie ja nicht den identischen Effekt hat. In der Tat eine gute Frage.
Karl heinz Buchegger schrieb: > Michael Buesch schrieb: > >>>> TIFR|=(1<<ICF1); >>> erst mal das TIFR eingelesen, dann ICF1 dazuverodert, und dann das Ganze >>> wieder auf das TIFR rausgeschrieben. >> >> Naja, und was ist wenn der compiler TIFR |= (1 << ICF1) zu sbi >> compiliert? Würde das immer noch nicht funktionieren? > > Gute Frage. Sogar eine sehr gute Frage. > Die tiefer liegende Frage lautet: Darf er das überhaupt? > > Das Problem: > Die ganze Operation ist auf C Ebene nur schlecht definiert, wenn > überhaupt. Man beschreibt ein Register (eine spezielle Variable) mit > einem Wert und hinterher steht hardwarebedingt etwas ganz anderes in > diesem Register. Das alleine widerspricht doch schon allem was in C > vorausgesetzt wird. > > Die daraus abgeleitete Frage lautet: > Wenn die oberste Prämisse für den Optimizer die 'As If' Regel ist, woran > muss er sich dann orientieren? An dem was das C-Statement aussagt, > nämlich das ein Bit zu einem Wert hinzugeodert wird. Dann darf er zu > einem sbi optimieren, selbst wenn das auf der Hardware nicht dieselben > Auswirkungen hat, wie bei einer reinen Betrachtung auf C Ebene. > Oder muss er sich an den Auswirkungen orientieren? Dann dar er die > Optimierung nicht durchführen, weil sie ja nicht den identischen Effekt > hat. > > In der Tat eine gute Frage. Darauf wollte ich eigentlich nicht hinaus. Der GCC wird REG |= (1 << const) als sbi übersetzen, wenn die Optimierung eingeschaltet ist. Das ist in keinem Standard festgeschrieben, aber er macht es halt. Ob man sich darauf verlassen kann und sollte ist eine andere Frage. Meine Frage war eher, gibt es einen Unterschied zwischen: sbi TIFR, bitnr und ldi r0, (1 << bitnr) out TIFR, r0 außer, dass das zweite einen Zyklus mehr braucht.
Michael Buesch schrieb: > Meine Frage war eher, gibt es einen Unterschied zwischen: > > sbi TIFR, bitnr > > und > > ldi r0, (1 << bitnr) > out TIFR, r0 > > außer, dass das zweite einen Zyklus mehr braucht. Nein, es gibt keinen weiteren Unterschied dazwischen. Für einige Register zumindest ist das auch explizit dokumentiert: [...] Beware that if doing a Read-Modify-Write on ADCSRA, a pending interrupt can be disabled. This also applies if the SBI and CBI instructions are used.
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.