Would this affect code inside the main loop that relies on the millis() function since a significant amount of time is spent processing the ISRs?
To put a figure on it for you ...
Frequency of the Timer 0 overflow ISR being called
The code called by the (default) Timer 0 overflow interrupt vector (TIM0_OVF_vect) is used by millis
and micros
to help return their results. Its purpose is to count Timer 0 overflows.
To get accurate results this ISR must not miss an overflow. The timer is configured to tick every 4 µs on a 16 MHz system (because of the prescaler of 64: 64 * 62.5 ns = 4000 ns
) and overflow every 1.024 ms (1024 µs) - because it overflows after 256 ticks ( 4 µs * 256 = 1024 µs
).
Since there is only one overflow flag, if the ISR misses an overflow then both millis and micros will be out by 1.024 ms (or more, if it misses multiple overflows).
To be certain of catching that overflow, the ISR therefore has to be called within 1.024 ms (probably slightly less because of the time taken to enter the ISR, so say: 1 ms).
Interrupt priority
On the Atmega328P (such as used in the Arduino Uno) these are the interrupt vector priorities:
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)
You can see from that list that TIMER0_OVF_vect is number 17 on that list, so any earlier priority interrupt would take precedence, for example external interrupts, pin change interrupts, the other timers (however not SPI / Serial / ADC / I2C).
If an overflow had just happened then you would have practically 2 ms of grace (because you have 1 ms before the next and then another 1 ms before you need to notice it). However if the overflow is about to happen then you only have the 1 ms grace period.
I mention this because if you have an external interrupt 0 event (INT0_vect) and the ISR takes 500 µs, and then external interrupt 1 event (INT1_vect) during that time (so another ISR will be serviced) then the timer interrupt might be blocked for a while.
That is why all ISRs should be short. It isn't good enough that some of them are.
Re-enabling interrupts
I strongly recommend against this. The libraries are not designed to be re-entrant, and once you start enabling interrupts in one ISR you may find that it itself is called again when it is half-way through being called the first time. You may also conceivably interrupt a library function (eg. memcpy) that was not designed for it.
And, of course, if you are re-enabling interrupts inside an ISR because the ISR takes a long time: well, that is the exact situation when you may trigger this re-entrancy.
More information: