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 Analog 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

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%

CubeMX Setup

The clock setup is as follows

  • External Crystal is used to provide the clock via the PLL
  • I am going to use the TIM1 for the PWM, which is connected to the APB2 Bus
  • The APB2 Timer clock is at 72MHz right now.
  • Select the PWM channel for the Timer, I am using Channel 1.
  • Set the Clock source as internal clock.
  • Pin PA8 is set as the PWM output Pin.

As I mentioned above that Timer 1 clock is at 72 Mhz. Using the Prescaler of 72 will bring the clock down to 1 Mhz.

Further using the ARR of 100 will set the PWM Frequency = 10 KHz. This is shown in the image below

Why do we need to use -1 ?

This is the setup as per the registers in STM32. The Prescaler Register and the ARR Registers are setup in a way, that they add a 1 to the value.

So whatever value we enter for the PSC, 1 will be added to that value. This is why we enter 1 less than the actual value.

Some Insight into the Code

 TIM1->CCR1 = 30;
 HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
  • Here we will set the value in the Capture Compare Register (CCR).
  • Since I am using Channel 1, the Register is CCR1.
  • And we will start the Timer in PWM mode

The value set in the CCR decides the width of the pulse. The formula to calculate the duty cycle is shown below


Duty cycle 30%, freq = 10 KHz

As we configured the Timer 1 clock at 10 KHz, our signal period is 100us. Also the CCR1 value is set to 30, so we got the duty cycle of 30%.

You can check the video to see the detailed output.

Check out the Video Below


You can help with the development by DONATING
To download the code, click DOWNLOAD button and view the Ad. The project will download after the Ad is finished.

20 Comments. Leave new

  • Diego Ulises
    June 15, 2024 8:41 AM

    Para que utilizas interrupciones! solo quiero enviar una señal pwm solo eso. You code while is empty not interrpt

  • Great example! Worked fine for me for anyone who can’t get it working
    1) Make sure PWM Timer is enabled.
    2) Make sure CCR value is correct.
    3) Double check Timer clock settings.

  • Thanks for your tutorial.
    I switched from Microchip to STM32 and everything is a little bit different^^
    I use the Board Nucleo G474RE and got the PWM-Output working. So I wanted to use more outputs with the same PWM-Timer and set the CCR for Channel 2, 3 and 4 of TIM1.
    Unfortunately I get only an output on channel 1.

    I tried this:
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);
    and this: //makes no sense for me…

    with the CCR-Settings:
    TIM1->CCR1 = 120; // PWM OUTPUT is on PIN A5 (PC0)
    TIM1->CCR2 = 120; // PWM OUTPUT is on PIN A4 (PC1)
    TIM1->CCR3 = 120; // PWM OUTPUT is on opposite Pin of A5 (PC2)
    TIM1->CCR4 = 120; // PWM OUTPUT is on opposite Pin of A4 (PC3)

    best regards

    • Yeah, I got it running.
      Unfortunately I selected “Output Compare CHx” instead of “PWM Generation CHx”.

  • I want to see how you wire up the complete circuit and what are the necessary links

  • Hi I want to use example but with an interrupt, can I modify CCRx while using interrupt? if not I can just use the example as is. But will I get accurate timing with the cpu running other parts of the code if I don’t use interrupt?

  • Hi I want to use example but with an interrupt? can I modify CCRx while using interrupt? if not I can just use the example as is. But will I get accurate timing with the cpu running other parts of the code if I don’t use interrupt?

  • I used the same configuration, but the last example didnt work either. There is no signal output at TIM_CH1. The others worked as expected.
    I use STM32F410RB board.

    • There is nothing in this example, so “not working” is not possible.
      Check your CCR value, also if you have started the timer in PWM mode.
      Also make sure you are measuring the output from the right pin.

  • You are the best! Thanks for all of your work.

  • I am using the STM32F401RE with the same code and same configuration, I confirmed the oscillator is 8Mhz and check that TIM1 is on APB1 – when I connect my logic analyzer I see nothing, no PWM signal.
    is there something I can check to figure out what I am missing ?

  • That works like a charm !

  • Graham Gillett
    February 19, 2020 6:10 PM

    I am running a Nucleo-64 with a STM32F401RE on it and the PWM frequency, as clocked by APB1, is nothing compared to what it should be. Say APB1 clock frequency is 84MHz and the pre-scale is 20 I get 19.84MHz on the PWM output?

  • Abhishek Gupta
    June 6, 2018 11:32 AM

    How to generate a center aligned pwm.

    • Because the PWM is a periodic signal it is center aligned.
      But it is easier to to read the time if you don’t view it as center aligned.


Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.


Adblocker detected! Please consider reading this notice.

We've detected that you are using AdBlock Plus or some other adblocking software which is preventing the page from fully loading.

We don't have any banner, Flash, animation, obnoxious sound, or popup ad. We do not implement these annoying types of ads!

We need money to operate the site, and almost all of it comes from our online advertising.

Please add to your ad blocking whitelist or disable your adblocking software.