PWM (Pulse Width Mod) in STM32

Pulse Width Modulation is one of the important functions of timer. PWM is a technique to control analogue circuits with digital output from microcontroller.

As you all know that an Analogue signal is the one whose value varies continuously with time whereas digital signals can only be either high or low. PWM is used for generating an analogue signal using a digital source.
PWM consist of two main components:-
1.) Duty cycle
2.) Frequency

Duty cycle describes the amount of time, the signal is in HIGH state as a percentage of total time, it takes to complete one cycle. Frequency describes how fast the PWM completes a cycle and therefore how fast it switches between HIGH and LOW.

By cycling a digital signal ON and OFF at a fast enough rate and at a certain duty cycle, the output will appear like a constant voltage analogue signal. For eg: To create a 2V signal from a digital source which is either HIGH(5V) or low (0). We can use PWM with duty cycle of 40% here. This 40% duty cycle would yield an average voltage of 5×0.4=2V.

Duty cycle of 25%
Duty cycle of 75%

I am going to use PWM to vary the brightness of a LED by using an input button. SO on each press of the button, the duty cycle will vary from 0 to 100% in 10 steps.  After 100% , it will go back to 0.

CubeMX Setup

First we need to select PWM in the timer section. Also see the PIN which is connected to respective channel of the PWM. PC13 is being used as an input button with internal PULL-UP.

In the CONFIGURATION tab, select timer and make sure your setup is as above. 84-1 will divide the clock frequency by 84, making it 1 MHz. 100-1 further divides the clock. It is the value for ARR( Auto reload Register), The counter counts upto this value and than reset back to 0. So making it 100 is more preferred as it can be counted as %. For eg- if the pulse is set for 30 and ARR is 100, it indicates that the duty cycle is 30%

The clock division is (84MHz/84)/100) giving us 10KHz frequency.

Also 100-1 and 84-1 are such that  HAL adds 1 to these values so we have to write 1 less than the value we want.

This is all regarding the CubeMx setup. Now generate the project and open the IDE.

Some Insight into the Code

 if (!(HAL_GPIO_ReadPin (GPIOC, GPIO_PIN_13)))   // if the user button is pressed
    while (!(HAL_GPIO_ReadPin (GPIOC, GPIO_PIN_13)));  // wait for the button to be released 
    htim3.Instance->CCR1 = increment;   // increase the pulse width in the steps of 10 
    increment+=10;  // increment in 10 steps or by 10% for the duty cycle 
    if (increment>100) increment =0;   // if increment is > 100 than reset its value to 0

Here we will wait for the button to be pressed

  • update the value in the CCR1 Register to change the duty cycle
  • increment the variable


Duty cycle 70%
Duty Cycle 50%
Check out the VIDEO Below

Notify of
Oldest Most Voted
Inline Feedbacks
View all comments