Skip to main content
whoamitosayotherwise
Associate
Jun 20, 2021 4:30 AM UTC
Solved

STM32 Inaccurate PWM Freq

I have the Nucleo - STM32F446RE board and have been trying to work with the PWM (using CubeMX) on it for Motor Control. But for some reason I was getting 32.8Khz whenever I set it for 32Khz (while SYSCLK was 180Mhz). I checked my calculations but to no avail. Finally I realized that when I set it to 84Mhz, I got the accurate 32Khz frequency I wanted. Upon further inspection if I kept the SYSCLK as 84, APB2 prescaler as /2 and *2 again for the APB2 timers, the problem returned. I realized that it may not have been about just the SYSCLK but the prescalers too. A /2 *2 configuration caused the 32.8Khz and a /1 *1 configuration resolved it (for 84 Mhz), but I can't do the same for 180Mhz as the clock after the first prescaler is supplied to APB2 peripherals and has a max of 90Mhz, so it can only work with a /2. This board is actually an upgrade to another M4 board I ran on 80Mhz and found to be insufficient for my use so I was looking forward to the 180Mhz. Is there any way I can solve this and get both, 180Mhz and accurate PWM? I have pasted the code and clock tab below if it can help.0693W00000BbSjCQAV.png

#include "main.h"
 
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim5;
 
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM5_Init(void);
static void MX_TIM2_Init(void);
 
int main(void)
{
 /* USER CODE BEGIN 1 */
 
 /* USER CODE END 1 */
 
 /* MCU Configuration--------------------------------------------------------*/
 
 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
 HAL_Init();
 
 /* USER CODE BEGIN Init */
 
 /* USER CODE END Init */
 
 /* Configure the system clock */
 SystemClock_Config();
 
 /* USER CODE BEGIN SysInit */
 
 /* USER CODE END SysInit */
 
 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_TIM5_Init();
 MX_TIM2_Init();
 /* USER CODE BEGIN 2 */
 HAL_TIM_PWM_Start(&htim5,TIM_CHANNEL_3);
 HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
 /* USER CODE END 2 */
 
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
 /* USER CODE END WHILE */
 
 /* USER CODE BEGIN 3 */
 }
 /* USER CODE END 3 */
}
 
/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
 RCC_OscInitTypeDef RCC_OscInitStruct = {0};
 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
 /** Configure the main internal regulator output voltage
 */
 __HAL_RCC_PWR_CLK_ENABLE();
 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
 /** Initializes the RCC Oscillators according to the specified parameters
 * in the RCC_OscInitTypeDef structure.
 */
 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
 RCC_OscInitStruct.HSIState = RCC_HSI_ON;
 RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
 RCC_OscInitStruct.PLL.PLLM = 8;
 RCC_OscInitStruct.PLL.PLLN = 84;
 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
 RCC_OscInitStruct.PLL.PLLQ = 2;
 RCC_OscInitStruct.PLL.PLLR = 2;
 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
 {
 Error_Handler();
 }
 /** Initializes the CPU, AHB and APB buses 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_DIV2;
 
 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
 {
 Error_Handler();
 }
}
 
static void MX_TIM2_Init(void)
{
 
 /* USER CODE BEGIN TIM2_Init 0 */
 
 /* USER CODE END TIM2_Init 0 */
 
 TIM_ClockConfigTypeDef sClockSourceConfig = {0};
 TIM_MasterConfigTypeDef sMasterConfig = {0};
 TIM_OC_InitTypeDef sConfigOC = {0};
 
 /* USER CODE BEGIN TIM2_Init 1 */
 
 /* USER CODE END TIM2_Init 1 */
 htim2.Instance = TIM2;
 htim2.Init.Prescaler = 0;
 htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
 htim2.Init.Period = 10000-1;
 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
 htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
 if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
 {
 Error_Handler();
 }
 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
 if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
 {
 Error_Handler();
 }
 if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
 {
 Error_Handler();
 }
 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
 if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
 {
 Error_Handler();
 }
 sConfigOC.OCMode = TIM_OCMODE_PWM1;
 sConfigOC.Pulse = 2000;
 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
 sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
 if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN TIM2_Init 2 */
 
 /* USER CODE END TIM2_Init 2 */
 HAL_TIM_MspPostInit(&htim2);
 
}
 
/**
 * @brief TIM5 Initialization Function
 * @param None
 * @retval None
 */
static void MX_TIM5_Init(void)
{
 
 /* USER CODE BEGIN TIM5_Init 0 */
 
 /* USER CODE END TIM5_Init 0 */
 
 TIM_MasterConfigTypeDef sMasterConfig = {0};
 TIM_OC_InitTypeDef sConfigOC = {0};
 
 /* USER CODE BEGIN TIM5_Init 1 */
 
 /* USER CODE END TIM5_Init 1 */
 htim5.Instance = TIM5;
 htim5.Init.Prescaler = 0;
 htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
 htim5.Init.Period = 5364;
 htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
 htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
 if (HAL_TIM_PWM_Init(&htim5) != HAL_OK)
 {
 Error_Handler();
 }
 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
 if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
 {
 Error_Handler();
 }
 sConfigOC.OCMode = TIM_OCMODE_PWM1;
 sConfigOC.Pulse = 2182;
 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
 if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN TIM5_Init 2 */
 
 /* USER CODE END TIM5_Init 2 */
 HAL_TIM_MspPostInit(&htim5);
 
}
 
/**
 * @brief GPIO Initialization Function
 * @param None
 * @retval None
 */
static void MX_GPIO_Init(void)
{
 GPIO_InitTypeDef GPIO_InitStruct = {0};
 
 /* GPIO Ports Clock Enable */
 __HAL_RCC_GPIOC_CLK_ENABLE();
 __HAL_RCC_GPIOH_CLK_ENABLE();
 __HAL_RCC_GPIOA_CLK_ENABLE();
 __HAL_RCC_GPIOB_CLK_ENABLE();
 
 /*Configure GPIO pin : B1_Pin */
 GPIO_InitStruct.Pin = B1_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
 
}

This topic has been closed for replies.
waclawek.jan
waclawek.janBest answer
Super User
Jun 20, 2021 6:19 AM UTC

HSI is unprecise and PLL influences it - see footnote under the HSI parameters table in the latest datasheet.

JW

5 replies

waclawek.jan
waclawek.janBest answer
Super User
Jun 20, 2021 6:19 AM UTC

HSI is unprecise and PLL influences it - see footnote under the HSI parameters table in the latest datasheet.

JW

Tesla DeLorean
Guru
Jun 20, 2021 9:24 AM UTC

The Period value needs to be encoded as N-1

84,000,000 / 2183 = 38479.157

84,000,000/ 32000 = 2625

htim5.Init.Period = 2625-1;

sConfigOC.Pulse = 1312; or 1313 would be approximately 50/50 duty

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
MM..1
Super User
Jun 20, 2021 10:21 AM UTC

I dont understand you example code (5364 result to ~15k), maybe your setup have some fail .

But when you need perfect freq, you need HSE or thermal corrected calibrate HSI table.

Simple calculation if error HSI is +3% then your 32k changes to 32,96k

whoamitosayotherwise
Associate
Jun 21, 2021 5:02 AM UTC

Yes the 5364 was just me tying out different values to check if the problem was at that specific range of frequency, sorry I forgot to update. As you all suggested I fixed the problem by using HSE and and am now getting the desired 32 Khz. Thanks

Piranha
Principal III
Jul 17, 2021 3:29 PM UTC

The 90 MHz limit is for APB2 peripheral clock (PCLK2). For APB2 timer clock the maximum is 180 MHz.