STM32 PWM Example – Timer PWM Mode Tutorial

Previous Tutorial Previous Tutorial Tutorial 16 Next Tutorial Next Tutorial
STM32 PWM Example – STM32 Timer PWM Mode & LABs
STM32 Course Home Page 🏠

 

STM32 PWM Example Tutorial - STM32 Timer PWM Mode HAL CubeMX Tutorial

 

In this tutorial, we’ll discuss the STM32 PWM generation using STM32 timer modules in the PWM mode. You’ll get to know how the PWM signal is generated, how to control its frequency, duty cycle, and how to estimate the PWM resolution. And how to set up the timer module to operate in PWM mode and write a simple application to make an LED dimmer. And without further ado, let’s get right into it!


   Required Components For LABs   

 

All the example code/LABs/projects in the course are going to be done using those boards below.

QTY Component Name 🛒 Amazon.com 🛒 eBay.com
2 BreadBoard Amazon eBay
1 LEDs Kit Amazon Amazon eBay
1 Resistors Kit Amazon Amazon eBay
1 Capacitors Kit Amazon Amazon eBay & eBay
2 Jumper Wires Pack Amazon Amazon eBay & eBay
1 9v Battery or DC Power Supply Amazon Amazon Amazon eBay
1 Micro USB Cable Amazon eBay
1 Push Buttons Amazon Amazon eBay

★ Check The Full Course Complete Kit List

Some Extremely Useful Test Equipment For Troubleshooting:

Affiliate Disclosure: When you click on links in this section and make a purchase, this can result in this site earning a commission. Affiliate programs and affiliations include, but are not limited to, the eBay Partner Network (EPN) and Amazon.com.


   STM32 PWM Mode Preface   

 

As we’ve discussed in an earlier tutorial, the timer modules can operate a variety of modes one of which is the PWM mode. Where the timer gets clocked from an internal source and counts up to the auto-reload register value, then the output channel pin is driven HIGH. And it remains until the timer counts reach the CCRx register value, the match event causes the output channel pin to be driven LOW. And it remains until the timer counts up to the auto-reload register value, and so on.

The resulting waveform is called PWM (pulse-width modulated) signal. Whose frequency is determined by the internal clock, the Prescaler, and the ARRx register. And its duty cycle is defined by the channel CCRx register value. The PWM doesn’t always have to be following this exact same procedure for PWM generation, however, it’s the very basic one and the easier to understand the concept. It’s called the up-counting PWM mode. We’ll discuss further advanced PWM generation techniques as we go on in this series of tutorials.

The following diagram shows you how the ARR value affects the period (frequency) of the PWM signal. And how the CCRx value affects the corresponding PWM signal’s duty cycle. And illustrates the whole process of PWM signal generation in the up-counting normal mode.

STM32 PWM Example Tutorial - STM32 Timer PWM Mode

STM32 Timers – PWM Output Channels

Each Capture/Compare channel is built around a capture/compare register (including a shadow register), an input stage for capture (with a digital filter, multiplexing, and Prescaler) and an output stage (with comparator and output control). The output stage generates an intermediate waveform which is then used for reference: OCxRef (active high). The polarity acts at the end of the chain.

And here is a diagram for the capture/compare channel 1 Full Circuitry

STM32 Input Capture Compare Channel Tutorial - Frequency Counter Measurement

And here is a diagram for the output stage that driver the OCx pins

STM32 PWM Example Tutorial - STM32 Timer PWM Mode Output Compare

A single STM32 timer usually has multiple channels (4, 6, or whatever found in the datasheet). Therefore, using a single timer you can independently generate multiple PWM signals with different duty cycles of course, but they’ll share the same timing (same frequency), and all of them will be in sync. We’ll do this in the 2nd LAB in this tutorial after we set up a single PWM channel and get everything up and running.

Here is a snapshot of the general-purpose Timer2 diagram, which highlights the presence of multiple output compare channels and output drivers.

STM32 PWM Example Tutorial - STM32 Timer PWM Mode TIM2 Output Compare

STM32 Timers In PWM Mode

Pulse width modulation mode allows generating a signal with a frequency determined by the value of the TIMx_ARR register and a duty cycle determined by the value of the TIMx_CCRx register. The PWM mode can be selected independently on each channel (one PWM per OCx output) by writing 110 (PWM mode 1) or ‘111 (PWM mode 2) in the OCxM bits in the TIMx_CCMRx register. The user must enable the corresponding preload register by setting the OCxPE bit in the TIMx_CCMRx register, and eventually the auto-reload preload register by setting the ARPE bit in the TIMx_CR1 register.

OCx polarity is software programmable using the CCxP bit in the TIMx_CCER register. It can be programmed as active high or active low. For applications where you need to generate complementary PWM signals, this option will be suitable for you.

In PWM mode (1 or 2), TIMx_CNT and TIMx_CCRx are always compared to determine whether TIMx_CCRx≤TIMx_CNT or TIMx_CNT≤TIMx_CCRx (depending on the direction of the counter).

The timer is able to generate PWM in edge-aligned mode or center-aligned mode depending on the CMS bits in the TIMx_CR1 register.

Note

PWM signals have a lot of properties that we need to control in various applications. First of which is the frequency of the signal. And secondly, and probably the most important one, is the duty cycle. Third, is the PWM resolution. And much more to be discussed in later tutorials, we’ll get into those 3 properties in the next sections down below.

STM32 PWM Frequency

In various applications, you’ll be in need to generate a PWM signal with a specific frequency. In servo motor control, LED drivers, motor drivers, and many more situations where you’ll be in need to set your desired frequency for the output PWM signal.

The PWM period (1/FPWM) is defined by the following parameters: ARR value, the Prescaler value, and the internal clock itself which drives the timer module FCLK. The formula down below is to be used for calculating the FPWM for the output. You can set the clock you’re using, the Prescaler, and solve for the ARR value in order to control the FPWM and get what you want.

STM32 PWM Frequency Formula - STM32 PWM Frequency Equation

STM32 PWM Duty Cycle

In normal settings, assuming you’re using the timer module in PWM mode and generating PWM signal in edge-aligned mode up-counting configuration. The duty cycle percentage is controlled by changing the value of the CCRx register. And the duty cycle equals (CCRx/ARR) [%].

STM32 PWM Duty Cycle Formula - STM32 PWM Duty Cycle Equation

STM32 PWM Resolution

One of the most important properties for a PWM signal is the resolution. It’s the number of discrete duty cycle levels that you can set it to. This number determines how many steps the duty cycle can take until it reaches the maximum value. So, the step size or the number of duty cycle steps can tell how fine can you change the duty cycle in order to achieve a certain percentage. This can be extremely important in some audio applications, motor control, or even light control systems.

This is the STM32 PWM resolution formula that can be used to calculate the resolution of the PWM signal at a specific frequency or even the opposite. If you’re willing to get a 10-Bit resolution PWM signal, what should the frequency be in order to achieve this? And so on..

STM32 PWM Resolution Equation - STM32 PWM Resolution Formula

In other situations, you’ll need to adjust the ARR value. Therefore, you’ll need to know the relationship between it and the PWM resolution. This is not a new formula, it’s derived from the first one and the FPWM equation that you’ve seen earlier in this tutorial. We’ll need it in later tutorials for designing our Motor driver library and some other applications.

Check this table which shows you some example frequencies and the PWM resolution at each FPWM frequency.

STM32 PWM Resolution Example - STM32 Timer PWM Mode Output Compare

STM32 PWM Different Modes

The PWM signal generation can be done in different modes, I’ll be discussing two of them in this section. The edge-aligned and the center-aligned modes.

1- Edge-Aligned Mode

In the edge-aligned PWM mode there exist a couple of possible configurations:

  • Up-Counting Configuration
  • Down-Counting Configuration

In the following example, we consider PWM mode 1. The reference PWM signal OCxREF is high as long as TIMx_CNT <TIMx_CCRx else it becomes low. If the compare value in TIMx_CCRx is greater than the auto-reload value (in TIMx_ARR) then OCxREF is held at ‘1. If the compare value is 0 then OCxREF is held at ‘0.

STM32 PWM Example Edge-Aligned Tutorial - STM32 Timer PWM Mode Output Compare

2- Center-Aligned Mode

The compare flag is set when the counter counts up when it counts down or both when it counts up and down depending on the CMS bits configuration. The direction bit (DIR) in the TIMx_CR1 register is updated by hardware and must not be changed by software.

The diagram below shows some center-aligned PWM waveforms in an example where: TIMx_ARR=8, PWM mode is the PWM mode 1.

STM32 PWM Example Center-Aligned Tutorial - STM32 Timer PWM Mode Output Compare

 

 


   STM32 PWM Example LED Dimmer   

 

LAB Number 12
LAB Title Timer Module In PWM Mode LED Dimmer
  • Set up timer 2 to operate in PWM mode with the internal clock. And enable CH1 to be the PWM output channel.
  • Set the ARR value to the maximum 65535 for example, so the frequency should be 1098Hz
  • Control the duty cycle by writing to the CCR1 register
  • Make Duty Cycle sweep from 0% up to 100% back and forth

 


   STM32 PWM Example LED Dimmer   

 

In this LAB, our goal is to build a system that sweeps the duty cycle of the PWM channel1 from 0 up to 100% back and forth. So that the LED brightness follows the same pattern. The auto-reload register will be set to a maximum value which is 65535, for no particular reason. But you should know that the output FPWM frequency is expected to be 1098.6Hz from the equation we’ve seen earlier. And the PWM resolution is estimated to be 16-Bit which is the maximum possible value for this module.

 

And now, let’s build this system step-by-step

 

Step1: Open CubeMX & Create New Project

Step2: Choose The Target MCU & Double-Click Its Name

Step3: Configure Timer2 Peripheral To Operate In PWM Mode With CH1 Output

STM32 PWM Example CubeMX Tutorial - STM32 Timer PWM Mode

Step4: Set The RCC External Clock Source

STM32 RCC External Clock Selection CubeMX

Step5: Go To The Clock Configuration

Step6: Set The System Clock To Be 72MHz

Step7: Name & Generate The Project Initialization Code For CubeIDE or The IDE You’re Using

 

Here is The Application Code For This LAB

#include "main.h"

TIM_HandleTypeDef htim2;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);

int main(void)
{
    int32_t CH1_DC = 0;

    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_TIM2_Init();
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
    while (1)
    {
    	while(CH1_DC < 65535)
    	{
    	    TIM2->CCR1 = CH1_DC;
    	    CH1_DC += 70;
    	    HAL_Delay(1);
    	}
    	while(CH1_DC > 0)
    	{
    	    TIM2->CCR1 = CH1_DC;
    	    CH1_DC -= 70;
    	    HAL_Delay(1);
    	}
    }
}

Download The PWM LED Dimmer LAB12 Project

 

The Resulting PWM Signal On My DSO

Note that the frequency is exactly 1098.6Hz!

The Resulting PWM LED Dimmer

 


 

 

Stay tuned for the upcoming tutorials and don’t forget to SHARE these tutorials. And consider SUPPORTING this work to keep publishing free content just like this!

 

Previous Tutorial Previous Tutorial Tutorial 16 Next Tutorial Next Tutorial

 

Share This Page With Your Network!

Khaled Magdy

I'm an embedded systems engineer doing both Software & Hardware. I'm an EE guy who studied Computer Engineering, But I'm also passionate about Computer Science. I love reading, writing, creating projects and Technical training. A reader by day a writer by night, it's my lifestyle. You can view my profile or follow me via contacts.

You may also like...

3 Responses

  1. Christiaan Meerkerk says:

    My project isnt recognising those 3 rows
    SystemClock_Config();
    MX_GPIO_Init();
    MX_TIM2_Init();
    Where are they and how are they generated?

    • Khaled Magdy says:

      Those functions are generated by CubeMX and you can find the definition of each function in the main.c file

  2. Reza Ikhsan Ardhani says:

    can you give wiring this experiment?
    thank you

Leave a Reply

%d bloggers like this: