Skip to main content
Explorer
February 29, 2024
Question

STM32F411 Timer not producing fixed PWM duty cycle at output timer channel.

  • February 29, 2024
  • 4 replies
  • 2472 views

Hi,

I am using the STM32F411 MCU and i am trying to generate PWM signal with fixed dutycycle and frequency.

clock configuration and timer settings is attached below.

vrindar_0-1709190458563.png

vrindar_1-1709190512250.png

When I set the PWM frequency to 10KHz and the duty cycle to 50%, I get the output as 10 KHz frequency and the dutycycle toggles between 50.00% and 49.97%. When setting PWM frequency to 40KHz and duty cycle to 50%, I get output as 40 KHz frequency and dutycycle toggles between 48.00% and 47.97%.

Program code:

void PWM_Frequency_Init(uint8_t PWM_Frequency)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
 
  Auto_Reload_Value= 1000000/(PWM_Frequency*1000);  //Calculate the ARR value
  TIM4->CCR1 = 0;
 
  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 72-1;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = Auto_Reload_Value -1;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_TIM_MspPostInit(&htim4);
}
 
 
/**
  * @brief  Generating PWM with respect to the duty cycle and frequency
  * @PAram  PWM_Dutycycle, Duty cycle with respect to the voltage/current/half-cell voltage
  * @PAram  PWM_Frequency, Frequency with respect to the voltage/current/half-cell voltage
  * @retval None
  */
void PWM_Genertion(float PWM_Dutycycle)
{
    CCR1_Value = ((PWM_Dutycycle*Auto_Reload_Value)/100); //calculate the ccr1 value
TIM4->CCR1= CCR1_Value;
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);
}

Could you please explain why getting like this?

Thank you

    This topic has been closed for replies.

    4 replies

    ST Employee
    February 29, 2024

    Hello @vrindar,

    I would check the clock source, but since you're using HSE, I don't think that would be the problem 

    Try to get the prescaler to zero, and do all the division in the period

     

    vrindarAuthor
    Explorer
    March 1, 2024

    Hello @Sarra.S 

    I tried the same in the Evaluation board(STM32F429ZI) using HSI but got the same variation in the duty cycle.

    vrindar_0-1709267140027.pngvrindar_1-1709267176914.png

     

    Super User
    February 29, 2024

    Does the program run otherwise, e.g. if you blink a LED (toggle an output) with a simple loopdelay in main loop, does it blink?

    Read out and check/post content of TIM and relevant GPIO registers.

    [EDIT] sorry I misread the question [/EDIT]

    JW

    Super User
    March 1, 2024

    Hi @vrindar ,

    If you set prescaler so that timer's counter clock is 1ms, and you set ARR so that PWM frequency is 40kHz, the period is 1/40kHz = 25ms i.e. ARR=25-1 and the granularity of pulse width setting is 1ms. If you want 50% PWM, the calculation you made above (i.e. ((PWM_Dutycycle*Auto_Reload_Value)/100) = (50*25)/100 =1250/100 = 12 (notice the rounding in integer division), i.e. the pulse is ON for 12 ms and off for 13ms. That's 12ms/25ms=48% (as consequence of the rounding). With 1ms granularity (i.e. prescaler set to 72-1) you can't set the PWM more precisely; if you'd set CCRx to 13, you'd have 13ms long pulse i.e. 13ms/25ms = 52% ratio.

    The solution is, as @Sarra.S said above, not to set prescaler to result in 1ms timer counter clock. As she said, simply set prescaler to 0, and then for 40kHz PWM you'll have ARR=(72 * 25) - 1, and the granularity is 1/72ms.

    JW

    Graduate II
    March 1, 2024

    @vrindar wrote:

    ...the dutycycle toggles between 50.00% and 49.97%....

     


    How did you measure that values ? Did you just read these values from oscilloscope or logic analyzer "automatic measurment" ?