Hallo liebe Gemeinde,
ich habe hier ein etwas kniffeliges Problem mit der Output Compare
Funktion beim AVR. Benutzt wird ein ATmega328. Ich möchte zur Erzeugung
es speziellen Steuersignals folgendes machen.
OCR1A und OCR1B sollen spezielle Pulse erzeugen. Dabei soll mittels
OCR1A und der Einstellung "Clear on match" der andere IO-Pin OCR1B per
CPU in der zugehörigen ISR gesetzt werden sowie über die reine
Hardwarefunktion OCR1A gelöscht. Und das Ganze umgekehrt mit OCR1B.
Beispielsweise 1000 Takte nach dem aktuellen Zeitpunkt (in einer
Funktion) soll OCR1A auslösen und in dem zugehörigen Interrupt soll das
Pin zu OCR1B(!) per CPU auf HIGH gestetzt werden, die Hardware löscht
OCR1A automatisch. Um das zu tun, muss man den Modus in TCC1A auf Normal
stellen um dem Waveformgenerator abzukopplen und den normalen Zugiff auf
das IO Pin per CPU zu ermöglich. Das geht soweit. ABER, nun das Problem.
Ich habe erwartet, dass beim Zurückschalten auf "clear on match" der
Pegel vom IO-Pin erhalten bleibt. Tut er aber nicht! Sobald TCCR1A mit
der Einstellung beschrieben wird, kippt das IO-Bit OCR1B zurück auf den
alten (LOW) Pegel! Mist!
Wenn man ins Datenblatt schaut, Abschnitt 15.8, Figure 15-5 sieht man
vereinfacht die Logik. Und es wird explizit gesagt
"The design of the Output Compare pin logic allows initialization of the
OC1x state before the output is enabled."
Aber hier geht scheibar der Update bzw. die Synchronisation zwischen dem
normalen PORT-Bit und der Kopie im Waveform Generator schief!
Hat jemand eine Idee, wie man das lösen kann? Wie kann man dem
Waveformgenerator verclickern, dass er den aktuellen Zustand vom Pin
übernehmen soll, damit beim Zurückschalten auf ihn der Pegel des IO-Pins
erhalten bleibt? Ich hab schon mehrere nop() und Delays zwischen die
verschiedenen Operation in der ISR eingefügt, leider ohne Erfolg.
Der Timer 1 läuft kontinuiertlich im Mode 0 mit /8 Taktteiler.
1 | ISR (TIMER1_COMPA_vect) {
|
2 |
|
3 | TCCR1A = 0;
|
4 | PORTB |= (1<<PB2);
|
5 | _delay_us(20);
|
6 | TCCR1A = (1<<COM1A1) | (1<<COM1B1); // mode 0, clear on COMPARE A/B
|
7 | }
|
P.S. das delay ist nur drin, um den Puls auf dem Oszi besser zusehen.
Edit. Ein Workaround wäre, die IO-Pins immer per CPU zu schalten und die
Clear FUnktion der Hardware nicht zu nutzen. Das habe ich schon gemacht,
geht auch, ist aber etwas unschön und an einigen Stellen ungünstig. Das
Clear per Hardware wäre schon eine feine Sache.