Ich hatte die IRMP Software für die mbed Bibliothek angepasst. Auf einem
LPC1347 und 4088 funktioniert das auch gut, dann wollte ich das auch auf
einem STM32F1 testen. Das Ergebnis war negativ obwohl ich ja nur
Basisfunktionen benutze. Bei der Fehlersuche bin ich auf einen bekannten
Issue gestossen: In IRMP wird mit 15 kHz die Samplingroutine aufgerufen
und das geht in mbed einfach mit einem 'Ticker' Objekt. Da fügt man mit
attach_us(&prog, period) eine Funktion einer Liste hinzu die dann mit
period_time [µs] aufgerufen wird. Der Listenteil ist quasi 'HighLevel'
und für alle MCUs gleich. Die Implentierung des Timer/Interrupthandlings
ist LowLevel und dann MCU abhängig.
Die LPC haben 32 Bit Timer und da ist der LowLevel Teil recht einfach
und performant, beim STM32F1 wird ein 16 Bit Timer benutzt und über
einen 'SlaveCounter' auf 32 Bit erweitert. Hier liegt mMn der
Knackpunkt, das ist nicht richtig Interruptfest. Nach einigen 100 ms bis
s (abhängig von der Periodenzeit) entstehen 65 ms Pausen in denen der
Ticker hängt.
Gefühlsmässig würde ich sagen das ist sehr schwer bis unmöglich sauber
in Software zu lösen, falls doch, wie?
Oder kann man beim STM32F1 Timer kaskadieren um einen echten 32 Bit
Zähler zu erhalten?
Ich habe schon lange in dem Code herumgestochert, falls da jemand mit
reinsehen möchte ist hier die Funktion wie ich sie interpretiere:
- in us_ticker.c ist in us_ticker_read() das Aulesen des Timers und
erweitern auf 32 Bit. Wenn hier ein 16 Bit Überlauf passiert wird (soll)
die Inkosistenz abgefangen.
in us_ticker_set_interrupt(timestamp_t timestamp) wird die neue
CompareMatch Zeit berechnet und gesetzt. Dazu wird das Delta zur
aktuellen Zeit berechnet und kontrolliert ob das noch innerhalb des
Timerüberlaufs passiert. Wenn die Zeit > 65ms ist wird in oc_int_part
n*65 ms gesetzt.
- in hal_tick.c ist die TimerInit und IRQ.
Bei Timerüberlauf wird der Slave inkrementiert.
Bei Compare Match wird der User-IRQ aufgerufen wenn keine n * 65 ms zu
warten ist, sonst wird die restliche Wartezeit berechnet und gesetzt.
Die eigentlich Rechnerei sieht ok aus, nur wenn der Timer kurz vor dem
Überlaufen ist klappt das mit dem SlaveCounter scheinbar nicht.
us_ticker_c:
https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F1/us_ticker.c
hal_tick.c:
https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F1/TARGET_NUCLEO_F103RB/hal_tick.c
das gemeldete Issue:
https://github.com/mbedmicro/mbed/issues/816
im Anhang sieht man die 65 ms Aussetzer im Ausgangssignal.
Mein Beispielprogramm sieht so aus:
1 | #include <mbed.h>
|
2 |
|
3 |
|
4 | Ticker ticker;
|
5 | DigitalOut led1(PC_13);
|
6 | DigitalOut led2(PB_12);
|
7 |
|
8 | void flip() {
|
9 | led2 = !led2;
|
10 | }
|
11 |
|
12 | int main()
|
13 | {
|
14 | ticker.attach_us(&flip, 200); // the address of the function to be attached (flip) and the interval (x microseconds)
|
15 |
|
16 | // spin in a main loop. flipper will interrupt it to call flip
|
17 | while(1) {
|
18 | led1 = !led1;
|
19 | wait(0.1);
|
20 | }
|
21 | }
|
Ich weiss das ist nicht alles einfach nachzuvollziehen, aber die Zahl
der STM32 Experten wächst hier ja.