2021-12-21 08:51 AM
An STM tutorial on timers has errors regarding PWM mode, for STM32.
The tutorial is: "STM32L4 - Timers : Advanced-control, general-purpose, and basic timers"
It is a slide-set, with notes. There are at least a couple versions of it, e.g., a version for STM32WB.
https://www.st.com/resource/en/product_training/STM32L4_WDG_TIMERS_GPTIM.pdf
The tutorial's introduction indicates the slides are describing STM32 timers in general. This is corroborated by the reference manuals for STM32L4 and STM32F76xxx [STM18, STM20]. The manuals have identical sections titled "PWM mode".
#### Problem Summary ####
The problems are summarized here, and more info is in the "Details" section, below.
References are listed at the end.
#### The duty-cycle equations are incorrect:
In the tutorial, on page 32, this equation appears to be incorrect:
duty_cycle = (CCRx + 1)/(ARR + 1)
I think it should be:
duty_cycle = CCRx/(ARR + 1)
The STM32L4 reference-manual describes how CCRx specifies the duty-cycle [STM18, pages 938f]. It does not seem to involve adding 1 to CCRx.
Similarly, on the tutorial's page 32, the derived equation is incorrect:
CCRx = (duty_cycle * (ARR+1)) - 1
To illustrate the error, a duty-cycle of 0 results in a CCRx value of -1, which can't be stored in CCRx.
#### The PWM-resolution equations are incorrect
In the tutorial, on page 32, this equation appears to be incorrect:
Res(steps) = Ftim / Fpwm
The problem is that those frequencies are based on different units, so they can't be divided in a meaningful way.
* Ftim is the clock frequency, i.e., clock_tics/second
* Fpwm is based on a scaled-clock frequency, i.e., scaled_clock_tics/second
The equation for Fpwm is given earlier, on page 31. PSC is the prescaler register:
Fpwm = Ftim / ((ARR + 1) * (PSC + 1))
Resolving the Res(steps) equation leads to:
Res(steps) = (ARR+1) * (PSC+1)
This is the number of clock-tics per PWM cycle. That doesn't make sense as the PWM resolution, unless PSC is 0.
#### Problem Details ####
#### The duty-cycle equations are incorrect:
In the tutorial, on page 32, this equation appears to be incorrect:
duty_cycle = (CCRx + 1)/(ARR + 1)
I think it should be:
duty_cycle = CCRx/(ARR + 1)
For example, the STM32L4 reference-manual specifies the following for PWM mode 1, in edge-aligned mode with up-counting [STM18, page 939]:
* CCRx specifies how long the signal is high. So, (CCRx+1) does not specify how long the signal is high, as the tutorial seems to claim.
* (ARR+1) specifies how long the PWM cycle is.
* For CCRx and ARR, the units are in scaled-clock-tics (scaled by (PSC+1))
* A CCRx value of 0 specifies a duty-cycle of 0.
* A CCRx value greater-than ARR specifies a duty-cycle of 100%
That errant equation does not allow for a duty_cycle of 0. Setting CCRx to 0 does not produce a duty_cycle of 0.
Also, the errant equation calculates a duty-cycle greater than 100% for a CCRx value greater-than the ARR value.
Similarly, on the tutorial's page 32, the derived equation is incorrect:
CCRx = (duty_cycle * (ARR+1)) - 1
There, a duty_cycle of 0 calculates a CCRx value of -1, which isn't possible.
Also, a duty_cycle of 100% does not calculate a CCRx value greater than the ARR value, which is required.
#### The PWM resolution equations are incorrect
In the tutorial, on page 32, this equation appears to be incorrect:
Res(steps) = Ftim / Fpwm
The problem is that these frequencies are based on different units, so they can't be divided in a meaningful way.
Ftim is the clock frequency, i.e., clock_tics/second
Fpwm is based on a scaled-clock frequency (scaled by (PSC+1)), i.e., the units are scaled_clock_tics/second.
The equation for Fpwm is on page 31:
Fpwm = Ftim / ((ARR + 1) * (PSC + 1))
Resolving the Res(steps) equation leads to:
Res(steps) = (ARR+1) * (PSC+1)
This is the number of clock-tics per PWM cycle, which doesn't make sense as the PWM resolution.
For example, if ARR is 0, there's minimal PWM resolution. There are only two possible duty-cycles: 0% and 100%. Increasing PSC will not increase the duty-cycle resolution. However, in the equation, increasing PSC would increase the resolution, for an ARR of 0.
The Res(steps) equation is only correct when PSC is zero.
For example, there is an STM Applicaton Note on PWM resolution, and it uses the same Res(steps) equation as the tutorial [STM17, page 6]. However, the STM Applicaton Note makes no mention of a prescaler being used.
In the tutorial, page 32 also has a derived equation using log base-2. So, it's also incorrect.
#### References ####
[STM17] STM, "PWM resolution enhancement through a dithering technique for STM32 advanced-configuration, general-purpose and lite timers", Application note AN4507, January 2017
[STM18] STM, "Reference manual : STM32F76xxx and STM32F77xxx advanced Arm-based 32-bit MCUs", RM0410, March 2018
[STM21] STM, "STM32L47xxx, STM32L48xxx, STM32L49xxx and STM32L4Axxx advanced Arm-based 32-bit MCUs", Reference manual RM0351, June 2021
2021-12-22 01:07 AM
Hello @JimYuill and welcome to the Community 🙂
Thank you for taking the time to post the errors in the Community!
Your feedback is reported internally for review and correction.
Thanks
Imen
2021-12-22 08:09 AM
Imen,
Thanks. Any feedback is appreciated, esp corrections to my bug report.
The STM tutorial with those problems was actually very useful. I'm new to STM32 and timers, and it was hard to find a tutorial for newbies. FYI, I ended-up writing a tutorial on using STM32 timers in PWM mode, for dimming LEDs. It's part of an open-source project related to learning FreeRTOS:
https://jimyuill.com/embedded-systems/study-guide-freertos-book/chapter-13--part-1.html
2021-12-22 08:12 AM
Imen,
BTW: There's an additional bug in the STM docs, related to PWM mode for timers. It might be worth fixing or clarifying. The doc is:
"LED dimming implemented on STM32 microcontroller", Application note AN2841, November 2008
Page 5 has a description of duty-cycle values, "Using a 4-bit PWM resolution, there can be 16 different light intensity (energy) values." It's illustrated by Figure 1, "PWM signal with 16 steps of possible voltage values"
This description and calculation don't take into account a duty-cycle of 0, i.e., the signal being low for all 16 steps. With it, there are 17 different light intensity (energy) values.
2022-01-15 11:28 AM
Regardless if it's for PWM or something else, 4 bits cannot code more than 16 values of anything. A PWM with 4-bit resolution can have 16 width values in a range of [0; 15], including the full off and full on.
2022-01-25 01:02 AM
Hi @JimYuill ,
Thanks for you feedback and for taking time to report this with many details.
We confirm the equation in the tutorial is not correct, and is indeed as you wrote:
duty_cycle = CCRx/(ARR + 1)
We confirm as well that the resolution equation is valid only for PSC = 0.
For most of the PWM use cases (with frequencies in tens of kHz range), the prescaler is set to zero to have the finest possible steps. Therefore this shortcut.
The 1kHz value taken in the example was to just to show how we can use the prescaler.
Anyway, we will correct these 2 points in the material, your comments are completely valid.
Still, what is not clear to us is why you say the log base-2 equation is not correct.
Let’s say we have 1024 steps (100MHz device and ~100kHz PWM to make it simple), and we low pass filter this PWM to have a DAC functionality.
In this case, the resolution will be equivalent to a 10-bit DAC (log (1024,2)).
Do you agree with this?
Thanks and best regards,
Vincent
2022-02-01 09:11 AM
Hi @JimYuill
Do you agree with @Vincent Onde proposal regarding log base-2 ?
If yes, please mark his reply as Best answer (click on "Select as Best"), and please don't hesitate to share your feedback.
Thanks
Imen