We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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
Ah I see.
So that's what a guru looks like.
Glad I'm not one ;)
maybe this an avatar of the professor himself? long tongue, I'm telling 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.
Hi IBShy,
you said: ""...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."
Are you sure ? I tried to do this. I deleted "TIM1->CNTR = 0x1234;" and it didn't work properly...
To get auto-reload, a timer must be configured to use auto-reload. In your case, it isn't enough to remove the assign in the ISR. You must also look through the configuration bits.
You need to: 1) Specify a reload value. 2) Configure the timer not not just generate an interrupt, but instead both generate the interrupt and at the same time reload the timer.
0xFFFC...?
Maybe I missed something in the reference manual ( You can have a look: www.st.com/.../13742.pdf )...
But I found nothing about auto-reload of the timer.
I agree that this function can be very useful but it's not implemented.
>"0xFFFC...?" I don't know what you try to mean but whatever you write in the counter (0x1234, 0x0000), the counter will be reset at the value 0xFFFC
I might be a bit off, since I don't work with the ST chips, but isn't it the pulse width modulation mode you should use?
Then it will count until it matches TIM_OC2R and then reload to 0xfffc. With OC2IE set, you will also get an interrupt when the timer gets reloaded.
Thanks for spending time on this problem. I'm not using timer in PWN mode. But, even if you set the OC2IE bit, the timer counters won't be reloaded (nothing is written about that).
I know that you are not using the PWM mode. But I think it looks like you should use the PWM mode.
Look at figure 44 - it clearly shows the auto-reload of the timer. And note 3 shows that you will get an interrupt too.
If I understand this correctly, you will not consume any external pin, unless you set the OC1E pin. After all, you are not interested in any pulse width modulation, just to get the timer to work with automatic reloads so it will not loose time on every interrupt.
In the end, it seems like you should follow the described procedure in 7.3.7 for configuring PWM mode, but instead of setting the OC1E, you should set OC2IE.
hehe cleaver :p (but tricky solution) You are right. I will try.