SoC
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
  • Arm Cortex M3
  • Contact
Reading: Utilizing Dual Stack Pointers (MSP and PSP) Without an RTOS
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

Utilizing Dual Stack Pointers (MSP and PSP) Without an RTOS

David Moore
Last updated: September 21, 2023 11:29 am
David Moore 6 Min Read
Share
SHARE

ARM Cortex-M processors provide two stack pointers, the main stack pointer (MSP) and process stack pointer (PSP), that enable dual-stacked operation without requiring an RTOS. This allows developers working on bare-metal embedded projects to take advantage of the flexibility and power of dual stacking while avoiding the complexity and overhead of an RTOS.

Contents
Introduction to Dual StackingBenefits of Dual Stacking Without RTOSImplementing Dual Stacking1. Defining Stack Arrays2. Initializing the Stack Pointers3. Creating Threads4. Context Switching5. SVCall for Thread APIsConclusion

Introduction to Dual Stacking

Dual stacking refers to the ability to have two separate call stacks in a system – one for privileged threads and one for unprivileged threads. The MSP points to the privileged stack while the PSP points to the unprivileged stack. When code executes in privileged mode, the processor uses the MSP. When code executes in unprivileged mode, the processor uses the PSP.

This enables multiple threads to run independently without interfering with each other’s stack space. It also allows switching between threads safely and efficiently by simply changing which stack pointer is active on context switch.

Benefits of Dual Stacking Without RTOS

Using dual stacking without an RTOS provides several key benefits:

  • Avoids RTOS complexity and overhead – No need to integrate and maintain a heavy OS.
  • Full control and customization – Stack sizes, switching logic, APIs can all be fully customized.
  • Optimized for application needs – Only features needed can be implemented unlike generic RTOS.
  • Reduced memory requirements – An RTOS can consume significant RAM and flash.
  • Easier to certify – RTOS certification introduces significant overheads.

Implementing Dual Stacking

The key steps to implement dual stacking without an RTOS are:

  1. Define two stack arrays – one for MSP and one for PSP.
  2. Write MSP and PSP initialization code.
  3. Create privileged and unprivileged thread code.
  4. Implement context switching logic.
  5. Use SVCall handler for thread requests.

1. Defining Stack Arrays

The first step is to define arrays for the MSP and PSP stacks in memory. These should be declared globally or statically allocated. Typical stack sizes range from a few KB to 16+ KB depending on application needs. /* Privileged stack */ static uint32_t msp_stack[MSP_STACK_SIZE]; /* Unprivileged stack */ static uint32_t psp_stack[PSP_STACK_SIZE];

2. Initializing the Stack Pointers

The stack pointers need to be initialized before creating threads. This is typically done in the reset handler before jumping to main(): void Reset_Handler() { /* Initialize the MSP */ __set_MSP((uint32_t)msp_stack + MSP_STACK_SIZE); /* Initialize the PSP if using it for threads */ __set_PSP((uint32_t)psp_stack + PSP_STACK_SIZE); /* Rest of reset handler code… */ /* Jump to main */ main(); }

3. Creating Threads

Thread functions for both privileged and unprivileged need to be defined. These should contain an endless loop with thread logic: /* Privileged thread */ void priv_thread() { while(1) { /* privileged thread code… */ } } /* Unprivileged thread */ __attribute__((naked)) void unpriv_thread() { __asm( ” MOVS R0, #1\n” ” MSR CONTROL, R0\n” ); /* unprivileged thread code… */ /* Privileged function call */ __asm( ” SVC #1\n” ); }

The unprivileged thread uses inline assembly to drop to unprivileged mode before executing main logic. The __attribute__((naked)) attribute prevents compiler optimizations that could corrupt state when switching modes.

4. Context Switching

To actually switch between threads, the PSP needs to be updated to point to the next thread’s stack on context switch: /* Privileged function to context switch threads */ void switch_context() { /* Save current context onto current stack */ push_registers_on_stack(); /* Update PSP to new stack */ __set_PSP(new_stack_address); /* Restore context of new thread */ pop_registers_from_stack(); }

The switch can be triggered by a timer interrupt, event flag, or other mechanism to initiate a context switch.

5. SVCall for Thread APIs

Since unprivileged threads cannot call privileged functions directly, the SVCall interrupt can be used to safely transition to privileged mode and provide a thread API: /* Privileged function to kill a thread */ void kill_thread(int id) { /* Kill thread logic */ } /* Unprivileged thread requests thread kill */ __asm(“SVC #1”); // SVCall with ID #1 /* SVCall Handler */ void handle_svc() { if(id == 1) { kill_thread(thread_id); } }

This allows abstracting privileged functions into APIs usable by unprivileged threads.

Conclusion

Implementing dual stacked operation on Cortex-M without an RTOS provides a flexible approach to gain the benefits of multithreading while minimizing complexity and overhead. With careful management of the MSP and PSP stack pointers along with robust context switching logic, developers can fully utilize the dual stacking capabilities of Cortex-M processors in embedded and IoT applications.

Newsletter Form (#3)

More ARM insights right in your inbox

 


Share This Article
Facebook Twitter Email Copy Link Print
Previous Article Determining Stack Requirements When Using an RTOS on Arm Cortex-M
Next Article Stack Limit Checking in Arm Cortex-M for Stack Overflow Detection
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 Voltage of ARM Cortex M0?

The ARM Cortex-M0 is a 32-bit RISC processor core designed…

10 Min Read

ARM cross compiler toolchain

An Arm cross compiler toolchain allows developers to compile code…

6 Min Read

Relocate the Vector Table in Cortex-M0

The vector table is a key component in Cortex-M0 microcontrollers…

9 Min Read

What is Nested Vector Interrupt Control (NVIC)?

The Nested Vectored Interrupt Controller (NVIC) is the interrupt controller…

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

Sign in to your account