What is the difference between edge-triggered and level-triggered interrupts? When does each matter?
An edge-triggered interrupt fires on a signal transition — rising edge (low to high), falling edge (high to low), or both. The interrupt controller captures the edge event in a pending flag, and the ISR must clear this flag to acknowledge it. An edge-triggered interrupt fires exactly once per transition, regardless of how long the signal stays at the new level. A level-triggered interrupt fires whenever the signal is at the active level (high or low). As long as the signal remains asserted, the interrupt keeps re-triggering — the ISR must resolve the condition that caused the level assertion (typically by reading a data register or clearing a status flag in the peripheral), or the ISR will re-enter immediately after return in an infinite loop.
Edge-triggered interrupts are appropriate for discrete events: button presses, encoder pulses, communication start-of-frame signals, or any signal where you care about the transition, not the sustained state. The risk with edge-triggered is missed edges: if two edges occur before the ISR can clear the pending flag, only one interrupt is generated. This matters for high-frequency pulse counting — if the ISR takes too long, edges are lost. The EXTI peripheral on STM32 is edge-triggered and captures edges in the PR (Pending Register), which latches until software clears it.
Level-triggered interrupts are appropriate for status conditions: a FIFO has data available (UART RXNE), a DMA transfer is complete, or an error condition persists. The level-triggered model naturally handles the case where the condition has not been resolved — the interrupt keeps firing until the ISR properly handles the source. The critical mistake with level-triggered interrupts is failing to clear the source condition. For example, if a UART RXNE interrupt fires and the ISR clears the NVIC pending bit but does not read the data register, RXNE remains asserted and the ISR re-enters immediately, creating an infinite loop that starves the rest of the system. The fix is always to address the root cause (read the data register to clear RXNE), not just the symptom (the NVIC pending bit).
Source: Interrupts & Priorities Q&A
