Hello, I configured a timer to generate a signal every 1 ms.
See below my code about the timer:
TIM_DeInit(TIMx); // TIM1 Deinitialization * TIM_InitStructure.TIM_Mode = TIM_OCM_CHANNEL_1; TIM_InitStructure.TIM_OC1_Modes = TIM_TIMING; TIM_InitStructure.TIM_Clock_Source = TIM_CLK_APB; TIM_InitStructure.TIM_Clock_Edge = TIM_CLK_EDGE_FALLING; TIM_InitStructure.TIM_Prescaler = 0xEF; // period = 5us TIM_InitStructure.TIM_Pulse_Length_1 = 0xC8; // cycle of 200 period => cycle = 1ms TIM_Init (TIMx, &TIM_InitStructure);
And the statements inside timer's interrupt:
void TIM1_IRQHandler(void) { // port 3 pin 7 activated P37_1; // ACK interrupt TIM_ClearFlag(TIM1, TIM_FLAG_OC1); // clear Output Compare 1 flag TIM_CounterCmd(TIM1, TIM_CLEAR); // Reset TIM1 Counter VIC0->VAR = 0xFF; // write any value to VIC0 VAR }
BUT my oscilloscope measured a period of 1.03 ms instead of the 1ms expected. Normally to generate a pulse every 1.03 ms the TIM_Pulse_Length_1 should be set to 0xCE. As you can see, the difference between 0xCE and 0xC8 is big.
What can be the cause of this timer's inaccuracy ? > Problem in PLL configuration ? > Problem of crystal ? > Problem in timer configuration ?
Has someone the same problem ? In advance, thank you
Hi everybody, We found a solution. We wanted to have an interruption every 1ms and now we measure 1.001 ms (because of the resolution of our oscillo) ! What we did: - We use FIQ (fast interrupt) instead of classical interrupt (IRQ) - We acces directly registers (we stop to use ST library) - We reset the timer first !, after we clear the interrupt flag and we activate the flag to toggle a LED in the main loop
BAD:
void TIM1_IRQHandler(void) { P37_1; // activate LED on Port 3 pin 1 // ACK interrupt TIM_ClearFlag(TIM1, TIM_FLAG_OC1); // clear Output Compare 1 flag TIM_CounterCmd(TIM1, TIM_CLEAR); // Reset TIM1 Counter VIC0->VAR = 0xFF; // write any value to VIC0 VAR }
GOOD:
void FIQ_Handler(void) { // ACK interrupt TIM1->CNTR = 0x1234; // Reset TIM1 Counter TIM1->SR &= ~TIM_FLAG_OC1; // clear Interrupt Output Compare 1 counter_ms++; // use to toggle a LED in the main loop }
I don't work with the ST chips, but are you sure that you have to reset the timer, and not just acknowledge the interrupt? Don't it have an auto-reload setting?
With auto-reload, it should not matter what IRQ priority you have. Low IRQ priority would generate more jitter, but the jitter will not affect the frequency. If one interrupt was handled late, the next interrupt will be trigged correspondingly earlier.
"...Don't it have an auto-reload setting?"
Yes, the ST (or at least the STR9) does, so that would be the way to do it.
There should also be no need to use the FIQ, the IRQ does a perfectly adequate job - Apart from the (inevitable small amount of) jitter.
I haven't got the source to hand, but I'm fairly sure that the RTX task switch timer operates in this manner.
I would be very surprised if there exists ARM chips with so low-end timer implementations that they don't have auto-reload.
View all questions in Keil forum