0
0
Cnc-programmingHow-ToBeginner · 4 min read

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 ISER or ICER registers.
  • 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

ActionRegister/FunctionDescription
Enable specific interruptNVIC_ISER[n]Set bit to enable interrupt number n*32 + bit position
Disable specific interruptNVIC_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.