I am writing some software that processes multiple types of events in realtime. Therefore, I have several interrupt service routines defined: UART_TX, UART_UDRE, ANALOG_COMP, and some timer comparisons. Occasionally, in response to an event which has triggered one of the interrupts, the software must do some fairly costly computation. For example, in response to the ANALOG_COMP event, a costly "rule matching" operation must sometimes occur, and this takes ~10 microseconds. This "rule matching" operation can occur a maximum of once per ~1400 microseconds.
Currently, my software is structured such that the interrupts execute as quickly as possible, placing some data in a buffer and then returning. The more costly processing happens in the course of the main loop. However, I would like the relevant processing to occur immediately after the triggering interrupt has occurred. Since the "heavier processing" occurs relatively infrequently, it seems appropriate to move this processing into the triggering interrupt. Of course, this would require that I allow re-entrant interrupts. So I have some questions about re-entrant interrupts and how best to handle them.
- Is it correct that if I declare the ISRs with the ISR_NOBLOCK macro, interrupts are disabled briefly, but then re-enabled? What assembly is emitted as part of the ISR when using ISR_BLOCK versus ISR_NOBLOCK? I see that I can also declare the ISR with ISR_NAKED. This way, am I able to never suspend processing of interrupts, as opposed to disabling and then immediately re-enabling the global interrupt enable flag as is the case with ISR_NOBLOCK? The ave-libc docs say, "the user code is responsible for preservation of the machine state including the SREG register, as well as placing a reti() at the end of the interrupt routine?" Is everything that I need to do to "preserve the machine state" included in the assembly emitted as part of the ISR when using ISR_BLOCK or ISR_NOBLOCK?
- I have been cautioned against immediately re-enabling interrupts in certain ISR vectors, such as the UART interrupts. If I set (or never disable) the global interrupt enable flag before reading UDR0, for example, will my code recurse infinitely? If so, is the way to handle this by disabling the relevant UART interrupts, then enabling interrupts globally? Is there a similar infinite loop gotcha with the analog comparator or timer interrupts?
Any advice on this would be greatly appreciated.