Forum: Mikrocontroller und Digitale Elektronik Timer1 im Capture Mode am Tiny2313


von Εrnst B. (ernst)


Lesenswert?

Hallo,

Ich versuche mit dem Timer1 vom Tiny2313 im Capture-Mode die Puls- und
Pausenlängen eines Signals zu messen, aber leider funktioniert das
nicht ganz so, wie ich mir das vorstelle...

Initialisierung wie folgt:
1
  TCCR1A = 0;
2
  TCCR1B=_BV(ICNC1) |  _BV(CS11) ; // Noise Canceler, CLK/8;
3
  TIMSK = _BV(TOIE0) | _BV(ICIE1) | _BV(TOIE1);
lässt also bei 8MHz Takt den Counter mit 1MHz hochzählen.

ISR für Timer0 Overflow macht was anderes, funktioniert.
ISR für Timer1 Overflow zählt eine 16bit variable hoch, zusammen mit
dem Timer hab ich dann einen 32Bit timestamp, funktioniert auch.

ISR für Timer1 Capture funktioniert so:
1
ISR(TIMER1_CAPT_vect) {
2
  uint16_t tval;
3
  tval=ICR1;
4
}
(Ich probier schon länger dran rum, die ISR enthält nur noch was nötig
ist um das Problem zu reproduzieren)

Damit ich jetzt abwechselnd auch an steigenden Flanken triggern kann,
muss ich im ISR das ICES1 Bit toggeln, also:
1
ISR(TIMER1_CAPT_vect) {
2
  uint16_t tval;
3
  tval=ICR1;
4
  TIMSK ^= _BV(ICES1); // Toggle flank to listen for
5
//  TIFR = _BV(ICF1);
6
}
Also im Prinzip so wie im Datenblatt vorgeschlagen, zuerst Wert
auslesen, dann ICES1 ändern, und dann das ICF1 Flag im TIFR
zurücksetzen (Der Schritt ist auskommentiert, macht keinen
Unterschied).

Problem ist nun, mit dieser ISR funktioniert es nur "meistens", etwa
jede 10.-20. Flanke am Eingangssignal führt der Tiny einen Reset aus.

Ich vermute, das ich dabei dann ungewollt irgendeinen nicht definierten
Interrupt auslöse, und die default "bad_interrupt" Routine vom GCC
dann resettet.

Irgendjemand eine Idee, was das sein könnte?

Danke,
/Ernst

von TravelRec. (Gast)


Lesenswert?

Am besten alle nicht benötigten Interrupts sperren oder gar nicht erst
einschalten. Oder den Watchdog mal ausmachen oder dessen Time-Out
verlängern. Vielleicht hängt ja das Programm und der Watchdog kommt...

von Εrnst B. (ernst)


Lesenswert?

Watchdog hab ich schon rumprobiert, der ist es nicht (mit 2 Sekunden und
ohne getestet)

Ansonsten scheinen die anderen IRQs, die ich eingeschaltet habe auch in
Ordnung zu sein, zwei UART-Irqs, Timer0 Overflow alle 10ms, und eben den
Timer1 Overflow (der auch funktioniert) und den Timer1 Capture
Interrupt.

Wenn ich das "Flankenauswahl" Bit in der Capture-ISR nicht anfasse,
funktioniert ja auch alles, nur sobald ich die "TIMSK ^= _BV(ICES1);"
Zeile hinzufüge, resettet der AVR regelmässig.

Als Referenz mal der Abschnitt aus dem Datenblatt, vielleicht hab ich
das was falsch verstanden:

---------------
Measurement of an external signal’s duty cycle requires that the
trigger edge is changed after each capture. Changing the edge sensing
must be done as early as possible after the ICR1 Register has been
read. After a change of the edge, the Input Capture Flag (ICF1) must be
cleared by software (writing a logical one to the I/O bit location). For
measuring frequency only, the clearing of the ICF1 flag is not required
(if an interrupt handler is used).
----------------

/Ernst

von Εrnst B. (ernst)


Lesenswert?

Keiner eine Idee?

Mir würd auch ein "Ich hab das schon benutzt, muss also gehen"
reichen, dann wüsste ich das ich weitersuchen muss...


Danke,
/Ernst

von Magnus Müller (Gast)


Lesenswert?

Lass die Zeile "TIFR = _BV(ICF1);" in der ISR drinne (nicht
auskommentieren)! Wenn Du das Flag nicht löschst wird nach dem
Verlassen der ISR nur der nächste Befehl von main() ausgeführt, und
danach landest Du automatisch (wegen des gesetzten 'ICF1') wieder in
der ISR.

Gruß
Magnetus

von Εrnst B. (ernst)


Lesenswert?

Hatts auch mit dem TIFR clear getestet, kein Unterschied, der Tiny hat
immer noch ständig resettet. (Hat vermutlich nur Blödsinn gemessen ohne
die TIFR=_BV(ICF1) Zeile, aber die Ausgabefunktionen waren das erste,
das ich zum Debuggen aus der ISR entfernt hatte).

... 5 minuten später ...

Hab den (blöden) Fehler aber glaubich grad selbst gefunden...
das ICES1 Flag ist nicht im TIMSK-Register, sondern im TCCR1B....

Manchmal ist man echt blind... hab das X-Mal im Datenblatt
nachgeschaut. grr..

Hab also "Aus Versehen" immer einen Compare-Match IRQ eingeschaltet,
und wenn der zufällig genau dann gekommen ist, ist der AVR in den Reset
gesprungen.

Danke an alle, die sich da mal drübergesehen haben,
/Ernst

von Magnus Müller (Gast)


Lesenswert?

>> Hab den (blöden) Fehler aber glaubich grad selbst gefunden...
>> das ICES1 Flag ist nicht im TIMSK-Register, sondern im TCCR1B....

So eine ähnliche Vermutung schwirrte mir auch schon im Kopf herum ;)

Auf jeden Fall: Wenn Du mal den Gegencheck machen willst... einfach mal
die Zeile "TIFR = _BV(ICF1);" auskommentieren -> dann wird Dein Code
wieder nicht funktionieren (nur mal zum Verinnerlichen ggg).

In diesem Sinne: Viel Spass beim Entwickeln (und Debuggen) cheese

Magnetus

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
Noch kein Account? Hier anmelden.