I observed that the micros() function is not accurate when called inside an interrupt (Arduino pro 5V 16 mMHz)
The structure of the code is similar to the following:
volatile unsigned long trig_time = 0;
volatile byte trig_flag = 0;
void setup() {
attachInterrupt(0, trig_detected, RISING);
}
void loop() {
if (trig_flag == 1){
// Do some timimg calculations with trig_time
trig_flag = 0;
}
else {
// Do other stuff
}
}
void trig_detected (){
trig_time = micros();
trig_flag = 1;
}
When I use a function generator to send trigger signal at well defined intervals of 100 000 us (100 ms), the timing calculated using the Arduino oscillate randomly between either 99 080 or 98 056us. The Arduino is thus making error of either 1 or 2 ms.
This issue is very similar to a problem recently observed for the Due . This problem was also reported a very long time ago and was reported as fixed since December 2009.
Apparently, the problem resides in the way that the function micros() handles interrupts. The code for micros() in wiring.c appears to be OK as the command cli() should deactivate the interrupts:
unsigned long micros() {
unsigned long m;
uint8_t oldSREG = SREG, t;
cli();
m = timer0_overflow_count;
#if defined(TCNT0)
t = TCNT0;
#elif defined(TCNT0L)
t = TCNT0L;
#else
#error TIMER 0 not defined
#endif
#ifdef TIFR0
if ((TIFR0 & _BV(TOV0)) && (t < 255))
m++;
#else
if ((TIFR & _BV(TOV0)) && (t < 255))
m++;
#endif
SREG = oldSREG;
return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}
I made several tests, and I found that I can solve the problem for my application by simply adding sei() just before the return of the micros() command in wiring.c. This is somewhat surprising for me. My understanding is that adding sei() is not required as the interrupts would be naturally re-enabled and the end of the function.
I am missing something? Is this a bug? Has the way the complier interprets cli() and sei() changed since this function was written?
Thanks.