cancel
Showing results for 
Search instead for 
Did you mean: 

My PWM Timer of the STM32f411 generates wrong Pulses. Any Ideas?

TKöhl.1
Associate II

I have migrated some Code from a STM32f103 to my new STM32f411CEU6 Microcontroller. While configuring the Timers for the PWM generation I ran into a problem, namely the pulses are about 1500us, when they should be 1000us.

Here are my Clock and Timer configurations from the STM32CubeMX:

Clock configuration:

0693W000000U7JZQA0.png

My PWM Setup:

0693W000000U7K8QAK.png

The Measured Signals:

0693W000000U7KNQA0.png

So I think i have configured the systemclock to have a frequency of 100Mhz, which gets fed to Timer3. A Prescaler of 99 should divide this pulse to 1us and a Pulse of 1000 should then result in Pulses with a width of 1000us.

I do not call any functions in my code, other than

HAL_TIM_PWM_Init(&htim3);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);

The from the CubeMX generated initialisation code for timer 3 looks like this and is called at the start of my program:

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 = 99;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 5000;
  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 = 1000;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.Pulse = 0;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */
 
  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&htim3);
 
}

So my question is: What is wrong with the my setup, that i get ~1500us Pulses instead of 1000us?

Some further Information:

I have the same Problem with Timer2, where i measure pulsewidths via interrupt, which differ by the same factor.

My HSE Crystal has a frequency of 25MHz, changing the clocksource to HSI and the /M divider to 16 doesnt affect the result.

I also generate a I2C Clock with 400kHz. The generated signal is correct, making me believe, that the systemclock should be correct.

(My htim2 setup)

0693W000000U7ROQA0.png

Any help is highly appreciadet. Thank you!

Regards

Tim Köhler

1 ACCEPTED SOLUTION

Accepted Solutions
TKöhl.1
Associate II

I now fixed the error. I am pretty sure, that PLL was configured as system clock prior to SystemClock_Config. While stepping through the code, I also hit the return HAL_OK statement of HAL_RCC_ClockConfig().

The Solution is pretty Simple. I let the CubeMX generate Code for configuring the HSI as System Clock. I copied this Method and called it just before the real SystemClock_Config() method. Now the PLL could be configured and i get the right Pulses as PWM and the peripheral Clocks seem to be right, too.

void SystemClockHSI_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_SCALE1);
	/** Initializes the CPU, AHB and APB busses clocks 
	*/
	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
	RCC_OscInitStruct.HSIState = RCC_HSI_ON;
	RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
	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_HSI;
	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_0) != HAL_OK)
	{
		Error_Handler();
	}
}

This is the Method for configuring the HSI as clock source.

Thanks to everyone for your helpful advices!

View solution in original post

6 REPLIES 6
Imen GH
ST Employee

Hello,

I hope this calculation information can help you:

For example, TIM2 input clock TIM2CLK is set to APB1 clock (PCLK1), since APB1 prescaler is equal to 1.                                 

  TIM2CLK = PCLK1                                                   

  PCLK1 = HCLK                                                      

  => TIM2CLK = SystemCoreClock (100 MHz)                            

To set the TIM2 counter clock frequency to 10 KHz, the prescaler (PSC) is calculated as follows:

PSC = (TIM2CLK / TIM2 counter clock) - 1

PSC = (SystemCoreClock /10 KHz) - 1

SystemCoreClock is set to 100 MHz for STM32F4xx Devices.

Auto-reload (ARR) is calculated to get a time base period of 10 ms, meaning a time base frequency of 100 Hz.

ARR = (TIM2 counter clock / time base frequency) - 1

ARR = (TIM2 counter clock / 100) - 1

Regards

TDK
Guru

Your readings are off from the expected by a factor of 16/25. I would guess you're assuming you're using a 25 MHz crystal, but instead are using a 16MHz crystal or the 16 MHz HSI as the PLL source. This is by far the most likely explanation.

If you want to be super sure, output MCO an add that to your scope trace.

If you feel a post has answered your question, please click "Accept as Solution".

> changing the clocksource to HSI and the /M divider to 16 doesnt affect the result.

Maybe the Cube magic in your code is somehow wrong and does not you click in CubeMX.

Read out and check the RCC registers' content.

JW

Thank you, for pointing me in the right direction!

I now configured the PLL to take the HSI as an Input, PLLM = 16, PLLN = 400 and PLLP = 4.

This does also reflect in the generated code:

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_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  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 = 16;
  RCC_OscInitStruct.PLL.PLLN = 400;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  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_3) != HAL_OK)
  {
    Error_Handler();
  }
}

But when i read the PLLCFGR the configuration does not seem to take effect.

It reads 0x08012008 which translates to: PLLM = 8, PLLN = 128, PLLP = 4. Therefore the Sysclock clocks at 64 Mhz, which also explains the difference in timer pulses.

The SystemClock_Config method finishes without error, but does not set the registers correctly.

I the Problem might be, that PLL is already enabled, when SystemClock_Config() is called and I did not see that change, during the HAL_RCC_ClockConfig call.

Do you have any advice for me, on how to fix this or how to maybe configure the clock by myself?

Thank you

Tim Köhler

Why is the PLL enabled prior to SystemClock_Config? You can't change it while it's enabled and being used as the system clock.
Are you sure this is completing without error? OR is it only completing because Error_Handler() is defined as nothing?
If you feel a post has answered your question, please click "Accept as Solution".
TKöhl.1
Associate II

I now fixed the error. I am pretty sure, that PLL was configured as system clock prior to SystemClock_Config. While stepping through the code, I also hit the return HAL_OK statement of HAL_RCC_ClockConfig().

The Solution is pretty Simple. I let the CubeMX generate Code for configuring the HSI as System Clock. I copied this Method and called it just before the real SystemClock_Config() method. Now the PLL could be configured and i get the right Pulses as PWM and the peripheral Clocks seem to be right, too.

void SystemClockHSI_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_SCALE1);
	/** Initializes the CPU, AHB and APB busses clocks 
	*/
	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
	RCC_OscInitStruct.HSIState = RCC_HSI_ON;
	RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
	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_HSI;
	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_0) != HAL_OK)
	{
		Error_Handler();
	}
}

This is the Method for configuring the HSI as clock source.

Thanks to everyone for your helpful advices!