How to Enable and Disable Interrupts in ARM Cortex-M
To enable or disable interrupts in ARM Cortex-M, use the
NVIC_ISER register to enable and NVIC_ICER register to disable specific interrupts. Additionally, use the __enable_irq() and __disable_irq() intrinsic functions to globally enable or disable all interrupts.Syntax
The ARM Cortex-M uses the Nested Vectored Interrupt Controller (NVIC) to manage interrupts. To enable or disable interrupts, you write to specific NVIC registers:
NVIC_ISER[n]: Interrupt Set-Enable Register to enable interrupts.NVIC_ICER[n]: Interrupt Clear-Enable Register to disable interrupts.
For global control, use intrinsic functions:
__enable_irq();— enables all interrupts globally.__disable_irq();— disables all interrupts globally.
c
/* Enable interrupt number 'IRQn' */ NVIC->ISER[IRQn >> 5] = (1 << (IRQn & 0x1F)); /* Disable interrupt number 'IRQn' */ NVIC->ICER[IRQn >> 5] = (1 << (IRQn & 0x1F)); /* Globally enable interrupts */ __enable_irq(); /* Globally disable interrupts */ __disable_irq();
Example
This example shows how to enable and disable a specific interrupt (e.g., interrupt number 10) and how to globally disable and enable interrupts.
c
#include "stm32f4xx.h" // Example MCU header void enable_interrupt(int IRQn) { NVIC->ISER[IRQn >> 5] = (1 << (IRQn & 0x1F)); } void disable_interrupt(int IRQn) { NVIC->ICER[IRQn >> 5] = (1 << (IRQn & 0x1F)); } int main(void) { // Globally disable interrupts __disable_irq(); // Enable interrupt number 10 enable_interrupt(10); // Globally enable interrupts __enable_irq(); // ... rest of the program ... while(1) {} }
Output
No console output; interrupts are enabled and disabled as per code.
Common Pitfalls
Common mistakes when enabling or disabling interrupts on ARM Cortex-M include:
- Not using the correct bit position for the interrupt number in
ISERorICERregisters. - Forgetting to globally enable interrupts with
__enable_irq()after enabling specific interrupts. - Disabling interrupts globally without re-enabling them, causing the system to stop responding to interrupts.
- Modifying NVIC registers without proper memory barriers or in critical sections, leading to unpredictable behavior.
c
/* Wrong: Using IRQn directly as bit position without masking */ NVIC->ISER[0] = (1 << IRQn); // Incorrect if IRQn >= 32 /* Correct: Mask IRQn to get bit position within register */ NVIC->ISER[IRQn >> 5] = (1 << (IRQn & 0x1F));
Quick Reference
| Action | Register/Function | Description |
|---|---|---|
| Enable specific interrupt | NVIC_ISER[n] | Set bit to enable interrupt number n*32 + bit position |
| Disable specific interrupt | NVIC_ICER[n] | Set bit to disable interrupt number n*32 + bit position |
| Globally enable interrupts | __enable_irq() | Enable all maskable interrupts |
| Globally disable interrupts | __disable_irq() | Disable all maskable interrupts |
Key Takeaways
Use NVIC_ISER and NVIC_ICER registers to enable or disable specific interrupts by setting the correct bit.
Always use __enable_irq() and __disable_irq() to globally control interrupt handling.
Calculate the register index and bit position correctly: register index = IRQn / 32, bit position = IRQn % 32.
Forgetting to globally enable interrupts after enabling specific ones will prevent interrupts from firing.
Avoid modifying NVIC registers without proper care to prevent unpredictable system behavior.