STM32F4 PWM tutorial with TIMERs

In this tutorial, I will show you, how to implement PWM outputs on STM32F4xx devices. This is for a lot of people pretty hard work, but believe me, it’s quite quick and easy. I will go step by step on how to make a PWM output on specific timer.

Update: I made a library for PWM, available here.



STM32F4 timers

They have up to 14 timers inside. Table below shows their description. You have to know, that let’s say F401 doesn’t have so many timers like F407 or F429. You have to always check manual for it’s chip if it has available timer.

Timer Type Resolution Prescaler Channels MAX INTERFACE CLOCK MAX TIMER CLOCK* APB
TIM1, TIM8 Advanced 16bit 16bit 4 SysClk/2 SysClk 2
TIM2, TIM5 General purpose 32bit 16bit 4 SysClk/4 SysClk, SysClk/2 1
TIM3, TIM4 General purpose 16bit 16bit 4 SysClk/4 SysClk, SysClk/2 1
TIM9 General purpose 16bit 16bit 2 SysClk/2 SysClk 2
TIM10, TIM11 General purpose 16bit 16bit 1 SysClk/2 SysClk 2
TIM12 General purpose 16bit 16bit 2 SysClk/4 SysClk, SysClk/2 1
TIM13, TIM14 General purpose 16bit 16bit 1 SysClk/4 SysClk, SysClk/2 1
TIM6, TIM7 Basic 16bit 16bit 0 SysClk/4 SysClk, SysClk/2 1

* Clock speed depends on which STM32F4xx device is used

Timer initialization

Before we can use PWM, we have to initialize timer. Because STM32F429 Discovery board does not have leds on PWM pins, I will use STM32F4 Discovery with 168MHz core clock for this example. Leds are connected to pins PD12 to PD15, what give us timer TIM4 with Output channels 1 to 4.

Initialize TIM4

Here we will initialize timer, for our PWM frequency. We have to set prescaler and period for how fast will it count and how much it will count for specific PWM frequency.

Initialize PWM 4 channels

Set PWM output channels to PWM.

Initialize outputs

Initialize and connect pins for specific TIM. Notice, that GPIOs have AF (Alternating Function) mode, because timer has full control on them.

Example

That’s it. You have not set your timer to work in PWM mode.

Hope it helps.

tilz0R

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!
  • jun

    hello ! it’s very helpful to me!
    i coped your code. and test .
    why frequency 3.2khz ?
    keil uvision5, stm32f407vg
    *—————————————————————————–
    * System Clock source | PLL (HSE)
    *—————————————————————————–
    * SYSCLK(Hz) | 168000000
    *—————————————————————————–
    * HCLK(Hz) | 168000000
    *—————————————————————————–
    * AHB Prescaler | 1
    *—————————————————————————–
    * APB1 Prescaler | 4
    *—————————————————————————–
    * APB2 Prescaler | 2
    *—————————————————————————–
    * HSE Frequency(Hz) | 25000000
    *—————————————————————————–
    * PLL_M | 25
    *—————————————————————————–
    * PLL_N | 336
    *—————————————————————————–
    * PLL_P | 2
    *—————————————————————————–
    * PLL_Q | 7
    *—————————————————————————–
    * PLLI2S_N | NA
    *—————————————————————————–
    * PLLI2S_R | NA
    *—————————————————————————–
    thank you

  • phivu

    HI Tilens, do you have experience for setting PWM for stm32f401 nucleo board. I donot know why when I set with those values, it shows me wrong frequency from oscilloscope. I setup by hands like this until i got 100hz with these parameters. Please tell me what is the true value and equation for stm32f401 nucleo board

    #define APB1_FREQ 84000000 // Clock driving TIM3 pll clock = APBx * 2

    #define CNT_FREQ 2100000

    #define PWM_FREQ 500 // PWM frequency 100 Hz

    #define PWM_DC_CH1 50 // Channel 1 duty cycle

    #define PWM_DC_CH2 75 // Channel 2 duty cycle

    #define TIM_PULSE_CH1 (((PWM_DC_CH1)*(TIM_PERIOD_PWM + 1)/100)-1) // Output Compare 1 reg value

    #define TIM_PULSE_CH2 (((PWM_DC_CH2)*(TIM_PERIOD_PWM + 1)/100)-1) // Output Compare 2 reg value

    #define TIM_PERIOD_PWM (((CNT_FREQ) / (PWM_FREQ))-1) // Autoreload reg value

    #define TIM_PRESCALER_PWM (((APB1_FREQ) / (CNT_FREQ))-1) // APB1 prescaler 21MHz

    • Apb1 in f401 is 42mhz. Try with that.

      • phivu

        when I set up as you proposed osscilloscope shows me the value of 38.3hz which is 25ms. If I said as I presented before, it shows me the true value of 100hz

        • But why do you have define PWM_FREQ set to 500 and comment set to 100?

          • phivu

            oh when I siad the value of 500 and checked on oscilloscope, it shows me 100 Hz. It’s really strange. if I set up 100, it will give me 25ms which is 33.83hz

          • Make sure, that your PLL settings are correct.
            Nucleo without crystal works with 16MHz internal clock.

            Show me full project please, so I can help you more.

          • phivu

            Hi my friend, I found one strange thing for my micro. If i setup for timer interrupt with the normal parameters, it is ok when i see on oscilloscope. But if I use pwm function, the period seems like the half of old frequency. Given below is my code . By the way, I would like to create duty cylce by RNC with the sample time of 100 ms and the range from 0 to 100. How can I do like that?
            Thanks.
            http://www.mediafire.com/download/n66kjeqjjwc6jl7/STM32F4xx_StdPeriph_Templates.rar

          • Your PLL settings are not correct and your MCU does not work at maximum speed.

          • phivu

            So can you help me to fix it?
            Best Regards,
            Phi Vu.

          • First, add 8MHz external crystal and 2 capacitors 22p to the nucleo board.

          • phivu

            oh ok i will consider. And do you know how to generate random duty cycle from RNG. i used your code and some guys but i do not know why my program stuck at RNG setup.

          • You are using my RNG lib and it is not working?
            Well, if you don’t, then you have to to enable clock for RNG and enable RNG peripheral and it is working.

  • Pingback: Fix Uvision 4 Error 65 Windows XP, Vista, 7, 8 [Solved]()

  • Sag Nie Bels

    In CoIDE 1.7.7 there is some trouble with the extern declaration in “tm_stm32f4_timer_properties.h”

    Source: tm_stm32fpwm.rar from “Update: I made a library for PWM, available here.”

    132: extern TM_TIMER_PROPERTIES_Result_t TM_TIMER_PROPERTIES_GenerateDataForWorkingFrequency(TM_TIMER_PROPERTIES_t* Timer_Data, double frequency);

    There was “double frequency” in parameters, the definition of the function has uint32_t frequency. I changed it to uint32_t and the compiler errors vanished.

  • Aung

    Dear Tilen,

    Thanks for your work.

    I was running the PWM example on stm32f407vgt6 using KeiluVision5 and got the following error.

    .TargetsSTM32F4_Discoveryproject.axf: Error: L6218E: Undefined symbol TIM_Cmd (referred from main.o).

    Please kindly help me to solve that problem.
    Thank you for your time.

    Aung

    • Hi, you are missing stm32f4xx_tim.h/c to add to project.

  • Syrer

    How sweet 🙂
    I suggest to use real formula’s for the calculations instead of “plain” values, that simplifies the testing, e.g.:
    uint32_t pwm_frequency=10000;
    uint32_t timer_frequency=SystemCoreClock;
    TIM_BaseStruct.TIM_Period = (timer_frequency/pwm_frequency) – 1;
    TIM_OCStruct.TIM_Pulse = (((TIM_BaseStruct.TIM_Period + 1) * 75 ) / 100) – 1 ;
    As usual, nice work and thanx 🙂

  • Gary

    Hi Tilen:

    I am having a huge amount of trouble to get a couple of pins to toggle in PWM mode. It works, but there’s a problem with the pin staying high. Here’s what I am trying to do, it’s quite simple, so I don’t see why it is so much problem. I think I’ll start banging my head on the wall soon 8~(

    This is low frequency stuff, the timebase calculation is good, and I can generate frequencies +/- 100mHz. Both output pins *must* start at 0 (low), and return to 0 (low).
    The 2 outputs must be PWM, call them Output1 and Output2. They will be exactly the same frequency, and exactly the same pulse width. The only difference is this: The start edge of Output 2 must be delayed from Output1 by an interval of timerPeriod / 2.

    Here is my code, 2 functions. The first one is the GPIO setup, the other is PWM configuration.

    void GPIO_Configuration(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;

    /* GPIOD Configuration: Use TIM4 to to PD12 (also LED on board) */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    /* GPIOC Configuration: TIM3 CH1 (PC6) */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    /* Connect TIM3 pins to AF2 */
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM3);

    /* Connect TIM4 pins to AF2 */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);
    }

    void PWM_TIMER_Configuration(float32_t frequency, float32_t dutyCycle)
    {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    uint16_t Prescaler, Period;

    // 20 KHz timebase, assumes APB1 H/4 TIMCLK4 H/2
    Prescaler = ((SystemCoreClock / 2) / 20000);
    Period = (uint16_t)( TIMER_BASE / frequency );

    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period = Period – 1;
    TIM_TimeBaseStructure.TIM_Prescaler = Prescaler – 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

    //set timer 3 & 4 to same frequency
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

    //assign variable
    uint32_t timerPeriod = TIM_TimeBaseStructure.TIM_Period;

    /* Output Compare PWM1 Mode configuration: Channel 1 */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

    //create pulse width “onTIme” for both channels
    uint16_t onTime = (uint16_t) (timerPeriod * txData[frqValue].dutyCycle);

    TIM_OCInitStructure.TIM_Pulse = onTime;
    TIM_OC1Init(TIM3, &TIM_OCInitStructure);
    TIM_OC1Init(TIM4, &TIM_OCInitStructure);

    TIM_Cmd(TIM3, ENABLE);

    //set timer 4 immediately to timerPeriod / 2 = 180 degrees shift
    TIM4->CNT = TIM3->CNT + (timerPeriod /2 );
    TIM_Cmd(TIM4, ENABLE);

    //Set up TIM3 interrrupt
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

    }

    See the attached image showing what the output looks like. The yellow trace is TIM3, the green is TIM4. Notice how TIM4 wants to stay high, this is exactly what I do not want. Ideally the TIM3 should look just like TIM4, with a clean transition LOW to high at start and the same at the end. TIM4 is delayed by the correct amount, but the starting relationship isn’t quite right, the trace looks goofy, and I’m not sure if it’s because TIM3 starts at HIGH.

    The idea is to monitor in an interrupt routine, let it run a specific amount of cycles, then stop it by doing this:
    TIM_Cmd(TIM4, DISABLE);
    TIM_Cmd(TIM4, DISABLE);

    I have tried everything, including using a physical pull up resistor, forcing the pin low.
    So what am I doing wrong? The manual isn’t telling me anything except how to set registers. I’ve even tried every direct register setting instead of the TIM_Cmd function, made no difference.

    Any help….advice…would be really appreciated.

    Thanks Tilen…

    • I don’t entirely what you wanna do.
      I also don’t understand this:
      TIM4->CNT = TIM3->CNT + (timerPeriod /2 );

      You call this after initialization. After first initialization, TIMx->CNT is set to 0 so it has no meaning in your case. Just thinking like that.

      • Gary

        Tilen,
        OK, thanks for that information. I added that change to do the assignment before initializing. I also changed my interrupt handler, and it’s now genrating the pulse train OK.

        Please keep up the good work on this site, it is very useful and makes understanding the STm32F4 chip easier.

  • Dracog71

    hi Tilens!, is it possible to handle the PWM with an incremental encoder by hardware? i mean some kind of capture/compare to stops PWM when a register is equal to another register?

    any ideas?, i’m stuck, i was trying to make this work http://www.zoomworks.org/fpv/antenna_tracker/index.html

    but when I configure Encoder CH1 CH2 and PWM CH3 to one Timer (TIM4) , encoder works perfectly but PWM doesn’t works !!!!

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    TIM_OCInitTypeDef TIM_OCInitStructure;

    TIM_ICInitTypeDef TIM_ICInitStructure;

    GPIO_InitTypeDef GPIO_InitStructure;

    void encoderInit (void)

    {

    RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOD, ENABLE);

    GPIO_StructInit (&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN ;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 ;

    GPIO_Init (GPIOD, &GPIO_InitStructure);

    GPIO_PinAFConfig (GPIOD, GPIO_Pin_12 , GPIO_AF_TIM4);

    GPIO_PinAFConfig (GPIOD, GPIO_Pin_13 , GPIO_AF_TIM4);

    RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM4, ENABLE);

    TIM_EncoderInterfaceConfig (TIM4, TIM_EncoderMode_TI12,

    TIM_ICPolarity_Rising,

    TIM_ICPolarity_Rising);

    TIM_SetAutoreload (TIM4, 0xffff);

    TIM_Cmd (TIM4, ENABLE);

    encodersReset();

    }

    void encodersReset (void)

    {

    __disable_irq();

    TIM_SetCounter (ENCR_TIMER, 0);

    __enable_irq();

    }

    void Sytem_Init(void)

    {

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;

    GPIO_Init(GPIOD, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_TIM4);

    TIM_TimeBaseStructure.TIM_Prescaler = 0;

    TIM_TimeBaseStructure.TIM_Period = 4199;

    TIM_TimeBaseStructure.TIM_ClockDivision = 0;

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

    /* CH1 */

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OCInitStructure.TIM_Pulse = 0;

    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;

    TIM_OC3Init(TIM4, &TIM_OCInitStructure);

    TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);

    /* TIM1 enable counter */

    TIM_Cmd(TIM4, ENABLE);

    TIM_CtrlPWMOutputs(TIM4, ENABLE);

    }

    Is there anything i’ve missed ?? any help will be thankfull!!

    • I think you will need to use somesort of interrupt when you receive new pulse on encoder.
      Then with some if statements you can do pwm stop.
      With hardware i think it is not possible.

      • Dracog71

        I will try with it, and if i got right, i’ll post some code for others to share the solveto this problem, anyway thnks!,

        For anyone who knows about “basic”, here its the solve,

        https://github.com/kwikius/quantracker/tree/master/ground/tracker/v1

        the problem its that some statements in Basic are different in “C” , but anyway, there’s the solution to a PWM control by Encoder comparing “TIMx->CNT”

  • Gary

    Tilens,

    Do you have an example posted on how to use 32 bit timer (TIM2, TIM5) to do a capture/compare for a very low frequency external signal?

    Thanks!

    • I have only PWM input/output libraries right now.

  • Pete

    Hi, awesome article!

    I have tried running your above code but i get the following error when trying to compile;

    Build target ‘Target 1’
    compiling main.c…
    linking…
    .Objectstest.axf: Error: L6218E: Undefined symbol RCC_APB1PeriphClockCmd (referred from main.o).
    .Objectstest.axf: Error: L6218E: Undefined symbol TIM_Cmd (referred from main.o).
    .Objectstest.axf: Error: L6218E: Undefined symbol TIM_OC1Init (referred from main.o).
    .Objectstest.axf: Error: L6218E: Undefined symbol TIM_OC1PreloadConfig (referred from main.o).
    .Objectstest.axf: Error: L6218E: Undefined symbol TIM_OC2Init (referred from main.o).
    .Objectstest.axf: Error: L6218E: Undefined symbol TIM_OC2PreloadConfig (referred from main.o).
    .Objectstest.axf: Error: L6218E: Undefined symbol TIM_OC3Init (referred from main.o).
    .Objectstest.axf: Error: L6218E: Undefined symbol TIM_OC3PreloadConfig (referred from main.o).
    .Objectstest.axf: Error: L6218E: Undefined symbol TIM_OC4Init (referred from main.o).
    .Objectstest.axf: Error: L6218E: Undefined symbol TIM_OC4PreloadConfig (referred from main.o).
    .Objectstest.axf: Error: L6218E: Undefined symbol TIM_TimeBaseInit (referred from main.o).
    Not enough information to list image symbols.
    Finished: 1 information, 0 warning and 11 error messages.
    “.Objectstest.axf” – 11 Error(s), 0 Warning(s).
    Target not created.

    I have been trying to figure it out all day but no success – sorry im not very good with C at the moment but am trying to learn. this is the exact code i am using

    #include “defines.h” //files that have been written defined this way – tells to get from local dircetory ie where prject is saved
    #include “stm32f4xx.h”
    #include “stm32f4xx_rcc.h”
    #include “stm32f4xx_gpio.h”
    #include “stm32f4xx_tim.h”
    #include //files that come with compiler defined this way – tells to get from system libaries
    #include
    #include

    /*
    #define APB1_FREQ 42000000 // Clock driving TIM3 pll clock = APBx * 2

    #define CNT_FREQ 2100000

    #define PWM_FREQ 500 // PWM frequency 100 Hz

    #define PWM_DC_CH1 50 // Channel 1 duty cycle

    #define PWM_DC_CH2 75 // Channel 2 duty cycle

    #define TIM_PULSE_CH1 (((PWM_DC_CH1)*(TIM_PERIOD_PWM + 1)/100)-1) // Output Compare 1 reg value

    #define TIM_PULSE_CH2 (((PWM_DC_CH2)*(TIM_PERIOD_PWM + 1)/100)-1) // Output Compare 2 reg value

    #define TIM_PERIOD_PWM (((CNT_FREQ) / (PWM_FREQ))-1) // Autoreload reg value

    #define TIM_PRESCALER_PWM (((APB1_FREQ) / (CNT_FREQ))-1) // APB1 prescaler 21MHz
    */

    //Function declarations
    //*******************************
    void TM_TIMER_Init(void);
    void TM_PWM_Init(void);
    //*******************************

    int main(void) {
    /* Initialize system */
    SystemInit();
    /* Init timer */
    TM_TIMER_Init();
    /* Init PWM */
    TM_PWM_Init();

    while (1) {

    }
    }

    void TM_TIMER_Init(void) {

    TIM_TimeBaseInitTypeDef TIM_BaseStruct;

    /* Enable clock for TIM4 */

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //a symbol is a function that is defined by extern ie not defined in the same translation unit
    /*
    TIM4 is connected to APB1 bus, which has on F407 device 42MHz clock
    But, timer has internal PLL, which double this frequency for timer, up to 84MHz
    Remember: Not each timer is connected to APB1, there are also timers connected
    on APB2, which works at 84MHz by default, and internal PLL increase
    this to up to 168MHz

    Set timer prescaller
    Timer count frequency is set with

    timer_tick_frequency = Timer_default_frequency / (prescaller_set + 1)

    In our case, we want a max frequency for timer, so we set prescaller to 0
    And our timer will have tick frequency

    timer_tick_frequency = 84000000 / (0 + 1) = 84000000
    */
    TIM_BaseStruct.TIM_Prescaler = 0;
    /* Count up */
    TIM_BaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
    /*
    Set timer period when it have reset
    First you have to know max value for timer
    In our case it is 16bit = 65535
    To get your frequency for PWM, equation is simple

    PWM_frequency = timer_tick_frequency / (TIM_Period + 1)

    If you know your PWM frequency you want to have timer period set correct

    TIM_Period = timer_tick_frequency / PWM_frequency – 1

    In our case, for 10Khz PWM_frequency, set Period to

    TIM_Period = 84000000 / 10000 – 1 = 8399

    If you get TIM_Period larger than max timer value (in our case 65535),
    you have to choose larger prescaler and slow down timer tick frequency
    */
    TIM_BaseStruct.TIM_Period = 8399; /* 10kHz PWM */
    TIM_BaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_BaseStruct.TIM_RepetitionCounter = 0;
    /* Initialize TIM4 */
    TIM_TimeBaseInit(TIM4, &TIM_BaseStruct);
    /* Start count on TIM4 */
    TIM_Cmd(TIM4, ENABLE);
    }

    void TM_PWM_Init(void) {
    TIM_OCInitTypeDef TIM_OCStruct;

    /* Common settings */

    /* PWM mode 2 = Clear on compare match */
    /* PWM mode 1 = Set on compare match */
    TIM_OCStruct.TIM_OCMode = TIM_OCMode_PWM2;
    TIM_OCStruct.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCStruct.TIM_OCPolarity = TIM_OCPolarity_Low;

    /*
    To get proper duty cycle, you have simple equation

    pulse_length = ((TIM_Period + 1) * DutyCycle) / 100 – 1

    where DutyCycle is in percent, between 0 and 100%

    25% duty cycle: pulse_length = ((8399 + 1) * 25) / 100 – 1 = 2099
    50% duty cycle: pulse_length = ((8399 + 1) * 50) / 100 – 1 = 4199
    75% duty cycle: pulse_length = ((8399 + 1) * 75) / 100 – 1 = 6299
    100% duty cycle: pulse_length = ((8399 + 1) * 100) / 100 – 1 = 8399

    Remember: if pulse_length is larger than TIM_Period, you will have output HIGH all the time
    */
    TIM_OCStruct.TIM_Pulse = 2099; /* 25% duty cycle */
    TIM_OC1Init(TIM4, &TIM_OCStruct);
    TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);

    TIM_OCStruct.TIM_Pulse = 4199; /* 50% duty cycle */
    TIM_OC2Init(TIM4, &TIM_OCStruct);
    TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);

    TIM_OCStruct.TIM_Pulse = 6299; /* 75% duty cycle */
    TIM_OC3Init(TIM4, &TIM_OCStruct);
    TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);

    TIM_OCStruct.TIM_Pulse = 8399; /* 100% duty cycle */
    TIM_OC4Init(TIM4, &TIM_OCStruct);
    TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);
    }

    Any help will be greatly appreciated!

    Kind Regards – Pete

    • Add standard peripheral drivers to project 🙂

      • Pete

        do you mean these;
        #include “stm32f4xx_rcc.h”
        #include “stm32f4xx_gpio.h”
        #include “stm32f4xx_tim.h”

        I have included them in the project – I thought… but maybe incorrectly…

        Thanks for the quick reply! I’ll keep fiddling around with the standard peripheral drivers then 🙂

        • Pete

          Thanks Majerle 🙂 Finally got it working. you were right. I had included the .h files but not the stm32f4xx_tim.c etc files. I then needed to add the stm32f4xx_conf.h file – make some adjustments in the header file and include this header file in all the .c files. Thanks again, Pete

  • Hasnat

    Hi Tilens! very nice work!
    Plz tell me from where i can add the header file stm324xx_tim.h

    • Download standard peripheral drivers.
      If you first time see this, then start with gpio tutorial!

      • Hasnat

        yes , i m First time seeing this and using STM controller . Plz can you guide me properly . Thanks in advance

      • Hasnat

        I m using Keil 4.14

  • Onur Akgün

    Hi Majerle,

    I need to use Timer without PWM. No matter which timer I use, it doesn’t work. Nothing happens.

    void TM_TIMER_Init(void) {
    TIM_TimeBaseInitTypeDef TIM_BaseStruct;
    NVIC_InitTypeDef NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    TIM_BaseStruct.TIM_Prescaler = 8399;
    TIM_BaseStruct.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_BaseStruct.TIM_Period = 999; /* 10 Hz */
    TIM_BaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_BaseStruct.TIM_RepetitionCounter = 0;

    TIM_Cmd(TIM4, ENABLE);
    }

    void TIM4_IRQHandler(void)
    {
    TIM4->SR=0;
    TM_DISCO_LedToggle(LED_GREEN);
    }

    int main (void) {

    SystemInit();
    TM_TIMER_Init();
    while (1) {
    }
    }

    • Before you start timer, add this line:

      TIM_ITConfig(TIM4, TIM_IT_Update);

      And you didn’t call TIM_TimeBaseInit() after your settings.

      • Onur Akgün

        I added
        TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
        before
        TIM_Cmd(TIM4, ENABLE);

        but nothing changes

        • I really don’t like if people don’t listen.

          After your settings, add TIM_TimeBaseInit() function with proper parameter!

          • Onur Akgün

            Sorry dude,

            I saw your message before your edit

            I added this one below after timer settings
            TIM_TimeBaseInit(TIM4, &TIM_BaseStruct);

            Nothing changes

          • Then you should test first.

            This works!
            http://pastebin.com/Vh9HvpKv

            PS: Don’t forget to init LEDS first using TM_DISCO_LedInit();

          • Onur Akgün

            Thanks dude

  • Kevin

    “But, timer has internal PLL, which double this frequency for timer, up to 84MHz”

    Can you explain this statement in more detail? I am new to embedded systems and the concept of a PLL. Is this an internal default or some kind of define you have set externally? I cannot find any resources which shows timer has its own PLL. In which system file is this set? Is it normal for the Timers to have twice the clock of the bus it’s located?

    Thanks!! -Confused student

  • Hai Anh Le

    hi Tilens!
    I’m having trouble with PWM using timer in stm32f4 discovery….can you help me with it…?

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

    PINinit.GPIO_Mode = GPIO_Mode_AF;
    PINinit.GPIO_Pin = GPIO_Pin_12;
    PINinit.GPIO_Speed = GPIO_Speed_100MHz;
    PINinit.GPIO_OType = GPIO_OType_PP;
    PINinit.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(GPIOD,&PINinit);

    GPIO_PinAFConfig(GPIOD,GPIO_PinSource12,GPIO_AF_TIM2);

    //RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    TIMinit.TIM_Prescaler = 0;
    TIMinit.TIM_CounterMode = TIM_CounterMode_Up;
    TIMinit.TIM_Period = 8399; //10khz
    TIMinit.TIM_ClockDivision = 0;
    TIMinit.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &TIMinit);

    TIMOCinit.TIM_OCMode = TIM_OCMode_PWM1;
    TIMOCinit.TIM_OCPolarity = TIM_OCPolarity_High;
    TIMOCinit.TIM_OutputState = TIM_OutputState_Enable;
    TIMOCinit.TIM_Pulse = 4199;

    TIM_OC1Init(TIM2, &TIMOCinit);
    TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
    TIM_ARRPreloadConfig(TIM2, ENABLE);
    TIM_Cmd(TIM2, ENABLE);

    i think i config it correctly but the led didn’t blink….

    • is TIM2 Channel1 connected to PD12?
      As far I know, TIM4 CH1 is connected there.

      • Hai Anh Le

        So I have to change to TIM4 CH1 to get it work??? And how can I know what channel connect to what pin ??

        • My example above works for PD12 for sure.

          To get all available pins for timers, check datasheet.

          • Hai Anh Le

            Oke let me change it to TIM4….thanks you for your time

  • Anton Khrapov

    Hi Majerle,

    First, let me tell you, your tutorials and libraries are AWESOME!

    I just recently got my 429-disco board and got a nice start thanks to you!

    I would like to contribute a bit to those who wants to dim their built-in LEDs in PWM-line manner on this board. I hope you don’t mind much 🙂

    This is an timer-interrupt-driven example and it works on my board however I don’t know if it will do anything else but dim LEDs:

    This file handles Timer interrupt:

    This is my main.c:

  • seprac

    HI. The details here are quite useful…I thank you very much for them.

    I have just one doubt. What is the significance of polarity in the above code? Also, there are two possibilities for same channel (CH1 and CHN1). What is the difference between them?

    • Polarity “feature” is just to select when pin is low and when high.
      In one mode, pin is high when timer starts at zero and goes low when compare value matches and is low till timer is zero again
      in second mode is first low, when compare is matched it goes high and is high till timer is zero again.

      To be honest, I have no idea, but probably it allows you to use 2 pins at the same time on one timer channel with inverted polarity. I’ve never checked this feature.

      • seprac

        Ok Cool…Thanks a lot…Then if I understood it correct, PWM Mode 1 with Polarity High will do the same function as PWM Mode 2 with polarity low…Right??

  • Mohammad Kamel

    hi Tilens!
    i have a question how can i use pwm for makin music . i emplement your code that was fantastic but now i want to make music with this pwm and i dont khow how to do this
    thank you alot

    • Fixed PWM frequency, duty cycle should be changed on every music sample, for example 44.1kHz. Use timer for interrupts or DMA for memory transfer from your music array.

  • h.mehrabian

    how can we change shape of a carrier?
    i.e. instead of tooth-wave shape, i want to have a triangle shape carrier.

    • If MCU has DAC, you can use this.

      • h.mehrabian

        No, u don’t get it. I mean, in PWM mode, we have a carrier which is compared with the reference signal.(and carrier have different shape wave) This reference signal also controls the duty cycle.

        • You can do different shape than signal high or low!

  • Pingback: Programming an ARM-processor (II) | erossel()

  • Makinde

    Thanks Tilens!
    Im a newbie in STM world. im using STM32F407VG. i tried runing the example code in coo cox… it compiled but the LEDs are not lighting up… i guess the code is for keil u vision5 but pls how can i use it on coo cox??
    Thanks

    • Code is code, C is C. Are you using f4-discovery board? Should work.

      • Makinde

        yes im using the f4 discovery

      • Makinde

        Thanks it worked

  • Mohammad Kamel

    hello i want to make 400 HZ frequency pwm but because of TIM_Prescaler and its 0 value i cant what this paramer value must be to make 400 HZ pwm thanks alot

  • Makinde

    hello Tilens, I will like to control the duty cycle of a PWM from USART command i stitched up some codes from this PWM tutorial and USART. but the code returned an exit status pls what is wrong with the code.

    #include “defines.h”
    #include “stm32f4xx.h”
    #include “stm32f4xx_rcc.h”
    #include “stm32f4xx_gpio.h”
    #include “stm32f4xx_tim.h”
    #include
    #include
    #include “stm32f4_discovery.h”
    #include “TecsploitUtils.h”

    #define BUFFER_SIZE 16

    volatile char received_buffer[BUFFER_SIZE+1];

    static uint8_t DataReceivedCounter = 0; //tracks the number of characters received so far, reset after each command

    //function prototypes
    void USARTCommandReceived(char * command);
    void ClearCommand();
    void Delay(int nCount);
    void ConfigureUsart(int baudrate);
    void TM_LEDS_Init(void);
    void TM_TIMER_Init(void);
    void TM_PWM_Init(int timepulse);

    //Configures the USART using pin B6 as TX and B7 as RX and the passed in baudrate
    void ConfigureUsart(int baudrate){
    //structures used configure the hardware
    GPIO_InitTypeDef GPIO_InitStruct;
    USART_InitTypeDef USART_InitStruct;
    NVIC_InitTypeDef NVIC_InitStructure;

    //enable the clocks for the GPIOB and the USART
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    //Initialise pins GPIOB 6 and GPIOB 7
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //we are setting the pin to be alternative function
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    //Connect the TX and RX pins to their alternate function pins
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1); //
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);

    //configure USART
    USART_InitStruct.USART_BaudRate = baudrate;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //enable send and receive (Tx and Rx)
    USART_Init(USART1, &USART_InitStruct);

    //Enable the interupt
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // finally this enables the complete USART1 peripheral
    USART_Cmd(USART1, ENABLE);
    }

    //writes out a string to the passed in usart. The string is passed as a pointer
    void SendData(USART_TypeDef* USARTx, volatile char *s){

    while(*s){
    // wait until data register is empty
    while( !(USARTx->SR & 0x00000040) );
    USART_SendData(USARTx, *s);
    *s++;
    }
    }

    void TM_LEDS_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct;

    /* Clock for GPIOD */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

    /* Alternating functions for pins */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_TIM4);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_TIM4);

    /* Set pins */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(GPIOD, &GPIO_InitStruct);
    }

    void TM_TIMER_Init(void) {
    TIM_TimeBaseInitTypeDef TIM_BaseStruct;

    /* Enable clock for TIM4 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    /*
    TIM4 is connected to APB1 bus, which has on F407 device 42MHz clock
    But, timer has internal PLL, which double this frequency for timer, up to 84MHz
    Remember: Not each timer is connected to APB1, there are also timers connected
    on APB2, which works at 84MHz by default, and internal PLL increase
    this to up to 168MHz

    Set timer prescaller
    Timer count frequency is set with

    timer_tick_frequency = Timer_default_frequency / (prescaller_set + 1)

    In our case, we want a max frequency for timer, so we set prescaller to 0
    And our timer will have tick frequency

    timer_tick_frequency = 84000000 / (0 + 1) = 84000000
    */
    TIM_BaseStruct.TIM_Prescaler = 0;
    /* Count up */
    TIM_BaseStruct.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_BaseStruct.TIM_Period = 8399; /* set to 25kHz PWM for motor */
    TIM_BaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_BaseStruct.TIM_RepetitionCounter = 0;
    /* Initialize TIM4 */
    TIM_TimeBaseInit(TIM4, &TIM_BaseStruct);
    /* Start count on TIM4 */
    TIM_Cmd(TIM4, ENABLE);
    }

    void TM_PWM_Init(int timepulse)
    {

    TIM_OCInitTypeDef TIM_OCStruct;

    TIM_OCStruct.TIM_OCMode = TIM_OCMode_PWM2;
    TIM_OCStruct.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCStruct.TIM_OCPolarity = TIM_OCPolarity_Low;

    TIM_OCStruct.TIM_Pulse = timepulse; /* 75% duty cycle */
    TIM_OC3Init(TIM4, &TIM_OCStruct);
    TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);

    }

    void USART1_IRQHandler(void){
    //check the type of interrupt to make sure we have received some data.
    if( USART_GetITStatus(USART1, USART_IT_RXNE) ){
    char t = USART1->DR; //Read the character that we have received

    if( (DataReceivedCounter < BUFFER_SIZE) && t != 13 ){
    received_buffer[DataReceivedCounter] = t;
    DataReceivedCounter++;
    }
    else{ // otherwise reset the character counter and print the received string
    DataReceivedCounter = 0;
    //only raise a command event if the enter key was pressed otherwise just clear
    if(t == 13){
    USARTCommandReceived(received_buffer);
    }

    ClearCommand();

    }
    }
    }

    void USARTCommandReceived(char * command){
    SendData(USART1, received_buffer);

    if (compare (command,"LMF1") == 0){
    TM_PWM_Init(6299);
    }else {
    TM_PWM_Init(0000);

    }
    }
    void ClearCommand(){
    int i =0;
    for(i=0;i < BUFFER_SIZE; i++){
    received_buffer[i] = 0;
    }

    }

    void Delay(int nCount) {
    while(nCount–) {
    }
    }

    int main(void) {

    ConfigureUsart(9600);

    SystemInit();

    TM_LEDS_Init();

    TM_TIMER_Init();

    SendData(USART1, "maksaero1 USART connection initialized");

    while (1){}
    Delay(900000) ;

    }

  • Balázs

    Hi Tilen!
    Thanks for your examples, they help a lot!
    I have a question: how can I change the pulse value in the main function without having to reinitialize the TIM4 module again? Or is that possible only in this way?

    • Set TIMx->CCRy register, where x represents TIM number and y represents tim output channel number from 1 to 4.

  • Lavanya Bodepu

    Hi Tilens! Your code was very helpful.
    I have a doubt regarding implementing sweeping frequency square waves using timers.
    Can you help me through this?

    • Hi,

      Well, let me know about your doubt and I will try to help.

  • Jacob

    In the table you’ve written that TIM2 can work with SysClk, tbh I cannot find infromation how to configure that timer to work with clock frequency.

    I know that eg. TIM1 works with that freq but TIM1_IRQn symbol is not delcared (all of PB2 timers don’t have this declaration). I need this because I use interrupts from timer in my app. Precisely I need to set “nvicStructure.NVIC_IRQChannel = TIMx_IRQn”

    Could you help me with that?

    • This depends on which stm device you have. F401 or f411 have sysclk, others sysclk/2

      • Jacob

        Oh ic, I am running on STM32F429.
        So is there any way to get interrupts from timer which works on 180 MHz?

  • RAVINDRA KANT

    Sir,

    I have copy paste the above program.But i am getting a linker error.

    collect2.exe: error: ld returned 1 exit status

    how to resolve it?
    thanks

  • Michael

    Hi,

    in the comments of your code you wrote:

    /* PWM mode 2 = Clear on compare match */
    /* PWM mode 1 = Set on compare match */

    Datasheet says:
    “In PWM mode 1, the reference signal ocxref is low as long as TIMx_CNT>TIMx_CCRx else
    it becomes high.”

    Isn’t this the other way around?

    Please correct me if I’m wrong.

    Kind regards

    • I dont know how to explain that statement to me, but when I set pwm mode to 2, output is high when tiner start from zero until it reaches ocrx register.

      After that, output is low.

      • Michael

        Is it possible this has something to do with the polarity?
        With polarity low, output is 1 while timer is low, am I right? I’m still struggling with the sense of this polarity function.

        • That’s the same I said one comment above.

          PWM mode 1: timer starts counting from 0, output is low. WHen counter reaches OCR on PWM channel, output goes high and stays there till timer overflows.

          PWM mode 2: opposite!

          • Farhan Musthafa

            a small clarification!

            We also need to set the channel polarity whether it is high or low

            for instance if i write ,

            TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

            TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

            then, the pulse may start from low to high. what if I write the polarity as high

            TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  • Farhan Musthafa

    May I Know few things?

    I am trying to to generate PWM from any channel or any TIM and GPIO Pins (if the pin has the PWM capability).

    1) I want to control the duty cycle value from user interface, in this case should I consider input captur or only pwm output configuration is enough to achieve this?

    2) I need to set the fixed voltage (5v or 3.3v), what is the way to achieve ? is there any method using code or hardware side ?

    Thanks.

    • You have mode and polarity, since output channel can work in different modes, not only pwm.

      Just take oscilloscope and check how signal looks like.

      If you wanna read, then you need input capture.
      To set fixed voltage just set pin level to 1 or 0,no need for pwm here.

      • Farhan Musthafa

        May I know which command to tell the pin level?

        (I am using your library).

        • Which one library?

          • Farhan Musthafa

            TM STM32F4 TIMER PROPERTIES

            TM STM32F4 GPIO

            and CMSIS’s libraries

            Could you please explain what does that mean to pin level 1 or 0 (from your previous comment)

            Are you talking about these two ??

            1) TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

            2) TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

          • Noooo.

            You dont need pwm and timer to set gpio to some level. Do you know how microcontroller gpio works?

            If not, please learn this first.
            And to set pin level, use gpio library from me.

          • Farhan Musthafa

            Fine. Thanks. I will learn further things.

  • Farhan Musthafa

    HI,

    I started using STM32 for my project since 1 month. Recently, I have been gone through PWM experiment with STM32F407xx. The PWM output was done but now I have an another issue, which is the voltage. In default, I can get the PWM output (0-3.3V). Is there anyway to achieve (0-5V). if so, can it be done through coding in KEIL(MDK-5)?. I am already using 5V (FT) tolerance pins.

    Thanks for your answer.

  • Pradeep Chl

    Hi Tilens, Thanks for the code. This code initiates the pwm on tim4. I am using tim9 and channel 1. I have connected GPIO pin to a buzzer. I have used 50% duty cycle and 5Khz PWM frequency. The buzzer is continuously ON. How do I set it OFF? How to set it OFF after 1 sec ? I guess I have to see how to set tim9 to off or count tim9 to 1 sec, Please suggest.

  • jafran

    hi, how to include extern library in coocox?

    • The same as others. Soudce files will be compiled and header included.

  • Peeyush Pashine

    Hi Tilen,

    I am trying to use frequency as 5Hz and experimented with various values of duty cycle. For duty cycle 0 PWM is leveled at zero as expected but for any value greater than 0, the pulse goes high to 1. For frequencies greater than 10hz, I get the expected behavior. Any clues? It happens for Nucleo and Discovery boards.

    • Use pastebin and show me your code for initialization.

  • Aniket Markande

    Hi, I m using STM32F427xx series and using PWM to drive stepper motor, and using HAL libraries.
    But if i have to give variable frequency for trapezoidal curve to drive motor at higher speed, how we can do it using HAL libraries?

  • Ali Izadinia

    Hi Tilens! Your site and libraries are awesome.
    I have to work with STM32F429 to generate the gate signals for controlling the active switches in 3 phase power electronic converter for my university project…
    So I have to add proper dead times to the complementary pwm signals on TIM1 or TIM8 output channels…
    I have checked your pwm library and can not find appropriate function to config the complementary output for PWM signal on TIM1 and TIM8 and also adding dead time to them…
    I will be appreciated if you can help me with that or add this functions to your libraries…
    Thank u in advance…
    Ali

  • ilker Talat Can KUTLUCAN

    Hello Tilen

    I tried to drive a little servo with PWM using pins other than LEDs and it doesnt work, pins never becoming HIGH, though when I changed GPIO_AFConfig for LEDs, ı could drive the servo using the pins 12 13 14 15 (GPIOD) just fine…

    Do you have any idea why cant ı use other pins ?

    • You can’t use any pin you want for timer. You must find pin which can work with your desired timer.

      • ilker Talat Can KUTLUCAN

        I am using TIM4 on f407vg-Dısc Board, Do you think I can find such information in Referance Manuel ?

        • Not in reference manual but in STM32F407 manual.

          • ilker Talat Can KUTLUCAN

            Found it 🙂 , Thank you for your quick reply

      • ilker Talat Can KUTLUCAN

        Found it 🙂 , thank you for your quick response