STM32(Cortex-M3架构):如何禁用除指定IRQ外的所有中断?
Got it, let's work through this problem. The issue with __disable_irq() is that it sets the PRIMASK register to 1, which masks all interrupts (except NMI and HardFault) globally—so you can't cherry-pick an IRQ to enable after that call. Here are two reliable approaches to achieve your goal:
Approach 1: Directly Control NVIC Interrupt Enable Registers
This method lets you explicitly disable all IRQs except your target one, and later restore the original state. It's straightforward and works regardless of priority levels.
Step-by-Step Implementation
- Save Current Interrupt State: First, save which IRQs were enabled so you can restore them later.
- Disable All IRQs: Use NVIC's Interrupt Clear-Enable Registers (
NVIC_ICERx) to turn off every interrupt. - Enable Your Target IRQ: Use
NVIC_EnableIRQ()to turn on only the specific IRQ you need. - Restore State Later: When you're done with the restricted state, write back the saved interrupt enable status.
Example Code
// Global variables to store original NVIC state (adjust based on your MCU's ISER count) static uint32_t saved_iser0 = 0; static uint32_t saved_iser1 = 0; #define TARGET_IRQ USART1_IRQn // Replace with your specific IRQ number void enable_only_target_irq(void) { // Lock out interrupts during configuration to avoid race conditions __disable_irq(); // Save current enabled interrupts saved_iser0 = NVIC->ISER[0]; saved_iser1 = NVIC->ISER[1]; // Add more ISER registers if your MCU has them (e.g., ISER2 for STM32F4) // Disable all interrupts NVIC->ICER[0] = 0xFFFFFFFF; NVIC->ICER[1] = 0xFFFFFFFF; // Match the number of ICER registers to your ISER saves // Enable only the target IRQ NVIC_EnableIRQ(TARGET_IRQ); // Re-enable global interrupts (now only target IRQ can trigger) __enable_irq(); } void restore_full_interrupts(void) { __disable_irq(); // Restore original enabled interrupts NVIC->ISER[0] = saved_iser0; NVIC->ISER[1] = saved_iser1; __enable_irq(); }
Notes
- MCU-Specific Adjustments: Different STM32 models have different numbers of
ISER/ICERregisters. For example, STM32F1 has 2, STM32F4 has 8. Check your reference manual to cover all used registers. - Unmaskable Interrupts: NMI and HardFault interrupts can't be disabled—this is a hardware limitation of Cortex-M3, so they'll still trigger regardless of your settings.
Approach 2: Use BASEPRI Register for Priority Filtering
If your target IRQ has a unique priority level, you can use the BASEPRI register to mask all interrupts with a lower priority (higher numeric value) than your target. This is cleaner if you've already configured interrupt priorities properly.
How BASEPRI Works
BASEPRIsets a priority threshold: any interrupt with a priority value greater than or equal to the threshold is masked.- Interrupts with a priority value lower than the threshold (higher priority) will still trigger.
Example Code
// Assume your target IRQ has a preemption priority of 1 (4-bit preemption priority configured) #define TARGET_IRQ_PRIORITY (1 << 4) // Shift left 4 bits to match NVIC IPR register format #define TARGET_IRQ USART1_IRQn void enable_only_high_priority_target(void) { // Set BASEPRI to mask all interrupts with priority >= TARGET_IRQ_PRIORITY // This ensures only our target IRQ (and any higher-priority IRQs) can trigger __set_BASEPRI(TARGET_IRQ_PRIORITY); // Optional: Explicitly enable the target IRQ if it wasn't already NVIC_EnableIRQ(TARGET_IRQ); } void restore_normal_interrupts(void) { // Clear BASEPRI to allow all interrupts again __set_BASEPRI(0); }
Notes
- Priority Configuration: Make sure no other IRQ shares the same priority as your target if you want only that specific IRQ to trigger. If other IRQs have higher priority, they'll still get through—adjust priorities first if needed.
- BASEPRI Limitation: It doesn't affect NMI or HardFault interrupts, just like PRIMASK.
Either approach will work—pick the one that fits your system's priority setup and requirements.
内容的提问来源于stack exchange,提问作者LOSnel

