Inside each block in a chip is an interrupt module that monitors signals from multiple interrupt sources within the block. These interrupt sources can be from state machines, counters, combinatorial logic, external signals, or other such sources. When an interrupt source asserts, it triggers the interrupt module to latch the event, generating an interrupt (directly or indirectly) to the CPU.
Interrupt modules come in two flavors: level-triggered or edge-triggered. Because there are different usages of those terms, let me define them.
A level-triggered interrupt module generates an interrupt when and while the interrupt source is asserted. If the interrupt source is still asserted when the firmware interrupt handler acks the interrupt, the interrupt module will regenerate the interrupt, causing the interrupt handler to be invoked again. This is not good if the interrupt source can potentially stay asserted for a long time.
Level-triggered interrupts force firmware engineers to take into account what is generating the interrupt source. If the interrupt source is just a pulse from a state machine, then the device drivers do not need to do any additional work. If the interrupt source is asserted when a counter equals zero, the device driver must first write a non-zero value to the counter before it can ack the interrupt. If the interrupt source is a signal from a different block with its own device driver or an external device under its own firmware control the device driver has no control over when the interrupt source is cleared. Its only choice is to disable that interrupt so that it can exit the interrupt handler. But then how does the device driver know when to re-enable the interrupt? Does it keep polling to see if the signal is deasserted yet? How often should it poll? What if the interrupt source deasserts then reasserts again since the last poll? An interrupt would have been missed. What if the external interrupt source deasserts sooner sometimes and later other times? These issues make level-triggered interrupts cumbersome for firmware.
On the other hand, edge-triggered interrupt modules can be acked immediately, no matter how the interrupt source behaves. The type of the interrupt source does not matter. It can be a pulse, a firmware-clearable signal, or some external signal that eventually is cleared somehow.
Edge-triggered interrupts keep firmware’s code complexity down, reduce the number of conditions firmware needs to be aware of, and provide more flexibility when interrupts are acked. This keeps development time down and quality up.
I see no benefit to level-triggered interrupts. Some engineers prefer level-triggered interrupts because they require fewer gates or because of hardware and firmware advantages when multiple interrupt sources share the same interrupt. But those advantages do not outweigh the additional complexity for firmware. And those advantages can be designed into an edge-triggered setup. If you believe otherwise, let me know and I’ll put your comments in the next newsletter.
Since level-triggered interrupts do exist, then no matter which triggering is used, specify the triggering in the block’s document. Firmware engineers will then know what needs to be taken into account. For level-triggered interrupt modules, clearly specify when and how the signal will deassert.
Until the next edge-triggered issue…