cancel
Showing results for 
Search instead for 
Did you mean: 

Prescaler and period values for PWM in STM32

GunkutA
Senior

I am using STM32F103C8Tx and I am trying to create a PID adjustable PWM. In PID I will be giving values to PWM from 0 to 100 to set the duty cycle. That means my counter period needs to be 100 in Cubemx. Because as I have learnt while I am changing the dutch cycle it changes the counter period. However, I need to create PWM with 200 KHz frequency and the clock of the timer is 72 MHz.In order to achieve a value of 100 in counter period I need to have a 3.6 prescaler. Am I following a wrong way or did I get this PWM duty cycle thing wrong in stm32?

Note: I am changing duty cycle from the code as

htimx.Instance->CCRx =Duty_Cycle;

 I think I cannot put codes as a reply so I will put them here:

static void MX_TIM3_Init(void)
{
 
  /* USER CODE BEGIN TIM3_Init 0 */
 
  /* USER CODE END TIM3_Init 0 */
 
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
 
  /* USER CODE BEGIN TIM3_Init 1 */
 
  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 1;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 359;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &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(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */
 
  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&htim3);
 
}
 
 
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
 
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC|RCC_PERIPHCLK_USB;
  PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

1 ACCEPTED SOLUTION

Accepted Solutions
berendi
Principal

The prescaler value is an integer. Check the timer feature description and register documentation in the reference manual, do not rely on libraries that leave important aspects undocumented.

You can either change the PID algorithm to output a value between 0 and 120 or 360, change the system clock to 60 MHz, or not use the prescaler at all and live with the 0.14 % error.

View solution in original post

17 REPLIES 17
berendi
Principal

The prescaler value is an integer. Check the timer feature description and register documentation in the reference manual, do not rely on libraries that leave important aspects undocumented.

You can either change the PID algorithm to output a value between 0 and 120 or 360, change the system clock to 60 MHz, or not use the prescaler at all and live with the 0.14 % error.

GunkutA
Senior

I guess the easiest way to change PID output to 0 and 360 range. Set Prescaler to 2 and Counter Period to 179. So it will give me 200 kHz PWM while using 72 MHz clock. However, since program adds +1 to counter period. I will never have a %0 duty cycle. Is that correct?

> However, since program adds +1 to counter period. I will never have a %0 duty cycle. Is that correct?

No.

If CCRx = 0, you have 0% duty cycle; if CCR = ARR CCR > ARR you have 100% duty cycle (depending on the particular PWM mode you are using, this may be the other way round).

Read the TIM chapter in RM.

JW

berendi
Principal

Reference manual, TIMx capture/compare mode register 1 (TIMx_CCMR1) description:

110: PWM mode 1 - In upcounting, channel 1 is active as long as TIMx_CNT<TIMx_CCR1 else inactive.

When you want a counter period of 100 cycles, you set ARR = 99. CNT counts from 0 to 99, then starts again at 0.

To have 0% duty cycle, set CCR1 = 0. Because CNT can't be less than 0, the output is always inactive.

To have 100% duty cycle, set CCR1 = 100. Now CNT is always less than CCR1, because CNT is always in the 0..99 range, so the output is always active.

GunkutA
Senior

Now eventhough APB1 Timer Clock is 72 MHz. Prescaler is 0 and Counter Period is 359. The frequency of the PWM is 12 Hz. I use blue pill STM32. What might be the cause . I know it is a little bit irrelevant from the topic but I didn't want to open a new topic for that.

berendi
Principal

Please post the contents of the RCC and timer registers.

> The frequency of the PWM is 12 Hz

How do you know?

JW

GunkutA
Senior

Here they are from CubeMX

RCC0693W000001pY2qQAE.png

Clock Config Screen

0693W000001pY30QAE.png

Timer 30693W000001pY35QAE.png

berendi
Principal

No, the contents of the hardware registers. Cube screenshots and and source code containing HAL function calls are useless for troubleshooting.