Hallo Zusammen,
ich versuche gerade mich in die verschiedenen Möglichkeiten zur
Verwendung der GP-Timer des ESP32 ein zu arbeiten. Grundfunktion,
Vorteiler, Alarmwert ist alles soweit klar. Bei Versuchen, den
Zählerstand in Mikrosekunden auszulesen bin ich aber auf ein Problem
gestossen.
Zunächst habe ich nur einen Timer verwendet und mit einem Vorteiler von
80 einen Zähltakt von 1MHz eingestellt. Mit einem Alarmwert von
1.000.000 gibt das schön einen Interrupt pro Sekunde.
Aus Interesse wollte ich dann mal sehen, ob in der Loop delay(500) auch
genau ist. Dabei ist mir aufgefallen, dass das Auslesen des Timers mit
timerReadMicros(Timer) falsche Werte liefert, wenn der Timer zusätzlich
mit Alarmwert genutzt wird.
In der Loop lasse ich eine LED mit 1Hz blinken (funktioniert in jedem
Fall korrekt!) und lese jedesmal den Zählerstand des Timers (uint64_t)
aus. Dann bilde ich die Differenz.
Das Setup der beiden genutzten Timer, einmal mit Alarmwert (der Reload
beim Alarm wirft nahher Fragen auf), einmal nur als Timer mit 1MHz Takt:
1 | void setup() {
|
2 | Serial.begin(115200);
|
3 | pinMode(LED, OUTPUT);
|
4 | state = LOW;
|
5 | digitalWrite(LED, state);
|
6 | // Timer 0 als Timer mit Alarmwert für 1s konfigurieren
|
7 | nextAlarm = 1000000;
|
8 | testTimer1 = timerBegin(0, 80, true); // Timer0, Teiler:80, Aufwärtszähler
|
9 | timerAlarmWrite(testTimer1, nextAlarm, false); // Alarm bei 1s, ohne Auto-Reload
|
10 | timerAttachInterrupt(testTimer1, &onTimer, true); // ISR onTimer()
|
11 | timerAlarmEnable(testTimer1);
|
12 | timerStart(testTimer1);
|
13 | delay(10); // der Delay hat nachher Folgen!!
|
14 | // Timer 2 ohne Alarm, 1MHz Takt
|
15 | testTimer2 = timerBegin(1, 80, true); // Timer0, Teiler:80, Aufwärtszähler
|
16 | timerStart(testTimer2);
|
17 | }
|
Der Alarmwert des ersten Timers wird nachher in der ISR neu gesetzt.
Ziel ist eigentlich, dass der Zählerstand nach Alarm weiter läuft und
der Alarmwert fortgeschrieben wird. Aber erstmal zur Endlosschleife...
1 | void loop() {
|
2 | // Wie genau ist denn Delay...
|
3 | delay(500);
|
4 | //timerStop(testTimer1);
|
5 | timerValNew = timerReadMicros(testTimer1); // mit testTimer2 funktioniert es problemlos...
|
6 | //timerStart(testTimer1);
|
7 | digitalWrite(LED, state);
|
8 | state=!state;
|
9 | Serial.printf("Zählerstand: %6d \n", timerValNew);
|
10 | Serial.printf("Alarmwert: %6d \n", timerAlarmRead(testTimer1));
|
11 | long delta = timerValNew - timerValOld;
|
12 | Serial.printf("Vergangene Zeit: %6d us\n", delta);
|
13 | timerValOld = timerValNew;
|
14 | }
|
Die vergangene Zeit sollten eigentlich 500.000 sein (ich hatte da
eigentlich mit kleinen Abweichungen gerechnet). Bei der Nutzung des
Timers testTimer2 ohne Alarmwert und Auto-Reload bekomme ich sogar exakt
500.000µs als Ergebnis (nice).
Wenn ich den anderen Timer testTimer1 mit Alarm und ohne AutoReload
auslese erhalte ich aber Zeiten von rund 990ms und 10ms (?!?). Die LED
blinkt aber korrekt im 1Hz-Takt weiter.
Den Timer vor dem Auslesen zu stoppen und nacher wieder zu starten
ergibt fast die selben Werte, die Verschieben sich nur bei jedem
Durchgang um 4-5µs.
Hier die Ausgaben, der nächste Alarmwert wird in der ISR erhöht.
1 | Zählerstand: 32000002 <= Hier blinkt die LED
|
2 | Alarmwert: 33000000
|
3 | Vergangene Zeit: 989867 us
|
4 | Zählerstand: 32010135 <= Hier blinkt die LED
|
5 | Alarmwert: 33000000
|
6 | Vergangene Zeit: 10133 us
|
7 | Zählerstand: 33000002 <= Hier blinkt die LED
|
8 | Alarmwert: 34000000
|
9 | Vergangene Zeit: 989867 us
|
10 | Zählerstand: 33010135 <= Hier blinkt die LED
|
11 | Alarmwert: 34000000
|
12 | Vergangene Zeit: 10133 us
|
Die kürzere Zeit ist dabei von dem delay() im Setup abhängig! Mit
delay(33) erhalte ich dann
1 | Zählerstand: 10000002
|
2 | Alarmwert: 11000000
|
3 | Vergangene Zeit: 966888 us
|
4 | Zählerstand: 10033114
|
5 | Alarmwert: 11000000
|
6 | Vergangene Zeit: 33112 us
|
Wie gesagt, die LED blinkt in allen Fällen korrekt. Hat da jemand eine
Idee, was da falsch läuft?
Arduion 1.8.13, ESP32 Version 1.0.5 und 1.0.6
gruß
Bernhard