How would you debug a system where interrupts seem to be lost or not firing?
Lost interrupts are among the most frustrating embedded bugs because the symptom (nothing happens) gives little diagnostic information. A systematic approach works through the interrupt delivery chain from peripheral to application. Step 1: Verify the peripheral is generating the request. Read the peripheral's status register — is the interrupt flag (e.g., UART RXNE, TIM UIF, EXTI PR) actually set? If not, the peripheral is not generating the event. Check that the peripheral is configured correctly, clocked (RCC enable bit set), and that the trigger condition is actually occurring. Use a logic analyzer to confirm the external signal is present if dealing with GPIO-based interrupts.
Step 2: Verify the NVIC path. Even if the peripheral flag is set, the interrupt must pass through the peripheral's interrupt enable bit (e.g., TIM_DIER_UIE, USART_CR1_RXNEIE), then the NVIC enable register (NVIC_EnableIRQ()), and finally the global interrupt mask (PRIMASK must be clear). Check each link in this chain. A common bug is enabling the NVIC IRQ but forgetting the peripheral-level interrupt enable, or vice versa. Read NVIC->ISPR[] to see if the interrupt is pending but masked — this indicates the NVIC is disabled or a higher-priority ISR is blocking it. Check that the priority level is not accidentally masked by a BASEPRI setting.
Step 3: Check for ISR-level issues. Place a GPIO toggle as the very first instruction of the ISR and monitor it with an oscilloscope. If the GPIO toggles, the ISR is firing — the bug is in the ISR logic, not the interrupt delivery. If it does not toggle, verify the vector table: is the function name correct (spelling must match the startup file's weak alias exactly — TIM2_IRQHandler, not Timer2_IRQHandler), and is the vector table located at the correct address? On STM32, if you relocate the vector table via SCB->VTOR and get the offset wrong, interrupts jump to the wrong address and typically HardFault. Another frequent cause of "lost" interrupts: the ISR fires but does not clear the peripheral flag, so it re-enters infinitely and the system appears to hang rather than miss interrupts. Adding a breakpoint inside the ISR and checking the call count can distinguish between "never fires" and "fires too many times."
Source: Interrupts & Priorities Q&A
