2017-04-19 02:43 AM
Posted on April 19, 2017 at 11:43
In a project I'm attempting to measure 4 frequency channels (range 10 to 500 hz) using TIM3 in the STM32F
During development I noticed the occasional missed capture event, or double capture events. I didn't pay much attention to these glitches thinking it was my hardware that glitched around a bit.
However, a completely other project with the same software has an identical problem. Then it must be software, right?
I've looked and it for a few days, and I think I found another problem in the timer capture hardware.
The erratas currently there:
In capture mode, when a capture occurs while the CCRx register is being read, the capture flag (CCxIF) may be cleared without the overcapture flag (CCxOF) being set. The new data are actually captured in the capture register
If a capture occurs while the capture register is being read, an overcapture is detected even though the previously captured data are correctly read and the new data are correctly stored into the capture register
But it seems unrelated to the reading of the capture registers because the frequency of my signal is relatively slow.
Following this I created a bare metal example, with 1 channel, and I found that when the capture flag is active longer than approximately 25 us, the capture interrupt never triggers.
What happens:
- PC7 has a falling edge. EXTI is pending immediately, TIM3 has hardware filtering first.
- The EXTI triggers, and sets PD2.
- The EXTI runs a series of nops to delay the execution of TIM3 ISR.
- The TIM3 ISR does timer stuff.
- The
TIM3
ISR clears PD2.
Now when I add one extra nop to the EXTI, the capture will occasionally miss. (probably when PC7 falls during systick)
As seen in this image:
<LINK NO LONGER ACTIVE>
Is this hardware, or a flaw in my software?
(void)register performs a dummy read to R0, I've checked.
The obvious workaround is to use software capture using the EXTI, but that would require the unfiltered EXTI to be at a very high nvic priority. Not ideal.
Source:
https://github.com/Jeroen6/stm32f103_capture_problem/blob/master/main.c
Chip: STM32F103RCT7 - GH239 93 - CHN GH 445
input-capture stm32f103 errata
Solved! Go to Solution.
2017-04-20 07:52 AM
You don't need to check for overflow.
delta = period + capture - previous_capture;
if (delta > period) delta-= period;
JW
2017-04-19 03:24 AM
Count the number of occurences of each interrupt - both counts have to be identical.
JW
2017-04-19 06:22 AM
I found that there were twice as much EXTI IRQ's than TIM3 IRQ's.
There had to be a __DSB(); after the pending flags were cleared. Immediate return causes issues.
However, now I am unable the reproduce the problem in the bare metal variant. But the problem is worse in the full project.
Now 1 in 7 capture is corrupted.
2017-04-19 07:12 AM
However, now I am unable the reproduce the problem in the bare metal variant. But the problem is worse in the full project.
Now 1 in 7 capture is corrupted.
Then there's some other issue. Try to reduce to minimal your 'full project' while checking if the problem still persists.
JW
2017-04-19 08:36 AM
Have you disabled all other interrupt sources? Usually input capture will miss if something disable interrupts too long in the main loop, or if in some isr there can be delays. Interrupt priorities and behaviour programming is important. Can you share the timer capture isr code?
2017-04-19 09:46 AM
In an isolated project the period time measurement works fine.
In the full project, if I enable any additional timer, problems arise. Ranging from once a minute to once every 5 seconds.
These 'occasional' bugs are the best...
2017-04-19 12:55 PM
There are some segments where interrupts are globally are disabled. This is done to copy some data between ISR threadspace to main threadspace. When the nvic is enabled again, the chip is supposed to start with any pending interrupts.The capture flags do still work when doing this, don't they?
The behavior in the main code is the occasional two failed captures. I only noticed this now, playing around with STM Studio*.
Say normal T delta is 80, then a capture of delta 15 is measured, followed by a capture of The 150 I can understand, it's because the last one was skipped or early. However the early capture confuses me, especially since the EXTIdoes not register this one as being early.
When I disable many other peripherals, the probability of the glitch decreases. Meaning there is something to do with timings.
I'm now seeing clearing the capture flags is superfluous, but the code looks like this:
void TIM3_IRQHandler(void){
IRQ_PROLOGUE();
// Capture channel 1
if(TIM3->SR & TIM_SR_CC1IF){
uint32_t c = sw_extend | TIM3->CCR1;
compute_period(0, c);
TIM3->SR &= ~TIM_SR_CC1IF;
}
// Capture channel 2
if(TIM3->SR & TIM_SR_CC2IF){
uint32_t c = sw_extend | TIM3->CCR2;
compute_period(1, c);
TIM3->SR &= ~TIM_SR_CC2IF;
}
// Capture channel 3
if(TIM3->SR & TIM_SR_CC3IF){
uint32_t c = sw_extend | TIM3->CCR3;
compute_period(2, c);
TIM3->SR &= ~TIM_SR_CC3IF;
}
// Capture channel 4
if(TIM3->SR & TIM_SR_CC4IF){
uint32_t c = sw_extend | TIM3->CCR4;
compute_period(3, c);
TIM3->SR &= ~TIM_SR_CC4IF;
}
// Update (overflow)
if(TIM3->SR & TIM_SR_UIF){
compute_overflow();
compute_frequency();
// Flag ISR complete
TIM3->SR &= ~TIM_SR_UIF;
}
// Trigger
if(TIM3->SR & TIM_SR_TIF){
TIM3->SR &= ~TIM_SR_TIF;
}
// Overcapture (no interrupt)
if(TIM3->SR & (TIM_SR_CC1OF | TIM_SR_CC2OF | TIM_SR_CC3OF | TIM_SR_CC4OF)){
overcapture++;
TIM3->SR &= ~(TIM_SR_CC1OF | TIM_SR_CC2OF | TIM_SR_CC3OF | TIM_SR_CC4OF);
}
__ISB();
IRQ_EPILOGUE();
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
Which looks reasonable to me.
*I am aware of the unstable sample rate of stm studio.
2017-04-19 01:20 PM
Who told you it's easy?
What I said is to cut out pieces from the existing problematic program, those you judge to be irrelevant, down until it's minimal but still exhibiting the problem. There are also other ways to isolate the problem of course. You can try to post portions of the program as it is now, e.g. the ISR alone, but then how do you know the issue is within the posted portion.
> TIM3->SR &= ~TIM_SR_CC2IF;
Don't RMW, do direct write, otherwise you risk missing interrupts, the TIMx_SR bits are rc_w0 for a reason. Besides, the capture flags are cleared by hardware when reading the capture register, so you don't need to do that at all.
Take into account the possiblity the interrupt being invoked simply because of late arrival of a cleared signal into NVIC also in the timer ISR, as you've experineced with the EXTI ISR. Btw., DSB is not a panacea, it's simply a form of time wasting not dissimilar to NOP (although with different timing implications).
JW
2017-04-19 02:02 PM
I am familiar with the basics used to isolate these issues. I just don't practice them a lot because this is my first full greenfield.
Don't RMW, do direct write, otherwise you risk missing interrupts, the TIMx_SR bits are rc_w0 for a reason. Besides, the capture flags are cleared by hardware when reading the capture register, so you don't need to do that at all.
I didn't notice the rc_w0. Great tip. I did indeed notice the superfluous clear.
There is a bit of variety in the peripherals some are write 0 to clear some write 1 clear. I just used the 'standard' way of clearing bit. Force of habit I guess.
2017-04-20 04:46 AM
Posted on April 20, 2017 at 13:46
Is this hardware, or a flaw in my software?
Good news everyone: It is my software.
The probabilty of the event slim. But the problem exists when the ISR handlerhas to handle both capture and overflow flags.
This means on entry of the ISR two things are known:
- Capture x contains a value.
- The counter was reset.
This means that the ISR has to figure out if the capture was before or after the overflow. And that part was missing.
The probability of the event depends on the jitter from IRQ to ISR. And thus on ISR priority and exclusive code.
How to fix this? Add the
if( overflow flag )
part.
if( timer overflow flag ){
// Overflow and Capture in the same handler
if( capture < counter ){
// Capture after overlow. else capture before overflow
set overflow event flag
}
}
if( overflow event flag ){
// Overflow between captures
T = counter_max - previous capture;
T = capture + T;
}else{
T = capture - ch[i].n1;
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
Thanks
https://community.st.com/s/profile/0050X000007vs4BQAQ
for having me look at interrupts priorities and noticing the jitter problem.
Thanks
https://community.st.com/s/profile/0050X000007vqmpQAA
forhaving me notice the need of DMB's and superflous flag clearings.