2026-02-19 1:02 PM
Hello,
I want to generate four 50% duty cycle frequencies up to ~12kHz. It should be possible to enable/disable single outputs. Currently no special high requirements about accuracy, etc. Using a STM32U0 device (56MHz max).
My first thought was to use an upcounting timer with four output compare channels where the timer itself is free running (ARR set to max. value). The compare channels are set to toggle on match and on each OC interrupt, the corresponding CCR register value is set to the next equivalent ARR value to toggle again. For example, if the timer is running at 1MHz and 1kHz frequency is needed, 1000 will be added to the CCR. To start/stop the output, I'd modify the corresponding OCxM value between toggle and frozen mode.
However, I'm not sure if this is the most efficient way, especially regarding overhead and complexity. Another solution which came to my mind was to use a DDS approach with a (low power) timer, constantly firing interrupts at the needed resolution. On each interrupt, a variable (per channel) is increment by a given value and toggling the output (simple GPIO output) on overflow.
For the first approach I assume the accuracy is better since the output is controlled by hardware, but it would have jitter if two or more compare interrupts occur at the same time (might depend on how the calculation for the next CCR value is performed). The second approach would enable me to serve all outputs simultaneously within a single interrupt.
Any recommendations or additional pros/cons for those approaches?
Regards
Solved! Go to Solution.
2026-02-20 10:55 AM
Waste three timers is based on what you need waste. For complete MCU offloaded generator you require 4 timers every with one channel. Zero instructions is used for hold signals on setup freq.
Oposite force is use one timer = waste many instructions on every ISR.
Both is efficient own way.
2026-02-19 1:27 PM - edited 2026-02-19 1:27 PM
Have one timer output the same PWM on each of 4 channels.
Change CCRx value to something above ARR when you want to turn off the channel. Put them back at their previous value when you want to turn it back on.
2026-02-19 2:06 PM
Hi @TDK
@TDK wrote:Have one timer output the same PWM on each of 4 channels.
By PWM you mean output compare with toggle on match, so basically the first approach I mentioned, right? If not, then I don't understand how using PWM could be used to generate four independand frequencies since in PWM mode the ARR defines the frequency.
@TDK wrote:Change CCRx value to something above ARR when you want to turn off the channel. Put them back at their previous value when you want to turn it back on.
I assumed this is also possible, but I couldn't find anything in the reference manual if this is allowed or would result in undefined behaviour. It would be easier than modifying the OCxM bits.
Regards
2026-02-19 3:15 PM
Not toggle on match. PWM mode 1. CCRx should be half of (ARR+1) to give a 50% square wave.
2026-02-19 5:04 PM
Another possible approach - use DMA (circular mode) to write to the GPIO BSRR register (to set/reset bits directly), you could clock the DMA from the LSE or similar. I use this technique a lot for Led displays.
2026-02-20 12:20 AM
If you cannot afford using 4 timers, the approach you outline seems to be the next good candidate. 12 kHz * 4 is close to nothing for the MCU, assuming you don't use HAL interrupt handling slowdown facility. Just write your own, register-based code (will be much shorter than HAL-based). Actually, it's 3 lines of C code per channel in the timer ISR:
if (TIMx->SR & TIM_SR_CCyIF)
{
TIMx->SR = ~TIM_SR_CCyIF;
TIMx->CCRy += halfperiod[y];
}
2026-02-20 4:50 AM
> ... assuming you don't use HAL interrupt handling slowdown facility.
Made my day! :D :D :D
2026-02-20 5:09 AM
Maybe I wasn't clear enough, sorry: I need different frequencies per channel and the frequencies will change during runtime. This can't be achieved using a single timer and channel PWM mode since ARR defines the frequency.
@gregstm
Interesting idea using DMA. I'll check if it would be feasible.
@gbm
It's not that I can't afford using four timers, it's more like that I don't want to waste three timers if it could be done with one timer :) Would be bad practice, I think.
Good point with avoiding HAL for the IRQ, I think writing a naked handler should be possible.
Thank you all for your answers.
Regards
2026-02-20 7:16 AM - edited 2026-02-20 7:17 AM
> Maybe I wasn't clear enough, sorry: I need different frequencies per channel and the frequencies will change during runtime. This can't be achieved using a single timer and channel PWM mode since ARR defines the frequency.
Ahh, that certainly changes things.
You can't generate 4 different frequencies with one timer, so you are left with the other options. If you need them to have zero-jitter, you'll need to use four timers. If a small amount of jitter is acceptable, either DMA or interrupt will do.
(Well, technically you could update CCRx every iteration and use toggle on match to get different frequencies and use DMA to update. Pretty involved, though.)
2026-02-20 10:55 AM
Waste three timers is based on what you need waste. For complete MCU offloaded generator you require 4 timers every with one channel. Zero instructions is used for hold signals on setup freq.
Oposite force is use one timer = waste many instructions on every ISR.
Both is efficient own way.