Skip to main content
LMorr.3
Senior
May 10, 2022 6:59 PM UTC
Question

Dividing hardware timer in software

I have a hardware timer using its updateEvent interrupt to increment a ms_passed variable every 1 ms. I have a freeRTOS task reading ms_passed ( via TaskNotification ) in a while(1) loop to toggle a pin at a given time interval/tempo based on a variable BPM ( beats per minute ).

I would like to be able to divide 4 'clocks' in software based on the ms_passed ticks. I have implemented a rough solution based on a similar way of setting baud rates registers, ( integer and remainder registers ) and use no floating points, but I still get drift. If I run toggle 2 leds, they are in sync initially but end up out of sync with drift introduced after several minutes.

Does anyone know of an example i can look at in case this has already been done or have suggestions on the best approach?

Thanks!

This topic has been closed for replies.

6 replies

Tesla DeLorean
Guru
May 10, 2022 9:23 PM UTC

Well NCO/DDS methods use an ADDER, basically you add a value to a 32-bit "phase accumulator" register, and the high order bit(s) can reflect the on/off state, or phase angle into a SINE ROM. Usually done in HW, usually clocked at high rates.

If it is walking off, you might need to add/subtract 1 from the value you're adding in. Generally pretty good at doing fractional rates that simple integer divider/counter methods fail at spectacularly.

Where are the TWO LEDs connected?

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
LMorr.3
LMorr.3Author
Senior
May 10, 2022 10:10 PM UTC

Good info. for me to research, thanks. I'm currently using a DISCO F407 dev board and I'm just toggling LEDs when I trigger 2 of my clock divisions. ( GPIOD, GPIO_PIN_14 and GPIOD, GPIO_PIN_15 ) I plan replacing my LED toggles with a trigger to a hardware timer to generate a one-time-pulse. ( I have that part working well )

For my test, I set BPM to 65 and divide 2 clocks to run them both side-by-side to detect drift. One clock is divided by /1 and the second is divided /2 with the idea of seeing one LED toggle at half of the other's rate. This is where I'm seeing the drift after a few minutes.

gbm
Super User
May 10, 2022 9:32 PM UTC

Whaty you are trying to do is in conflict with RTOS philosophy. That's what timing system was designed for. Use osDelayUntil() or RTOS timers.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
LMorr.3
LMorr.3Author
Senior
May 10, 2022 10:12 PM UTC

Thanks for pointing this out, I will revisit using freeRTOS software timers, which is where I started. I thought they may not be accurate enough ( 1ms resolution ) but did not know about compensating for drift at the time.

gbm
Super User
May 11, 2022 5:10 PM UTC

It's roughly the same. I would recommend to stick to one RTOS interface; I believe CMSIS-RTOS2 is the way to go. Generally CMSIS osXxx calls are easier to use and more immune to simple mistakes than native FreeRTOS calls.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice