timerstm32pwm

STM32 PWM Generation


I need to generate PWM in periods of 20ms and at a frequency of 50Hz. The pulse width (duty cycle) of the generated PWM should be between 1.5 and 2ms

I'm using STM32f103c8t6 mcu and my APB2 peripheral clock is 72MHz. I Will use TIM4 CH1 to generate pwm.

Currently, I tried to do it according to the following formula:

Frequency = ClockFreq / ((PSC + 1) * (ARR + 1))

1440 * 1000 = 1.440.000

72.000.000 / 1.440.000 = 50 = Frequency

The part I can't understand after this calculation is; what should i set TIM4->CCR1 value for generate 1.5ms pulse width and what do I need to do to make the period 20ms?


Solution

  • First, some general words about configuring a timer:

    1. All timer configs are expressed in timer ticks. Timer tick frequency is TimerBaseFreq/TimerPrescaler (1 timer tick = timer counter incremented by 1)
    2. Determine the duration of a single timer tick via setting the prescaler
    3. Determine the duration of a timer period in timer ticks, set auto-reload register
    4. Determine the duration of compare=true event in timer ticks, set compare value register
    5. Don't forget to configure compare function of the timer (enable compare, set compare output destination - e.g. GPIO or another timer), check if your timer is upcounter or downcounter, etc.

    Also, timer base frequency is not equal to CPU frequency. It may be equal, it may be not, depends on timer clock configuration. It's usually tied to APBx clock frequency of the APB bus the timer sits on (and it can be double APBx clock, it can be equal to APBx clock, sometimes it's derived from AHB clock instead, depends on specific clock configuration; in many "default" max clock configurations of MCUs timer base clock is usually equal to (double APBx clock) = CPU clock).


    Now that we have the algorithm to configure a timer, we can actually follow it:

    Let's use your prescaler of 1440, because it really is a nice value that comfortably divides the timer base clock.
    72*10^(6) / 1440 = 72*10^(6) / (72*2*10) = 10^4 * 5 = 50kHz, which is equivalent to 1/50kHz = 20us period. 20us is the time it takes the timer to increment its counter by 1.

    Now, you just need to calculate how many of those timer ticks would make up your desired period. Your desired period is 20ms (equivalent to 50Hz), so you need 1000*20us ticks. Thus, ARR should be 999. Every 1000 timer ticks (= every 20ms), the counter will start over.

    Notice how prescaler and auto-reload value can be different, but still produce the same timer period. For example, you can have half the prescaler (timer ticks twice as fast then), but you will need double the number of ticks to produce timer period of the same duration. The difference is usually in 1) how many bits wide can PSC and ARR be (varies from timer to timer, often only 16-bit values allowed, sometimes 32-bit) and 2) granularity - all timer behavior parameters depend on timer's tick duration, the shorter the tick, the more finely you can control period/compare threshold. Your job is to find a good balance between these two, depending on your application. Sometimes you want it to be as granular as possible, sometimes it doesn't matter at all.

    Now, the compare part is left, and there is no magic about it either: all you need is to calculate how many timer ticks your desired pulse is supposed to be. 1.5ms would be 75 ticks, 2ms would be 100 ticks. As you can see, with this timer prescaler, there are only 26 values within this range (including 75 and 100). If you had a prescaler of 2880, then timer period duration of 20ms would require 2000 of those shorter ticks. Compare values would be in the range of 150 and 200, giving you double precision. You can extend this logic further, just don't forget how large your prescaler and auto-reload values are allowed to be.