Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do interrupts interrupt other interrupts on Arduino?

I have an Arduino Uno (awesome little device!). It has two interrupts; let's call them 0 and 1. I attach a handler to interrupt 0 and a different one to interrupt 1, using attachInterrupt() : http://www.arduino.cc/en/Reference/AttachInterrupt.

Interrupt 0 is triggered and it calls its handler, which does some number crunching. If interrupt 0's handler is still executing when interrupt 1 is triggered, what will happen?

Will interrupt 1 interrupt interrupt 0, or will interrupt 1 wait until interrupt 0's handler is done executing?

Please note that this question specifically relates to Arduino.

like image 685
Chris Laplante Avatar asked Feb 24 '11 22:02

Chris Laplante


People also ask

How do interrupts work in Arduino?

How Does It Work? When the event or interrupt happens, the processor takes immediate notice, saves its execution state, runs a small chunk of code (often called the interrupt handler or interrupt service routine), and then returns back to whatever it was doing before.

How do I use two interrupts in Arduino?

Two push buttons are connected to Arduino Nano at pin D2 & D3. They are used for using two external interrupts, one for turning LED ON and another for turning OFF a LED. Each push button has a pull down resistor of 10k connected to ground.

Can you have multiple interrupts Arduino?

Using Interrupts in ArduinoIf your sketch uses multiple ISRs, only one can run at a time. Other interrupts will be executed after the current one finishes in an order that depends on the priority they have.


2 Answers

On Arduino (aka AVR) hardware, nested interrupts don't happen unless you intentionally create the conditions to allow it to happen.

From avr-lib:

The AVR hardware clears the global interrupt flag in SREG before entering an interrupt vector. Thus, normally interrupts will remain disabled inside the handler until the handler exits, where the RETI instruction (that is emitted by the compiler as part of the normal function epilogue for an interrupt handler) will eventually re-enable further interrupts. For that reason, interrupt handlers normally do not nest. For most interrupt handlers, this is the desired behaviour, for some it is even required in order to prevent infinitely recursive interrupts (like UART interrupts, or level-triggered external interrupts). In rare circumstances though it might be desired to re-enable the global interrupt flag as early as possible in the interrupt handler, in order to not defer any other interrupt more than absolutely needed. This could be done using an sei() instruction right at the beginning of the interrupt handler, but this still leaves few instructions inside the compiler-generated function prologue to run with global interrupts disabled.

(source: http://linux.die.net/man/3/avr_interrupts )

like image 105
gpcz Avatar answered Oct 06 '22 08:10

gpcz


Will interrupt 1 interrupt interrupt 0, or will interrupt 1 wait until interrupt 0's handler is done executing?

Unless you specifically re-enable interrupts inside an ISR (Interrupt Service Routine) then whatever interrupt is currently running completes, plus one more machine code instruction, before the next interrupt is serviced.

Most interrupts set a flag inside the processor, which is checked between instructions, to see if the interrupt should be serviced. Flags are checked in priority order. On the Uno that is:

 1  Reset   2  External Interrupt Request 0  (pin D2)          (INT0_vect)  3  External Interrupt Request 1  (pin D3)          (INT1_vect)  4  Pin Change Interrupt Request 0 (pins D8 to D13) (PCINT0_vect)  5  Pin Change Interrupt Request 1 (pins A0 to A5)  (PCINT1_vect)  6  Pin Change Interrupt Request 2 (pins D0 to D7)  (PCINT2_vect)  7  Watchdog Time-out Interrupt                     (WDT_vect)  8  Timer/Counter2 Compare Match A                  (TIMER2_COMPA_vect)  9  Timer/Counter2 Compare Match B                  (TIMER2_COMPB_vect) 10  Timer/Counter2 Overflow                         (TIMER2_OVF_vect) 11  Timer/Counter1 Capture Event                    (TIMER1_CAPT_vect) 12  Timer/Counter1 Compare Match A                  (TIMER1_COMPA_vect) 13  Timer/Counter1 Compare Match B                  (TIMER1_COMPB_vect) 14  Timer/Counter1 Overflow                         (TIMER1_OVF_vect) 15  Timer/Counter0 Compare Match A                  (TIMER0_COMPA_vect) 16  Timer/Counter0 Compare Match B                  (TIMER0_COMPB_vect) 17  Timer/Counter0 Overflow                         (TIMER0_OVF_vect) 18  SPI Serial Transfer Complete                    (SPI_STC_vect) 19  USART Rx Complete                               (USART_RX_vect) 20  USART, Data Register Empty                      (USART_UDRE_vect) 21  USART, Tx Complete                              (USART_TX_vect) 22  ADC Conversion Complete                         (ADC_vect) 23  EEPROM Ready                                    (EE_READY_vect) 24  Analog Comparator                               (ANALOG_COMP_vect) 25  2-wire Serial Interface  (I2C)                  (TWI_vect) 26  Store Program Memory Ready                      (SPM_READY_vect) 

(Note that Reset cannot be masked).

Conceivably a low-level interrupt might be in progress (eg. TIMER0_OVF_vect). While that is busy doing its stuff multiple other interrupt events might occur (and set the corresponding bits in the CPU). They will be serviced in the above order, not in the order in which they actually occur in time.

There are hardware registers that can be written to, to cancel a pending interrupt - that is, to clear the flag.


The reason for mentioning "one more machine code instruction" is that the processor is designed to guarantee that when it transitions from interrupts not enabled, to interrupts enabled, one more instruction is always executed.

This lets you write code like this:

  interrupts ();             // guarantees next instruction executed   sleep_cpu ();              // sleep now 

Without that, an interrupt might occur before going to sleep. Which means you never wake, because you were relying upon the interrupt occuring during sleep, not before it.


How wonderfully moronic of Freescale and Atmel to both use the very same instruction names, but with inverted meanings

That is why I prefer the mnemonics of interrupts and noInterrupts because the intent there is very clear. These are implemented by defines in the core include files.

like image 43
Nick Gammon Avatar answered Oct 06 '22 08:10

Nick Gammon