2020-05-26 11:54 PM
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();
}
}
Solved! Go to Solution.
2020-05-27 12:51 AM
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.
2020-05-27 12:51 AM
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.
2020-05-27 01:01 AM
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?
2020-05-27 01:06 AM
> 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
2020-05-27 01:24 AM
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.
2020-05-27 04:37 AM
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.
2020-05-27 04:50 AM
Please post the contents of the RCC and timer registers.
2020-05-27 05:02 AM
> The frequency of the PWM is 12 Hz
How do you know?
JW
2020-05-27 05:04 AM
Here they are from CubeMX
RCC
Clock Config Screen
Timer 3
2020-05-27 05:10 AM
No, the contents of the hardware registers. Cube screenshots and and source code containing HAL function calls are useless for troubleshooting.