cancel
Showing results for 
Search instead for 
Did you mean: 

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

vrindar
Associate

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

5 REPLIES 5
Sarra.S
ST Employee

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

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

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

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

 

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


@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" ?