STM32F407 update PWM duty cycle after complete PWM period only

Thread Starter

Vindhyachal Takniki

Joined Nov 3, 2014
I have made a code for PWM for STM32F407. It is working fine for generating PWM.

1. Currently what happens is I have made a PWM period of 5seconds in total.

2. Suppose in code I call TIM_SetCompare2(TIM9 , 32767), now outout will be 2.5 seconds on & 2.5 seconds off.
where 32767 is 50% duty cycle, & 65535 is 100% duty cycle.

3. Now suppose on time of 2.5seconds is running & I suddenly change TIM_SetCompare2(TIM9 , 10000), it will now be roughly 15% on and 15% off.
This happens even if previous 2.5 duty cycle was running

4. I want that next compare value updates only after completion of first compare match cycle.

5. I have no way to sync both, because compare value is coming from a another setup at random stage, & when a new compare value comes, I have to set a display to user, and it should run for that compare cycle only, not to get updated by new compare cycle.

6. How to do it?

void initialize_pwm(void)
    uint16_t Channel2Pulse = 0U;   
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
/* GPIOA Configuration: Channel 2 as alternate function push-pull */
    RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA , ENABLE);
    GPIO_InitStructure.GPIO_Pin    = GPIO_Pin_3;
    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(GPIOA, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_TIM9);
/* TIM9 clock enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9 , ENABLE);
/* Time Base configuration */
    TIM_TimeBaseStructure.TIM_Prescaler = 12816U;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_Period = 65535;//PWM_PERIOD_VALUE;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM9, &TIM_TimeBaseStructure);

/* Channel 2 Configuration in PWM mode */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
    TIM_OCInitStructure.TIM_Pulse = Channel2Pulse;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
    TIM_OC2Init(TIM9, &TIM_OCInitStructure);

/* TIM9 counter enable */
    TIM_Cmd(TIM9, ENABLE);

/* TIM9 Main Output Enable */
    TIM_CtrlPWMOutputs(TIM9, ENABLE);

    TIM_SetCompare2(TIM9 , 32767);

} /* function ends here */


Joined Oct 2, 2009
This is a typical scenario on any MCU running PWM with HW timers.
The problem occurs if you attempt to alter the timer settings while PWM is still in progress and your new value is lower than the current timer value.

One solution is to use timer interrupts to indicate when the timer has reached its maximum count and is about to restart.
Use this interrupt to be the only time when you are allowed to make changes to the new PWM value.

Another solution is to stop the timer, make changes, and reset the timer count. Restart timer.