cancel
Showing results for 
Search instead for 
Did you mean: 

Timer at double expected speed (have considered clock tree)

honboxuan
Associate II
Posted on October 06, 2013 at 03:28

I'm using a DIY development board for STM32F405RGT6, with an 8MHz HSE. I've used the clock configuration tool from ST to generate the system_stm32f4xx.c file such that the clock is configured to 168MHz using the HSE. I've checked that the HSE value in the stm32f4xx.h file is correct.

Now I've configured TIM6 to generate an interrupt every (what I expected to be) 1 millisecond. TIM6 uses APB1, which has a prescaler of 4. Considering the clock tree, I expect the timer clock to be 84MHz. So I set my prescaler to 83, and period to 9 By incrementing a volatile integer in the interrupt and blinking an LED based on that (no oscilloscope at home), I find the frequency to be twice of what I expected. Here's the code I used to set up TIM6.

void base_timer_init(void) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
//TIM_TimeBaseInitStructure.TIM_Prescaler = 167;
//TIM_TimeBaseInitStructure.TIM_Prescaler = (uint16_t)((SystemCoreClock/2)/1000000)-1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 83;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 999;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseInitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM6_DAC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM6, ENABLE);
}

And here's the code for blinking the LED:

#include <
stdio.h
>
#include ''stm32f4xx.h''
#include ''gpio.h''
#include ''timer.h''
__IO uint32_t millis = 0;
int main(void) {
RCC_HSEConfig(RCC_HSE_ON);
while(!RCC_WaitForHSEStartUp());
gpio_init();
base_timer_init();
while(1) {
if (millis >= 1000) {
millis = 0;
GPIO_ToggleBits(GPIOC, GPIO_Pin_9);
}
}
return 0;
}
void TIM6_DAC_IRQHandler(void) {
millis++;
TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
}

I've spent quite a few hours on this but made no progress, so I'll really appreciate any help! Thank you in advance. #stm32f4-timer-clock-frequency
6 REPLIES 6
Posted on October 06, 2013 at 03:57

void TIM6_DAC_IRQHandler(void) {
TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
millis++;
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
honboxuan
Associate II
Posted on October 06, 2013 at 04:07

Thanks for the fast response as usual!

Why does the order matter? I just left my workbench (it's 3am now), so I'll only test it later.

Posted on October 06, 2013 at 04:26

There is a pipelining/write-buffer hazard with the tail-chaining, your interrupt handler re-enters once immediately after it leaves. You should clear interrupt sources early, and ideally qualify the source.

 

'Basically the pipeline in the processor decides what interrupt to service next before the clearing of the interrupt propagates back from external peripherals on the APB/AHB buses, and back into the NVIC. The latency will depend on the speed disparity of those buses, futher impacted by the write buffer on the processor. The effect will be that the processor will re-enter an interrupt service routine almost immediately with what looks like a spurious interrupt which will not be signalled in the status register as that read will have fenced the pending write, which may also have already completed. It's a classic race condition, the pipeline gives the appearance of single cycle execution (throughput), but the latency is much higher.

 

 

So you either need to dwell for a couple of cycles to accommodated the pipeline/write buffer, or fence the write with some other reads/writes to enforce in-order completion.'

https://community.st.com/message/55698

 

Edit: Fixed DEAD LINK, original post from Oct 5, 2013

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
honboxuan
Associate II
Posted on October 06, 2013 at 14:07

I'm glad I asked. Thank you!

derek
Associate II
Posted on October 12, 2013 at 20:21

I've had this issue also.   Dependent on certain settings, the clock used for the timers will actually be 2x the speed of the bus they are on.   

In section 6.2 of the STM32F4 reference manual there is a short blurb describes this:

The timer clock frequencies for STM32F405xx/07xx and STM32F415xx/17xx are

 

automatically set by hardware. There are two cases:

 

1. If the APB prescaler is 1, the timer clock frequencies are set to the same frequency as

 

  that of the APB domain to which the timers are connected.

 

2. Otherwise, they are set to twice (×2) the frequency of the APB domain to which the

 

   timers are connected.

Since you are running a prescaler of 4 for the APB1 bus, the timer clock will 2x the bus speed. 
Posted on October 12, 2013 at 22:09

He's not talking about the clock tree, as the title clearly states.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..