SoC
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
  • Arm Cortex M3
  • Contact
Reading: ARM Cortex M0(PGA970) set Primask/disable interrupts
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

ARM Cortex M0(PGA970) set Primask/disable interrupts

Neil Salmon
Last updated: October 5, 2023 9:58 am
Neil Salmon 9 Min Read
Share
SHARE

The ARM Cortex-M0 is an ultra low power 32-bit ARM processor core designed for microcontrollers and deeply embedded applications. It features a reduced instruction set computing (RISC) architecture and a flexible interrupt controller for rapid response to real-time events. The PGA970 is a specific implementation of the Cortex-M0 core by NXP Semiconductors.

Contents
PRIMASK RegisterDisabling Interrupts with PRIMASKUsing PRIMASK in a C ProgramUsing CMSIS FunctionsDisabling Interrupts in C++Using Inline AssemblyDisabling Interrupts with BASEPRIChoosing Between PRIMASK and BASEPRIAdditional Cortex-M0 Interrupt ControlsConclusion

A common need when working with embedded systems like the Cortex-M0 is to temporarily disable interrupts to allow a critical section of code to run without being preempted. On the Cortex-M0, this can be achieved by setting the PRIMASK register to 1, which prevents exceptions from invoking their handlers while it is set. This prevents interrupt service routines (ISRs) from running until PRIMASK is cleared again.

PRIMASK Register

The PRIMASK register is a 32-bit read/write register present in all Cortex-M processors. Setting bit 0 of this register to 1 raises the priority mask to the maximum level, preventing all exceptions with configurable priority from invoking their exception handlers. This prevents interrupt preemption during critical sections of code.

The PRIMASK register can be accessed directly using the MRS and MSR instructions, for example: MRS R0, PRIMASK ; Read PRIMASK into R0 MSR PRIMASK, R0 ; Set PRIMASK to value in R0

Setting PRIMASK to 1 prevents all interrupts and exceptions with configurable priority levels from preempting the processor. Exceptions that cannot be masked, like NMI, HardFault, and escalated FaultMask interrupts, can still be triggered when PRIMASK is set.

Disabling Interrupts with PRIMASK

To disable interrupts temporarily on the Cortex-M0, PRIMASK can be set to 1 before a critical section of code, and cleared to 0 after it completes. For example: MRS R0, PRIMASK ; Read current PRIMASK state CPSIE I ; Globally enable interrupts MOV R1, #1 ; Set mask value MSR PRIMASK, R1 ; Disable interrupts ;; Critical section MSR PRIMASK, R0 ; Restore PRIMASK state

This sequence saves the current PRIMASK state, globally enables interrupts via CPSIE, sets PRIMASK to 1 to disable interrupts, executes a critical section of code, then restores PRIMASK to its original state.

Alternatively, the CPSID I instruction can be used to disable interrupts instead of MSR PRIMASK: MRS R0, PRIMASK ; Read current PRIMASK state CPSIE I ; Globally enable interrupts CPSID I ; Disable interrupts ;; Critical section MSR PRIMASK, R0 ; Restore PRIMASK state

CPSID I sets PRIMASK to 1 internally, preventing exceptions from preempting execution until a matching CPSIE I instruction clears PRIMASK.

Using PRIMASK in a C Program

In C code, PRIMASK can be directly accessed using the special register intrinsics provided by ARM: #include //Device header int main(void) { // Local variable for PRIMASK state uint32_t primask_state; // Read current PRIMASK state primask_state = __get_PRIMASK(); // Enable interrupts __enable_irq(); // Set PRIMASK to disable interrupts __disable_irq(); // Critical section // Restore PRIMASK state __set_PRIMASK(primask_state); }

This saves the current PRIMASK state, enables interrupts globally, sets PRIMASK to disable interrupts for a critical section, then restores the original PRIMASK state.

Using CMSIS Functions

The Cortex Microcontroller Software Interface Standard (CMSIS) provides common APIs across Cortex-M devices. CMSIS functions can also be used to manipulate PRIMASK: #include “stm32xxxx.h” // Device header #include “core_cm0.h” // CMSIS core header int main(void) { // Local variable for PRIMASK state uint32_t primask_state; // Read current PRIMASK state primask_state = __get_PRIMASK(); // Enable interrupts __enable_irq(); // Set PRIMASK to disable interrupts __disable_irq(); // Critical section // Restore PRIMASK state __set_PRIMASK(primask_state); }

This achieves the same result as the previous example, using CMSIS functions.

Disabling Interrupts in C++

For C++ code, PRIMASK manipulation can be wrapped in a class for encapsulation: class InterruptDisable { public: InterruptDisable() { // Save current state state_ = __get_PRIMASK(); // Disable interrupts __disable_irq(); } ~InterruptDisable() { // Restore original state __set_PRIMASK(state_); } private: uint32_t state_; }; int main() { // Disable interrupts for this scope { InterruptDisable disable; // Critical section } // Interrupts restored when disable goes out of scope }

Here a class constructor and destructor are used to disable/restore interrupts for a particular scope. This encapsulates PRIMASK manipulation safely.

Using Inline Assembly

For complete control, PRIMASK can be directly accessed using inline assembly in C/C++ code: // Variable for PRIMASK register uint32_t primask; asm volatile(“mrs %0, primask” : “=r” (primask)); // Read PRIMASK // Enable interrupts __enable_irq(); asm volatile(“cpsid i”); // Set PRIMASK to disable interrupts // Critical section asm volatile(“msr primask, %0” : : “r” (primask)); // Restore PRIMASK

This allows the PRIMASK state to be saved, interrupts enabled, PRIMASK set to disable interrupts, a critical section executed, then the original PRIMASK state restored all in inline assembly for precise control.

Disabling Interrupts with BASEPRI

An alternative to using PRIMASK is to raise the BASEPRI priority mask register. Setting BASEPRI to a non-zero value prevents all exceptions with a priority less than or equal to BASEPRI from invoking their exception handlers.

For example: // Local variable for BASEPRI state uint32_t basepri_state; // Read current BASEPRI asm volatile(“mrs %0, basepri” : “=r” (basepri_state)); // Set BASEPRI to disable interrupts asm volatile(“mov r0, #128”); asm volatile(“msr basepri, r0”); // Critical section // Restore original BASEPRI asm volatile(“msr basepri, %0” : : “r” (basepri_state));

This saves the current BASEPRI value, sets BASEPRI to a priority level that masks all interrupts, executes a critical section, then restores the original BASEPRI state. BASEPRI allows selectively disabling a subset of lower priority interrupts unlike PRIMASK.

Choosing Between PRIMASK and BASEPRI

PRIMASK and BASEPRI both allow interrupts to be temporarily disabled on Cortex-M0 devices like the PGA970. Some key differences:

  • PRIMASK disables all interrupts with configurable priority levels.
  • BASEPRI allows selectively disabling interrupts below a set priority level.
  • PRIMASK disables all faults/exceptions except NMI, HardFault, and escalated FaultMask interrupts.
  • BASEPRI only masks peripheral interrupts, not faults or system exceptions.
  • PRIMASK is simpler and faster to manipulate directly.
  • BASEPRI allows finer gradation of interrupt disabling.

In general, PRIMASK is good for short critical sections that require no interrupts at all. BASEPRI can be used if finer grained interrupt control is needed for medium term critical sections.

Additional Cortex-M0 Interrupt Controls

In addition to PRIMASK and BASEPRI, the Cortex-M0 provides several other mechanisms for interrupt control:

  • FAULTMASK – Generates a HardFault when a configurable fault occurs.
  • CONTROLR – Controls exception behaviors and stack limit checking.
  • SHPR – Configures system handler priorities like SVCall, PendSV, SysTick, etc.
  • AIRCR – Controls priority grouping, preemption, vectored interrupt handling.
  • SCR – Configures SleepOnExit, SEVONPEND, interrupt handling on wake up.
  • ICER/ISER/ISPR – Enable/disable interrupts in the NVIC.

These provide a robust set of tools for managing interrupt response and behavior in the Cortex-M0. PRIMASK and BASEPRI are commonly used for temporary critical sections, while the other registers handle broader interrupt configuration and control.

Conclusion

Temporary interrupt disabling on the Cortex-M0 is critical for protecting access to shared resources and providing atomic operations. PRIMASK and BASEPRI give developers powerful options for disabling interrupts during critical code sections without having to manage interrupt enables/disables individually.

By understanding these registers and the techniques for utilizing them effectively, developers can write Cortex-M0 firmware that robustly handles complex real-time events and constraints. Mastering PRIMASK and BASEPRI usage unlocks the real performance potential of the Cortex-M0 in embedded systems.

Newsletter Form (#3)

More ARM insights right in your inbox

 


Share This Article
Facebook Twitter Email Copy Link Print
Previous Article Faster way of multiplying 2 32-bit numbers giving a 64-bit result in Cortex M0/M0+
Next Article Hard Fault Handler Problem – Cortex-M0+
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 difference between startup code and reset handler?

When an ARM-based microcontroller powers on or resets, the processor…

12 Min Read

Differences between debugging Cortex-M1 and Cortex-M3 processors

Debugging any microcontroller can be challenging, but debugging ARM Cortex…

4 Min Read

How to disable nesting in NVIC Interrupts in ARM Cortex M0+?

The quick answer is that you can disable interrupt nesting…

6 Min Read

How fast is the Arm Cortex-M4?

The Arm Cortex-M4 is a 32-bit processor core designed for…

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

Sign in to your account