Home > Back-end >  STM32F4 Timers - Prescaler or period value must be divided by two to get what I expect
STM32F4 Timers - Prescaler or period value must be divided by two to get what I expect

Time:10-16

I am working on STM32F4 and I noticed some strange behaviors with Timers.

I need three timer : the first one must generate an interrupt every 1ms (I chose TIMER 1, an advanced control timer), the second one must generate an interrupt every 10ms (TIMER2, general purpose interrupt) and the third one must have its CNT counter incremented every 1µs (so interrupt is generated every 65.535 ms, as I am using TIMER 3 for this one and CNT is 16 bits).

In order to compute PSC (prescaler) and ARR (period) values, I used this thread. So the formula I am using is (for a period in ms):

Period = 1000 * (PSC 1)*(ARR 1) / TmerClockFreq

Which gives :

ARR = ((Period * TmerClockFreq) / (1000*(PSC   1)) - 1

In my case, TmerClockFreq = 168 MHz = 168 x 10^6 Hz

For TIMER1, everything work as expected. I chose PSC=11 which gives me ARR=13999 and corresponding interrupt is in deed called every 1 ms.

Things get complicated with TIMERS 2 and 3.

TIMER 2 : I want Period = 10 ms. If I take, PSC = 39, it gives me ARR = 41999. Problem : with those parameters, my interrupt is called every 20ms. To get the period I wanted, I had to divid PSC by 2. So PSC = 19 and ARR = 41999.

Same thing go with TIMER 3. For Period=65.535 ms and ARR = 65535, PSC = 167 (Please note that computation are approximatives in this case, but I don't need a very high precision). But there again, interrupt is called twice as slow as I expected (every 131.064 ms approx.) I add to chose PSC = 83 to get my interrupt to be called every 65.535 ms.

So my question is : why do I need to divide prescaler by 2 for TIMER 2 and TIMER 3 to get expected period call for my interrupt ?

Here's how I set up TIMER 3 :

/* Get clock speed */
u32_ticks = (HAL_RCC_GetHCLKFreq() / 1000000); // = 168

pst_TimerHandle->Instance = TIM3;
pst_TimerHandle->Init.Prescaler = (u32_ticks - 1) / 2;
pst_TimerHandle->Init.CounterMode = TIM_COUNTERMODE_UP;
pst_TimerHandle->Init.Period = 0xFFFF;
pst_TimerHandle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
pst_TimerHandle->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(pst_TimerHandle) != HAL_OK)
{
    //error handling
}
st_ClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(pst_TimerHandle, &st_ClockSourceConfig) != HAL_OK)
{
    //error handling
}
st_MasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
st_MasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

Here's how I generate some pulse in IRQ handler to check interrupt's period :

void TIM3_IRQHandler(void)
{
    HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);

    HAL_TIM_IRQHandler(HAL_TIMER3_GetHandle());
}

Oscilloscope output for TIMER 3, ARR=0xFFFF and PSC = 167 (value computed from formula, output NOT as expected)

Oscilloscope output for TIMER 3, ARR=0xFFFF and PSC = (167 / 2) = 83 (PSC divided by 2, output as expected)

CodePudding user response:

Timer1 is the advanced timer and timer2 & 3 are general purpose timer. Timer1 is from APB2 and timer 2,3 from APB1. You can check reference book or check your clock setting to see more details.

  • Related