cancel
Showing results for 
Search instead for 
Did you mean: 

Why STM32H7 PWM Timer does not start immediately after reconfiguration?

NRedd.2
Associate II

Hi,

I am using STM32H7's Timer 2 peripheral to generate a clock frequency ranging from 10Hz to 1MHz.

To reconfigure the PWM to attain certain frequency, the PSC, ARR and CCR1 registers are modified.

The sequence for modification is as follows: PWM_Start ==> PWM_Stop ==> Config ==> PWM_Start.

When I follow this sequence, jumping frequencies upwards doesn't work. For e.g. when I go from 10Hz to 100kHz, the PWM seems to start after 15 seconds.

But, going downwards always works.

As a workaround, I am de-initializing and initializing the Timer2 peripheral. This seems to fix the issue.

But I still wonder why going upwards by just changing PSC, ARR and CCR1(Pulse) doesn't work.

#define HANDLE_TIMER_DAC_CLOCK htim2
 
bool Clock_Start()
{
	ret = HAL_TIM_PWM_Start(&HANDLE_TIMER_DAC_CLOCK, TIM_CHANNEL_1);
 
	if (ret != HAL_OK)
	{
		LOG_ERROR("[DAC] Failed to start PWM  %lu", ret);
		Error_Handler();
	}
 
	return true;
}
 
bool DAC_Stop()
{
	uint32_t ret = 0;
 
	ret = HAL_TIM_PWM_Stop(&HANDLE_TIMER_DAC_CLOCK, TIM_CHANNEL_1);
 
	if (ret != HAL_OK)
	{
		LOG_ERROR("[Clock] Failed to stop PWM : %lu", ret);
		Error_Handler();
	}
 
	return true;
}
 
static void ConfigTimer(TIM_HandleTypeDef* htim,
                        dac_frequency_map_t* pMap,
                        uint32_t* pTimerPeriod)
{
	uint32_t timerPrescaler = 0;
	uint32_t timerClockFreq = HAL_RCC_GetSysClockFreq() / 2;
	uint32_t timerPeriod    = timerClockFreq / ( pMap->requestFreqHz);
 
	while ((timerPeriod / (timerPrescaler + 1)) > UINT16_MAX)
	{
		timerPrescaler++;
	}
 
	timerPeriod = timerPeriod / (timerPrescaler + 1);
 
	__HAL_TIM_SET_PRESCALER(htim, timerPrescaler);
	__HAL_TIM_SET_AUTORELOAD(htim, timerPeriod);
 
 
         TIM2->CCR1 = (timerPeriod / 2);
}
 

1 ACCEPTED SOLUTION

Accepted Solutions

TIMx_PSC is unconditionally preloaded. After changing it it does not get "active" until next update. If ARR is not preloaded (i.e. you've set TIMx_CR1.ARPE=0), changing ARR is active immediately, and if it changes to a high value while the active PSC remained higher than the one matching ARR, the resulting time period is longer than expected.

If ARR is not preloaded, you also run into the risk of setting ARR below the current value of CNT, in which case CNT will count up to the maximum for given timer (0xFFFF or 0xFFFFFFFF) and that will take surprisingly long.

JW

PS. TIM2 is most likely to be 32-bit in 'H7, check. That means you in most cases don't need to use prescaler.

View solution in original post

3 REPLIES 3

TIMx_PSC is unconditionally preloaded. After changing it it does not get "active" until next update. If ARR is not preloaded (i.e. you've set TIMx_CR1.ARPE=0), changing ARR is active immediately, and if it changes to a high value while the active PSC remained higher than the one matching ARR, the resulting time period is longer than expected.

If ARR is not preloaded, you also run into the risk of setting ARR below the current value of CNT, in which case CNT will count up to the maximum for given timer (0xFFFF or 0xFFFFFFFF) and that will take surprisingly long.

JW

PS. TIM2 is most likely to be 32-bit in 'H7, check. That means you in most cases don't need to use prescaler.

NRedd.2
Associate II

Hello @Community member​ ,

Ah! That is it!

Setting the CNT to 0 works perfectly. I now do not have to de-init the peripheral.

Thank you for the detailed explanation and response! Very much appreciate it.

It's a similar problem than as in this recent thread.

JW