PWM basics on the STM32 general purpose timers

By | February 6, 2016

The STM32 Family processors include general purpose timers that have a nice PWM function that can handle four channels of independently controlled duty cycles. In this article I will look at how to set these up for basic use suitable for the majority of applications that need PWM signals.

PWM with the general purpose timers

This is part of a series of articles about the general purpose timers found in the STM32 family of ARM cortex processors. In the preceding parts I introduced the TIM3 timer features, showed you how to identify the timer clock and set up the prescaler and reload register, and how to use the output compare interrupts. You can see all the STM32 TIM3 posts here. Code is written using the Standard Peripheral Library for the STM32F4Discovery board. Timer related portions should run directly on other STM32 family members since they all have a TIM3 or other identical general purpose timer.

A small change for the STM32F4Discovery

This article will switch to using the TIM4 timer simply because it has the output compare pins for TIM4 conveniently connected to four LEDs on the board. That will let me test the code directly on the STM32F4Discovery without wiring up any other LEDs. TIM4 is identical in all respects to TIM3 and everything here will work perfectly well on any of the general purpose timers so long as you take note of the output pins where present on your specific device.

In this article, I am going to look at how the general purpose timers on the STM32 Family of processors can be used to generate up to four channels of PWM, each with its own independent duty cycle.

PWM

Pulse Width Modulation is a way of modifying a signal my changing the proportion of time it is on and off. There are other uses of the term but, for now, I am only interested in signals where the amount of time that the signal is active – the duty cycle – can be varied from 0 to 100%. Signals such as these are used a lot in power control applications like light dimmers and motor speed control. The brightness of your computer screen is almost certainly controlled by a PWM signal.

The STM32 general purpose timers like TIM3 and TIM4 have hardware that makes it easy to generate PWM signals. In fact they have several modes for just this purpose. I will consider only simplest type which is good for the great majority of application. There are four channels available and each can have a different duty cycle although the basic frequency will be the same for each.

Basic PWM mode is similar to the output compare toggle mode except that the output pin is cleared whenever there is a match between the CCRx and the CNT registers and then set again when the counter reloads.
PWM on three channels from the STM32 general purpose timer

The diagram shows the default behaviour. This is the arrangement that is most intuitive. It is also possible to configure a channel to have an inverted state. That is, it will be set on a match and cleared the reload. This can be useful when driving motors both forwards and backwards.

PWM frequency

The frequency of the PWM signal can be important parameter of the setup. For changing the brightness of an LED, any frequency above a few tens of Hertz will not be seen by the eye. Below that and the light will seem to flicker. Even at relatively high frequencies you may sometimes see spotty trails left by PWM dimmed lights as your vision tracks across them. For motors, it is often a good idea to have PWM frequencies of well above the range of normal hearing. Otherwise, your motor controller will appear to whine a lot. It is someties difficult to distinguish the whining of the motor from the whining of the customers who have to listen to it.

PWM resolution

Another factor to take into account is the minimum resolution you need from the PWM system. That is, how many different steps in duty cycle are needed. The most obvious choices might be 100 steps, corresponding to percentages, or 256 steps, corresponding to the range of values in an 8 bit integer. Perhaps you only want 16 different intensities of a backlight. It is generally OK to have more resolution than you need but to have less might be a problem.

Configure the timer timebase

As with other timer problems, there are a number of constraints to consider when setting up the timer timebase. These are:

TIMER_Frequency – the input clock to the timer module
PWM_Steps – the number of different duty cycles needed
PWM_Frequency – the repetition rate of the PWM signal

These numbers determine the reload register and prescaler values used to configure the timer.

Suppose I want to have 100 different PWM levels and a frequency of 100Hz for a simple LED dimming application. First, I need to calculate the frequency needed to drive the counter

COUNTER_Frequency = PWM_Frequency * PWM_Steps = 100 * 100 = 10000 = 10KHz

Now I need to find a value for the prescaler that will give me a 10kHz clock from the Timer_Frequency

TIMER_Prescale = (TIMER_Frequency / COUNTER_Frequency) – 1 = 72000000/10000 – 1 = 7199

This value is safely within the range of an unsigned 16 bit register so I should be safe to proceed.

The ARR register will get a value that is PWM_Steps – 1 and I am ready to configure the timer timebase.

PWM configuration

With the timebase sorted out, I can concentrate on configuring the PWM. This turns out to be really easy when using the Standard Peripheral Library. Also, the designers of the chip made sure that the default values for many registers in the timers produce a basic working configuration. All I really need to do is tell the library function that I want to use PWM mode 1 (the simple one) and that I want to connect the output state to the OCx pin. In my example, I have configured one of the channels, the one for the blue LED, to be low polarity and the others to be high polarity. If you run the code, you will see that, with the same value for duty cycle, they have opposite brightness.

Using the PWM

Once enabled and active, the duty cycle for each channel can be set either with a call to the library functions or by setting the CCRx register directly. Either way, the value is updated the next time the counter reloads so that there are no glitches. You are free to write a value to the CCRx register that is outside the range that can be matched by the counter. If you do that, the output will stay in one state or another. If you want the output to stay active or inactive you can simply set a duty cycle at one or the other extreme.

Bonus – flickering flame effect

In the application listing below, I set one LED to fade up while the other fades down thanks to the ease with which the PWM can be set to complementary mode.

The red LED will flicker with a flame-like effect and you may be interested in how this is done. The most obvious choice might be to generate a random duty cycle and set the channel with that. The result is not very pleasing with large excursions in the output intensity and visible high-frequency components that do not look very realistic. A basic property of random numbers is that if you average several of them, you get a new random number with a normal distribution. The more values that you average, the less the variation in the output. Here I average uniformly distributed number to gat an average 50% duty cycle and give that to the PWM channel looking after the red LED.

4 thoughts on “PWM basics on the STM32 general purpose timers

  1. Pingback: TIM3 on the STM32 - an introduction - Micromouse Online

  2. Stickler

    first include statement in the last code listing is missing file.

  3. Peter Harrison Post author

    So it is. Thank you.

    The line should, I think, be

    #include

  4. Pingback: Creating a stand-up countdown buzzer - Pt 2 - Fourtress

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.