Causing an I2C interrupt inside a D2 interrupt

I recognise that by default interrupts do not run inside interrupts, but I also know that there are lines of AVR code which one can include within a sketch to enable interrupts or disable them at points where they would not normally be enabled/disabled. I also know that I2C is pretty low down (25th) in priority on standard arduino uno atmega328p devices.

I wanted to ask about allowing I2c Interrupts to occur within a D2 pin (2nd priority) interrupt.

Inside an interrupt interrupts are usually disabled but the flags for interrupts can still be set. I can perhaps clear other flags within the interrupt if this helps avoid priority issues. I can also use

EIFR = 1; // clear flag for interrupt 0 (D2 on Uno)

to ensure that the d" interrupt doesn't run a second time immediately afterwards.

Is doing this feasible or are there unforeseen complicatons likely to occur? I can understand the chaos that can occur if an interrupt allows it's own types of interrupts inside it, but in the case of an I2C interrupt (either the receive or getting requested from type, assuming the uno is a slave I2c device) what could generally go wrong, so long as I'm happy to accept some risk that the d" interrupt might not run quite as desired every time but outweighed by the I2C interrupt always working properly.

I'm not sure whether the default I2C library for the arduino has dependencies on any other interrupts (timing perhaps?), if so is it feasible to also enable those necessary interrupts within a D2 interrupt?

I have looked over and while it discusses enabling interrupts within interrupts it doesn't seem to give any information specific to I2C.


Let us make a quick review of the Interrupt Process of the ATmega328P MCU:

1. There are in total 26 sources of interrupts in the ATmega328P MCU. The interrupts have priorities ; where, an interrupt with lower vector has the higher priority in terms of rendering services. For example, 'External Interrupt Request 1 (INT1) with vector 0x0004' at PD3-pin has the higher priority than the 'I2C Serial Interface Interrupt with vector 0x0030'. 'External Interrupt Request 0 (INT0) with vector 0x0002' at PD2-pin has the higher priority than the INT1 and I2C interrupts.

2. Every interrupt (except the RESET interrupt) is associated with an interrupt enable bit known as local interrupt control flag; it (when active) helps the programmer to tell the MCU that the interrupt in question should be given services. However, there are issues to be considered when another interrupting device is present in the network.

3. The MCU is equipped with another interrupt enable bit known as global interrupt control flag (I-bit of SREG Register); it (when inactive) helps the programmer to tell the MCU that none of the interrupts of the network will receive services.

4. Assume that we have three interrupts in the network: INT0, INT1, and I2C; local interrupt and global interrupt control flags are active.

5. Let us assume that INT1 has happened. The MCU finishes the current instruction of the Main Line Program (MLP), saves the return address on the Stack, disables the global interrupt control flag (puts 0 into I-bit), and then goes to the ISRINT1 (Interrupt Service Routine due to INT1 interrupt). What will happen if I2C interrupt occurs when ISRINT1 is in progress? Because the global interrupt control flag (I-bit) is at disabled state, the interrupt logic of the MCU will not notice the I2C interrupt; the interrupt will simply be ignored. What will happen if the user activates the I-bit just after arriving at the ISRINT1? Because the I2C interrupt has the lower priority than INT1, the MCU will ignore the I2C interrupt.

6. What will happen if INT0 interrupt occurs when the ISRINT1 is in progress. Because the I-bit is at inactive state, the MCU will ignore the INT0 interrupt though it has higher priority than INT1. What will happen if the user activates the I-bit just after arriving at the ISRINT1? Because the INT0 interrupt has the higher priority than INT1, the MCU will suspend the ISRINT1 and will enter into ISRINT0. The MCU will finish the ISRINT0 and then it will resume ISRINT1. After the completion of ISRINT1, the MCU will resume the MLP.

So you're saying that even with disabling the D2 interrupt within the D2 interrupt's routine, and clearing the D2 interrupt fag, then enabling the I2C interrupt then turning interrupts back on the chip will attempt to run another D2 interrupt from within the first D2 interrupt before it is willing to run an I2c Interupt in there?