STM32 gotchas
16. Interrupt does not fire (some troubleshooting hints)

What to do, when interrupt is enabled in a program, but the Interrupt Service Routine (ISR) does not run?

As usually, the most straighforward method is to follow the path of execution in hardware, i.e. in the mcu itself. This is contrary to the usual wishes of the novices, who don't want to go beyond the comfort of the IDE and software-writing process, using some sort of "libraries". Sorry, but that's not how it works, the mcu does not care about libraries nor software.

One more "inconvenience" is, that successful debugging requires understanding of the underlying mechanisms, which is achieved by reading the available documentation. For interrupts, this involves the Reference Manual (RM), mainly Interrupts and Events chapter (in some newer RM named differently, or even split e.g. into Nested vectored interrupt controller (NVIC) and Extended interrupts and events controller (EXTI) chapters); plus the chapter related to the particular peripheral from which the particular interrupt signal originates. However, the real working of NVIC is not described there, as it is part of the processor/core, so the related Programming Manual (PM) has to be consulted (and perhaps other related ARM material). And, note, that from ARM's point of view, interrupts fall into the somewhat broader group of "exceptions", so you want to read everything about "exception priorities" there.

As usually, the most convenient tool to use is the built-in debugging facility plus the associated external hardware (debugging "pod") and software (often IDE, sometimes bare gdb with associated interfacing layer (like openOCD) or other similar tools). The following lines are written mostly with this method in mind. However, as usually, this is not a necessity, the good programmer has a whole range of tools and methods at hand - some of them avoiding the issue that the original problem may actually be caused by the built-in debugger being intrusive to a certain extent.

Here are some steps to contemplate:

Also note, that the debugger will usually prevent interrupts being invoked, while single-stepping.


1. Users of C++ often don't realize, that in C++ function names are mangled by the compiler, so the linker cannot match the name in the vector table to the user-written ISR and falls back to the default "weak" handler, usually implemented as an empty infinite loop. The canonical way to avoid name mangling in C++ is to enclose the given function (ISR) into extern "C"{} block:

extern "C" {
    void TIM2_IRQHandler() {
      [...]
    }
  }