To my surprise, delayMicroseconds() seems to work fine even inside ISR. (knowing that delay() does not)
does millis() and micros() increase as usual while in ISR ?
The reason I ask, is that I came over an bigger app, that is very timer-driven (mstimer2) - and it does also read millis & micros for timing - the only way that can be precise, if both are always running.
delayMicroseconds() works too, and that makes me think it does not use a timer (?)
micros() will return the right value unless timer0 rolls over while you're in your ISR.
Robin2:
You should not stay in an ISR so long that you need delayMicroseconds()
What if you need a short, precise delay? Maybe it isn't the best example but the ISR in the Arduino SoftwareSerial library holds on to the processor for as long as it takes to read a character. At 9600 baud that's about 1 millisecond.
If interrupts are disabled micros() will return a lower value when it rolls over. It would be like trying to tell the time from a stopwatch which has a moving second hand but stuck minute and hour hands. The value micros() returns is essentially the timer0 8-bit count + timer0 rollover count. Without interrupts the latter won't update.
jboyton:
micros() will return the right value unless timer0 rolls over while you're in your ISR.
???
what happens then? does micros() return the wrong value?
micros() returns the hardware timer contents (which updates continuously), plus a count of rollovers (ie. one rollover ever 1.024 mS). It can handle one rollover (the hardware remembers that) so it doesn't matter if you cross a rollover point, however after 1.024 mS it will not know about the second rollover and then will be 1.024 mS out.
Slightly simplified code (removed stuff not for the Atmega328) and with comments:
unsigned long micros() {
unsigned long m;
uint8_t oldSREG = SREG, t; // remember if interrupts were on
cli(); // turn interrupts off
m = timer0_overflow_count; // get overflow count from previous interrupts
t = TCNT0; // get hardware counter
if ((TIFR0 & _BV(TOV0)) && (t < 255))
m++; // increment overflow count if hardware has rolled over
SREG = oldSREG; // turn interrupts back on if needed
return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); // return result
}
It multiplies by 64 rather than 256 because of the way the prescaler is set up (one "tick" every 4 µS).
delayMicroseconds just counts. So it isn't affected by micros() or millis().
Simplified for the 16 MHz boards:
void delayMicroseconds(unsigned int us)
{
// for the 16 MHz clock on most Arduino boards
// for a one-microsecond delay, simply return. the overhead
// of the function call yields a delay of approximately 1 1/8 us.
if (--us == 0)
return;
// the following loop takes a quarter of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2;
// account for the time taken in the preceeding commands.
us -= 2;
// busy wait
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
}
Thus it should work indefinitely. However, of course, the time returned by millis() or micros() subsequently will be out if you delay more than a millisecond (inside an ISR). So it "works" in one sense.
I think it sets the overflow bit when the counter reaches 255, then sets the counter back to zero. There would be a race condition where you detect the overflow, but the counter is still at 255, so you should not use the overflow just yet. Thus by testing for < 255 you are sure that the overflow happened in the past.
In micros() you first read the timer0 counter, then the overflow interrupt flag. If the count is 255 and the flag is set, there's no way to know if the flag was just set by the timer0 counter rolling over to zero in between the two reads or if it was set by a previous rollover at least 1ms ago. So the logic chooses the more likely scenario, that the timer0 rollover interrupts are not being blocked for that long.
I don't understand the 256 in the other code since timer1 is a 16 bit counter. I must be missing something.