SoC
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
  • Arm Cortex M3
  • Contact
Reading: Disabling All Interrupts on ARM Cortex-M0
SUBSCRIBE
SoCSoC
Font ResizerAa
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Search
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Have an existing account? Sign In
Follow US
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
© S-O-C.ORG, All Rights Reserved.
Arm

Disabling All Interrupts on ARM Cortex-M0

Holly Lindsey
Last updated: September 14, 2023 1:41 pm
Holly Lindsey 10 Min Read
Share
SHARE

The ARM Cortex-M0 is an extremely popular 32-bit embedded processor used in a wide range of microcontroller units (MCUs). As an ultra low-power processor, the Cortex-M0 is designed to maximize energy efficiency in IoT and industrial applications. When optimizing for low-power usage, it may be necessary to disable peripheral interrupts to avoid waking the processor from sleep modes.

Contents
Purpose of Disabling InterruptsPRIMASK RegisterPRIMASK Register FormatCortex-M0 Interrupt HandlingCortex-M0 Interrupt Priority LevelsDisabling Interrupts with PRIMASKAlternatives to PRIMASKSaving and Restoring PRIMASK StateUsing CMSIS Intrinsic FunctionsEnsuring Compiler AwarenessInterrupt LatencyConclusion

Disabling all interrupts on the Cortex-M0 can be easily achieved by setting the PRIMASK register to 1. The PRIMASK register acts as the priority mask and prevents activation of all exceptions and interrupts when set to 1. This provides a simple method to disable all interrupts without needing to manually disable individual interrupt sources.

Purpose of Disabling Interrupts

There are several reasons why a developer may want to disable all interrupts on a Cortex-M0 processor:

  • Protect critical sections of code from being interrupted
  • Prevent interrupts during flash memory writes
  • Avoid interrupt overhead during time-sensitive operations
  • Maximize low-power sleep mode by blocking wake-up events
  • Simplify debugging by eliminating asynchronous interrupts

Disabling interrupts is key to maximizing sleep mode efficiency. Peripherals such as timers, ADCs, and serial ports can generate interrupts that will wake the processor. By globally disabling interrupts, the Cortex-M0 can stay in deep sleep modes for longer periods of time.

PRIMASK Register

The PRIMASK register is part of the system control block in Cortex-M0 processors. It indicates the minimal priority level for allowed exceptions and interrupts. The PRIMASK register can be set through special register access instructions such as MRS and MSR.

Setting PRIMASK to 1 will mask all interrupts and exceptions. The exception and interrupt priority levels go from 0 (highest priority) to 256 (lowest priority). So by setting PRIMASK to 1, no interrupts or exceptions below priority level 256 will be able to activate.

The PRIMASK register uses bit 0 as the enable/disable bit. When bit 0 is cleared to 0, interrupts and exceptions will function normally based on their priority levels. Setting bit 0 to 1 will disable all interrupts regardless of priority.

PRIMASK Register Format

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 __________________________________________________________________________________________________ | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | P | |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| | |

  • P – Interrupt disable bit
  • x – Unused bits (read as zero, ignore on write)

Cortex-M0 Interrupt Handling

The Cortex-M0 processor implements interrupt handling through the Nested Vectored Interrupt Controller (NVIC). This allows flexible prioritization and vectoring of interrupt sources.

When an interrupt occurs, the processor will suspend execution of the current code and instead execute the Interrupt Service Routine (ISR) associated with the interrupt source. Upon completing the ISR, the processor will return to the original code execution.

The NVIC manages up to 32 external interrupt sources with configurable priority levels. Higher priority interrupts will interupt lower priority code execution. The PRIMASK register controls the threshold above which interrupts are masked.

Cortex-M0 Interrupt Priority Levels

  • Level 0 = highest priority
  • Level 1-3 = reserved for system exceptions
  • Level 4-7 = external interrupts
  • Level 8-14 = more external interrupts
  • Level 256 = lowest priority

Setting PRIMASK to 1 masks all interrupt priority levels. This prevents any interrupt or exception from triggering, since nothing is above level 256.

Disabling Interrupts with PRIMASK

There are a few simple steps needed to disable all Cortex-M0 interrupts using the PRIMASK register:

  1. Include the CMSIS core_cm0.h header file
  2. Add MSR and MRS instructions to set/read PRIMASK register
  3. Set PRIMASK bit 0 to 1 before critical code section
  4. Clear PRIMASK bit 0 to 0 after critical code section

Here is an example code snippet to disable interrupts: #include “core_cm0.h” void critical_function() { // Disable interrupts __asm volatile (“MRS r0, PRIMASK”); __asm volatile (“ORR r0, r0, #1”); __asm volatile (“MSR PRIMASK, r0”); // Critical section of code // Re-enable interrupts __asm volatile (“MRS r0, PRIMASK”); __asm volatile (“BIC r0, r0, #1”); __asm volatile (“MSR PRIMASK, r0”); }

The in-line assembly instructions use the MSR and MRS instructions to set and read the PRIMASK register directly. ORR sets bit 0 to 1 to mask interrupts. BIC clears bit 0 to 0 to re-enable interrupts.

Alternatives to PRIMASK

While the PRIMASK register provides a simple method to disable all Cortex-M0 interrupts, there are some alternative approaches that provide finer control over interrupt masking:

  • BASEPRI – Masks interrupts below a set priority level
  • Interrupt Priority Registers – Change priority of individual interrupts
  • NVIC_DisableIRQ() – Disable specific interrupt vectors

BASEPRI allows you to set an interrupt priority threshold, rather than disabling all interrupts. This allows higher priority interrupts to still occur while masking lower priority sources.

The NVIC interrupt priority registers let you configure the priority of specific interrupt sources. Setting a source to low priority can prevent it from interrupting time-critical code sections.

NVIC_DisableIRQ() can disable individual interrupt vector sources. This provides very fine control but requires more configuration compared to PRIMASK.

Saving and Restoring PRIMASK State

When disabling interrupts, it is important to restore the previous PRIMASK state after finishing the critical code section. This ensures that interrupt behavior returns to normal. uint32_t primask_state; // Save current state __asm volatile (“MRS %0, PRIMASK” : “=r” (primask_state) ); // Disable interrupts __asm volatile (“MOV r0, #1”); __asm volatile (“MSR PRIMASK, r0”); // Critical section // Restore previous state __asm volatile (“MSR PRIMASK, %0” :: “r” (primask_state) );

This code sample shows how to save PRIMASK to a variable, disable interrupts, restore PRIMASK, and ensures proper behavior after the critical section.

Using CMSIS Intrinsic Functions

The CMSIS headers for Cortex-M0 provide intrinsic functions that can be used instead of direct MSR and MRS instructions.

For example: // Disable interrupts __disable_irq(); // Critical section // Enable interrupts __enable_irq();

The __disable_irq() intrinsic sets PRIMASK to 1 to disable interrupts. __enable_irq() clears PRIMASK to 0 to re-enable interrupts.

CMSIS functions like __get_PRIMASK() and __set_PRIMASK() can also be used to save/restore the PRIMASK state if necessary.

Ensuring Compiler Awareness

When using instructions like MSR and MRS to directly access system registers like PRIMASK, it is necessary to ensure compiler awareness. This prevents the compiler from optimizing away the intended operations.

The volatile assembly instructions in the prior examples will prevent unintended compiler optimizations. Intrinsic CMSIS functions also inhibit optimizations.

You can also surround inline assembly with compiler optimization barriers: __asm volatile (“.syntax unified”); // Compiler specific // Inline asm to disable interrupts __asm volatile (“.syntax unified”);

The .syntax unified directives notify the compiler about the use of ARM assembly so code is not optimized incorrectly.

Interrupt Latency

When interrupts are disabled via PRIMASK or other methods, keep in mind that this increases interrupt latency. Any pending interrupts will have to wait until interrupts are re-enabled to be handled.

Leaving interrupts disabled for too long can cause problems:

  • Input data loss if buffers overflow
  • Control system instability
  • Missed timing deadlines

Where possible, use other techniques like BASEPRI masking and priority levels to minimize the duration interrupts are disabled. This helps keep interrupt latency short and system responsiveness high.

Conclusion

The PRIMASK register provides an efficient way to disable all interrupts on an ARM Cortex-M0 processor. Setting bit 0 of PRIMASK masks all interrupt priority levels until it is cleared again.

This allows time-critical code sections to run without being interrupted. However, PRIMASK should be used carefully and interrupts enabled again promptly to minimize latency issues.

Other techniques like BASEPRI priority masking, NVIC register configuration, and CMSIS intrinsic functions can also be used for more advanced interrupt control.

Understanding how to properly disable and re-enable Cortex-M0 interrupts using PRIMASK is key to maximizing efficiency in embedded applications requiring low-power sleep modes or interrupt-free code execution.

Newsletter Form (#3)

More ARM insights right in your inbox

 


Share This Article
Facebook Twitter Email Copy Link Print
Previous Article Difference Between ARM Cortex M0 and M0+
Next Article ARM Cortex M0 Delay Function
Leave a comment Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

2k Followers Like
3k Followers Follow
10.1k Followers Pin
- Sponsored-
Ad image

You Might Also Like

What is the startup code of ARM in C?

The startup code of an ARM processor written in C…

8 Min Read

How to implement atomic operations on multi-core Cortex-M0/M0+?

Atomic operations allow thread-safe access to shared resources without the…

7 Min Read

Can QEMU run on arm?

The short answer is yes, QEMU can run on ARM…

9 Min Read

Arm Cortex M1 Architecture

The Arm Cortex M1 is a 32-bit reduced instruction set…

6 Min Read
SoCSoC
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
Welcome Back!

Sign in to your account