Library 48- Measure PWM input signal with STM32F4

First library in 2015 is here. With it, you will be able to measure PWM input signal from “other world”. STM32F4’s timers have capability to make an interrupt on edge, when signal is active on input pin for specific timer. This allows us, to measure signal in input. With a simple calculations, we can detect frequency of signal and duty cycle.

Of course, this is not veery accurate, but with 168MHz F407 device, using 32bit TIM2 (high resolution) I got pretty good results. Input PWM was set to random value 2545Hz with 23% duty cycle. Results from TIM2 were:

  • Frequency: 2545.13Hz
  • Duty cycle: 22.97%

Result’s quality depends on frequency you measure and also on timer’s performance (prescaler, max period value).

In library below, everything you have to set are:

  • Timer you will use for measuring signals
  • Timer’s IRQ for NVIC interrupt request
  • Create timer’s IRQ for interrupt handler
  • Call defined function in this handler
  • Call function to get results
  • More in example..



  • Measure PWM input signal on all available timers with input pin possibility
  • Measure frequency and duty cycle


    • STM32F4xx
    • STM32F4xx RCC
    • STM32F4xx GPIO
    • STM32F4xx TIM
  • TM
    • defines.h

Table below shows all possible pins for each timer and channel. You can select any of max 3 pins for each input channel.

Timer Channel 1 Channel 2
TIM 1 PA8 PE9 PA9 PE10
TIM 2 PA0 PA5 PA15 PA1 PB3
TIM 4 PB6 PD12 PB7 PD13
TIM 5 PA0 PH10 PA1 PH11
TIM 10 PB8 PF6
TIM 11 PB9 PF7
TIM 12 PB14 PH6 PB15 PH9
TIM 13 PA6 PF8
TIM 14 PA7 PF9
  • PPx: Pins Pack 1 to 3, for 3 possible channel outputs on timer.

Notes on table above

  • Not all timers are available on all STM32F4xx devices
  • Not all timers works with same tick frequency
  • All timers have 16bit prescaler
  • TIM6 and TIM7 don’t have PWM feature, they are only basic timers
  • TIM2 and TIM5 are 32bit timers
  • TIM10, TIM11, TIM13 and TIM14 have only one PWM channel
  • Only 1 channel can be selected on 1 timer

Other notes

  • If you don’t know which frequency you can expect on your input, then set initialization function to 1, which means that you want to measure minimal frequency of 1Hz. If you want to go even lower, you can basically go to a value of
    • This can be very low value, but if you have then signal in 10kHz spectrum, your result can veery very fail from real. I suggest you that you set this value to 1 if you don’t know what you can expect, if you know, then set it to a little bit smaller value.
      • Example: if you expect signal of 1000Hz, then set value to 950 in initialization function or something like that
  • I suggest you to use 32-bit timer (TIM2, TIM5) to measure input PWM, you got better result and better accuracy
  • Expected frequency is just some kind of reference, how to set timer with prescaler, so you will be able to measure entire PWM period with one timer’s period value for valid result!

Default NVIC priority for all timers is set to 0x01. If you need to set another value, then use define in defines.h file:

Sub priority for timers is generated in a way that which timer you initialize first, this timer has higher sub priority.

Functions and enumerations


  • Example and results are based on STM32F4-Discovery board.
  • TIM4 makes PWM on pin PD12 with 3251Hz.
  • TIM2 and TIM3 are measuring timers
    • TIM2 is 32-bit, TIM3 is 16-bit.
  • Results in pictures below
    • First has capture timers set to 1000Hz expected frequency, second with 1Hz
      • TIM3 starts failing with result
TIM2 and TIM3 measuring results with 1Hz input frequency expection

TIM2 and TIM3 measured results with 1Hz input frequency expection

TIM2 and TIM3 measuring results with 1000Hz input frequency expection

TIM2 and TIM3 measured results with 1000Hz input frequency expection

Project available at my Github account, download library below.

TM STM32F4 PWM IN Library


Owner of this site. Also electronic enthusiasts, web developer, 3D printer fan, handball player and more. Big fan of STM32F4 devices. In anticipation of the new Discovery board for STM32F7 lines.

You may also like...

Read before commenting!

Before you make a new comment, make sure you agree with things listed below:

  • - Read post to make sure if it is already posted what you are asking for,
  • - Make sure you have the latest version of libraries used in your project,
  • - Make a clean and grammatically correct written message,
  • - Report as many details as possible, including what have you done so far,
  • - Do NOT post any code here. Use Pastebin,
  • - Do NOT post any error codes here. Use Pastebin,
  • - Specify STM32Fxxx family and used Discovery/EVAL/Nucleo or custom made board,
  • - Make sure your clock is set correct for PLL,
  • - If you are using my HAL drivers, please check this post how to start.
Comment will be deleted on breaking these rules without notification!
  • Ronak Patel

    Hey Majerle, I’m trying to initialize timer1 as my input signal and using timer 5 as my output signal. I’m getting an error with TIM1_IRQn. Is the input signal limited to only 2,3,4,5?

    • Hi, if I look into stars, I cant know what is your problem, so please tell me more 🙂

      • Ronak Patel

        Ok so, I’m generating a 5-10% duty cycle and 50Hz frequency from an RC transmitter. I’m trying to read the signal using a 16 bit timer instead of a 32 bit timer. I need to make 4 identically signals through the STM32F407 board to output to my electronic speed controllers. So the question is, will the 16bit timer be able to read such a low duty cycle and accurately read it? The error is stating that TIM1_IRQn has not been declared. I don’t run into this issue when I use Timer 2 and Timer 5. (I need to read 4 signals and create 4 output signals accordingly, currently doing 1 signal).

        • I think it could measure this.

          Well, TIM1_IRQn does not exists. You can use these for TIM1:

          TIM1_CC_IRQn <- this will be for you.

          • Ronak Patel

            Thank you. I got it too work with a input and output the PWM. Does generating 4 PWM signals using 1 timer create a problem when connecting the output to 4 motors?

          • Kostas Papadopulos

            Hello to both.
            Have you managed to read 4 channels successfully?
            If yes, could you Ronak share the project?
            I’ve currently lost second day without any success.
            I wanna feed the duty cycle of RC pwm singal into quadcopter controll system.

          • You need 2 channels to measure one PWM.
            One PWM can be measured with one timer.

          • Kostas Papadopulos

            I think it can be done with one channel too.
            The trick is to toggle the ICpolarity at every interrupt request is made.
            Take a look at Baseflight project .
            Also i think instead of toggling using BothEdge interrupt will be the same.

          • Ronak Patel

            Currently, reading 1 input and generating 4 output signals for my quadcopter. So I will keep you updated as I get further along.

  • Eerik Sweden

    Is there a way to handle frequency that goes below the MinExpectedFrequency? I would want to detect if an input PWM stops or is below MinExpectedFrequency.

    • Ok, if your minimal PWM frequency should be at least 1kHz, then you can set MinExpectedFrequency parameter to let’s say 10Hz.

      If result from PWM measure is less than 1kHz, you are below minimal.

  • Pingback: All STM32F4 libraries - STM32F4 Discovery()

  • Daluxolo

    Hi there,
    I’m having a bit of trouble working out the pros and cons of a 16bit vs 32bit timer for use in this mode. Could anyone perhaps share some insight?
    As I reason, 32bit will have the potential for greater resolution, but will be slower and vice versa with 16bit.
    Are these postulations correct?

    I’m going to use a similar setup to this to measure a square wave from an optical incremental encoder, and I’m trying to work out which timer to use.

    • timers have built-in support for increment encoders. Check examples for STD periph drivers and read datasheet about that. It’s very easy to configure.

      • Daluxolo

        Thanks for the advice. Could you share your thoughts on 16bit vs 32bit timers in this application?

        • Probably 16bit timer is enough, you dont have so many rotations i think.

          • Daluxolo

            Thanks for the advice, but whether it’s enough or not is not the point. I’m wondering about the theoretical implications, for educational purposes and with a view to optimization. Do you think a 16bit timer would be ‘faster’, but less accurate than 32bit?

          • Does not care here. What it does is timer speed.

  • kais

    i need to read pwm signal pulse width in ms from an RC receiver
    how can i proceed to get the pulse width knowing Duty cycle mesured and the frequency (50Hz)

  • stm beginnet

    Hi Tilen , Is it possible to measure an analog input signal with STM32F4 ?

    • Search for ADC (Analog to digital converter) on this site or others.

      • stm beginner

        Ya Tilen , thank you . Tilen I have one more question. I have tried your library above and tried measuring the PWM with various possible Timers. But the readings were incorrect for Timers 10,11 , 13 and 14. I used TIM1_UP_TIM10_IRQHandler , TIM1_TRG_COM_TIM11_IRQHandler , TIM8_UP_TIM13_IRQHandler and TIM8_TRG_COM_TIM14_IRQHandler respectively. Is there anything that I need to take care of for these Timers ?

  • Konstantinos Zarkadis

    Hello Tilen,

    I’m trying to measure the frequency of an incremental encoder and I thought it would be possible to do so by using your PWMIN method.. I took your code but I deleted the whole TIM4 configuration thing since I have my encoder output for that, and I also deleted your TIM2 ’cause as I can realize from your code you only need it to compare a 32bit timer (TIM2) to a 16bit (TIM3).

    I print the Frequency and DutyCycle value on my STM32F429 screen but the values are always “0”. Could the problem be that the frequency I want to measure is less than 1KHz?? I also changed the ‘1000’ value to ‘1’ in “TM_PWMIN_InitTimer” command but nothing changed.

  • wafa

    Variateur des signaux PWM:Le but de ce projet est et de varier le rapport cyclique de 4 signaux PWM en utilisant une interface graphique sur lcd de kit discovery stm32f429. Les périphériques à programmer seront: GPIO, TIM, LTCD et NVIC.

    svp chekoune najem 3awni fih ce projet .

  • stm beginner

    Hi Tilen,
    I have generated a PWM signal of 1MHz with Timer4 and using that as input PWM signal to measure at Tim2.
    I have enabled the clock for all Timers and these are my 4 lines of code:
    //Timer 4
    TM_PWM_InitTimer(TIM4, &PWM_Data, 1000000);
    TM_PWM_InitChannel(&PWM_Data, TM_PWM_Channel_1, TM_PWM_PinsPack_2);
    TM_PWM_SetChannelPercent(&PWM_Data, TM_PWM_Channel_1, 50);
    // Timer 2

    For frequencies till 100kHz the above code is working fine. But above 100kHz ,like 200kHz or for 1MHz , the above code crashes. Would be glad to know if you have come across this issue would like some information on it. Thank you so much for your code.

  • stm beginner

    Hi Tilen,

    Thank you so much for your code.
    I have downloaded the latest libraries to generate PWM on one Timer and measure the same on another Timer.
    I am using STM32F407VGT6.
    I have initialized the system clock at 168MHz and the buses are running at the appropriate frequencies.

    I am using TIM4 to generate a PWM signal . This signal is then measured at TIM2.

    I have used the main.c above to generate and then measure the signals.
    As long as I use the frequencies till 100KHz , the code works fine. For ex: I generate a 100KHz at TIM4 and measure the same at TIM2.
    I get correct results.

    I have generated frequencies as high as 1MHz and there occurred no problem in PWM Signal generation.
    However, if I measure 1MHz (or any generated frequency greater than 100KHz), with any of the Timers, the program crashes just at the point when PWMIN data has to be read from the Timer.

    Would like to know if have come across this Problem and how you could solve it.


  • Farhan Musthafa

    Library 48 link is not working for me. could you please check whether the link address is correct?

    • It works for me.

      • Farhan Musthafa

        yes. not it is fine. I am sorry something was wrong with my server.

        I would like to learn about PWM code for stm32f4. could you please let me know if there is any link to view the sample code.

        I need to draw

        PWM input and output signal for DC motor control.


        • You can use this library to measure PWM input values.
          Then, you can check my PWM tutorial how to make a PWM.

          According to your settings, you set timer period/prescaler (for PWM frequency) and channel output for duty cycle.

  • Gary

    Could you please explain something about this post with respect to your table above.

    In the example there, he is using TIM2 and AF pins PD3, PD4, PD6, & PD7
    According to your chart, these are not listed for TIM2. Is it because you don’t list all possible connections?

  • Leiter

    What is the minimal required voltage of the input PWM signal (the one to be measured)?
    Additionally, is it possible to set the output PWM signal to 5V instead of 3.3V? (Using your libraries)

    • Voltage is defined by pin input voltage detection, around 2 volts or more probably. For detail, check dedicated datasheet.

      No, you cannot have 5V pwm from 3.3V supply voltage.

  • Lal Bosco

    I have configured TIM4_CH3 (PD14) is PWM output and TIM4_CH4 (PD15) is PWM input. PD14 and PD15 are connected (feedback).
    Would help anyone here, how can i read the frequency from PD15 (TIM4_CH4).

    • Lal Bosco

      Any update.

      • Use single timer for input reading only first.

        • Lal Bosco

          Thanks for the update,
          Which means that we can not use the single timer for to PWM input and output.

          • Lal Bosco

            By using different timer, am able to read it.
            But our hardware implemented such a way that set the PWM output on TIM4_CH3 and PWM input (Read) from TIM4_CH4.
            I have been struggling from last two weeks, I am unable to read read PWM input frequency from TIM4_CH4, when I set the PWM output on TIM4_CH3.

          • It is never good idea to do the hardware before teted software. That’s why nucleo/discovery boards are for.

  • issa93

    I want to do a project that generates three PWM signals, read the frequencies of three PWM signals and send data through USART, can someone help me please

  • Joaquim Porte Jimenez


    I’m tring to reset a LED register with a timer (TIM4) interrupt, but TIM4_IRQHandler(void); fucntion it’s never launch, the code that i’m using is: (mi board es STM32f429I-DISC1).

    Some one can help me please?

    Thank you very much for your attention
    #include “stm32f4xx.h”

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    void INTTIM_Config(void)
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    TIM_TimeBaseStructure.TIM_Period = 10 – 1;
    TIM_TimeBaseStructure.TIM_Prescaler =84 – 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
    TIM_ITConfig(TIM4, TIM_FLAG_Update, ENABLE);
    TIM_Cmd(TIM4, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_SetPriority(TIM4_IRQn, NVIC_EncodePriority(4,15,0));



    int main(void) {

    GPIO_InitTypeDef GPIO_InitDef;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);

    GPIO_InitDef.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
    //Initialize pins
    GPIO_Init(GPIOG, &GPIO_InitDef);
    GPIO_SetBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);


    while (1) {



    void TIM4_IRQHandler(void)
    GPIO_ResetBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);

    if (TIM_GetITStatus(TIM4, TIM_FLAG_Update) != RESET)
    TIM_ClearFlag(TIM4, TIM_FLAG_Update);
    GPIO_ResetBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);

  • Arvind


    The PWMIN library works with Timer 3 Channel 2 PA7 but DOES NOT work with Timer 14 Channel 1 PA7.

    I am testing with STM32F446 on a custom board. I get the PWM externally from a waveform generator. System clock is at 168MHz. I have set the expected frequency to 10kHz and I am measuring a 30kHz signal.

    With timer 3, I consistently get a frequency of 30.042kHz and 50% duty.

    But with timer 14, the interrupts are generated ( in TIM8_TRG_COM_TIM14_IRQHandler ) but the capture frequency keeps randomly changing anywhere between 1kHz and 104kHz ( mostly it is under 10kHz).The duty cycle is always 0.

    Is there any configuration that is missing or is it an issue with timer 14?


    • Please verify if timer14 exists in your device.

      • Arvind

        Yes. It does. I also checked the reference manual for STM32F429 (RM0090) and Page 653 says that for General Purpose timers 9 to 14, PWM Input mode is only for Timers 9 and 12.

    • Arvind

      Hi Tilen,
      I am now convinced that PWM Input mode does not work with Timers 10, 11, 13 and 14. Please look into this and if you agree, kindly change the table above.