Clarifying millis() function call from an ISR

The attachInterrupt documentation http://www.arduino.cc/en/Reference/AttachInterrupt says that millis() wont work in an interrupt handler. Looking at the millis() function in wiring .c, it appears it will return the most recent millis reading, although it will not be incremented while in the handler.

If this is correct, I suggest the comment changed from:
Note: millis() and delay() won't work in your interrupt-handling function. Any serial data received while in your interrupt-handling function will be lost.

To
Note: delay() won't work in your interrupt-handling function. Any serial data received while in your interrupt-handling function will be lost. Millis() will return the last millis count, but will not continue counting until the handler is exited.

thats interesting, so millis() can be partially used in some sketchs :slight_smile:

So it appears, but lets wait for mellis to share his insight on millis

Updated, thanks.

thats interesting, so millis() can be partially used in some sketchs :slight_smile:

If your interrupts aren't critically time sensitive, I imagine you can re-enable interrupts from within your ISR so that millis() will continue to function. When you jump to an ISR, the global interrupt flag i in SREG is disabled; re-enabling interrupts will allow your ISR to be interrupted by other things like the timer interrupt that's updating millis().

If you do this, just be careful you don't end up with an interrupt that keeps interrupting itself, which would be like infinite recursion and would quickly fill up your stack. You can avoid this by specifically disabling your current ISR source before re-enabling global interrupts.

  • Ben

Millis() will function in the interrupt routine without doing anything to the global interrupt flag. But the underlying tick counter won't increment so using it to delay for any number of milliseconds won't work.

Personally, I don't recommend code that spends a lot of time in an interrupt handler so re-enabling interrupts in the ISR to keep the millis timer interrupting counter going is IMHO something to be avoided if possible.

Ben's advice is good for those with some experience debugging ISRs, but if you are relatively new to embedded programming and don't have experience debugging ISRs, try to find a solution that doesn't involve manipulating the interrupt registers if you can.

Personally, I don't recommend code that spends a lot of time in an interrupt handler so re-enabling interrupts in the ISR to keep the millis timer interrupting counter going is IMHO something to be avoided if possible.

I'd like to second this. In general, when dealing with interrupts, your strategy should be to get out as quickly as possible, though for complex programs things like interrupting interrupts can become the most attractive solution.

Ben's advice is good for those with some experience debugging ISRs, but if you are relatively new to embedded programming and don't have experience debugging ISRs, try to find a solution that doesn't involve manipulating the interrupt registers if you can.

ISRs have been the source of pretty much all of my debugging horror stories. Usually I only use one ISR in any given program I write, and that ISR is devoted to the most time-critical element of the project, which helps to keep the program flow as deterministic as possible. Only under extraordinary circumstances would I re-enable interrupts from within an interrupt. For example, if I need to measure an input pulse width to an accuracy of .4us, I would have a time-critical pin change interrupt. If at the same time I need to capture SPI communication from a master device fast enough so that I know I won't miss any incoming bytes, I'd use an SPI-received interrupt that could itself be interrupted by pin-change interrupts.

  • Ben