How to Switch the Stack Pointer to PSP for an STM32F407G Microcontroller Board in C

STM32F407G discovery board

In this article, we show how to switch the stack pointer to PSP STM32F407G microcontroller discovery board.

PSP stands for the process stack register.

According to the generic user manual for the Cortex-M4 processor, in an OS environment, ARM recommends that threads running in Thread mode use the process stack and the kernel and exception handlers use the main stack.

The Process Stack Pointer (PSP) is an alternate stack pointer that can only be used when the processor is in thread mode. It is usually used for application tasks in embedded systems and embedded operating systems.

For example, we may use PSP to create a scheduler that executes tasks in our program in a round robin fashion over and over again in a specific order.

PSP can be used for user applications such as task scheduling such as that.

PSP is one of the core registers of the Cortex-M processor.

In order to switch from the MSP to the PSP, you first must initialize the PSP to a valid stack address. PSP, by default, has no value assigned to it unless it is initialized by the programmer to a valid stack address. You then must set bit 1, the SPSEL bit, of the CONTROL register of the Cortex-M4 processor to 1. Once this bit is set to 1, the current stack pointer is now PSP. The only thing after this that you must do is return control back to the main program. After this, all stack memory is now tracked with the PSP instead of the MSP.

So both the PSP and the CONTROL registers are special registers of the Cortex-M4 processor.

We cannot directly access these registers using the C programming language, because they are special registers and are not memory mapped.

In order to have access to these registers, we must use in-line assembly.

Below is code that changes the stack pointer to the PSP.

So let's now go over the code.

So the first thing we do is create a function that allows for the switch of the stack pointer from the default MSP to PSP.

The MSP and the PSP are core registers of the Cortex-M4 processor. Therefore, they can only be accessed via in-line assembly code; they cannot be accessed with C code.

We create this function as a naked function. A naked function treats the code as pure assembly and, therefore, does not add any unwanted items to the code.

So the function is change_sp_to_psp()

This changes the SP (Stack Pointer) register to PSP (Process Stack Pointer).

The first thing we must do is initialize the PSP register.

We have to initialize the PSP register to the address you want it to start from. In order to use PSP, you must initialize it to a valid address.

We create the assembly version of a macro and set SRAM_END equal to, (0x2000000 + (128 *1024))

SRAM starts at the address, 0x2000000

The STM32F407G board has 128KB of SRAM. Therefore, the end of the SRAM is at, (0x2000000 + (128 *1024))

We want to reserve the end of SRAM and have 512 bits (or a half of a 1KB) for the MSP.

After this, we want the PSP to start from 512 bits after the end of the SRAM.

Therefore, we create another name, STACK_PSP_START, and set it equal to, (SRAM_END - 512)

We then use the LDR (load) instruction to initialize R0 to the value of STACK_PSP_START through the line, __asm volatile("LDR R0,=STACK_PSP_START");

The LDR instruction is what you want to use because it allows for the initialization of a register of 32 bits. The MOV instruction is for 16 bits of data or less.

Now that we have initialized R0, it is time to move its value to PSP.

The MSR instruction moves data from an ARM register to a special register, which in this case is PSP.

Now PSP is initialized.

If you debug this code and step through it, you will see that the PSP register is now initialized.

Now one thing you need to know is the CONTROL register of the ARM Cortex-M4 processor.

By setting bit 1, the SPSEL bit of the CONTROL register, to 1, we are able to make the PSP register the current stack pointer.

This is shown in the diagram below.

Cortex-M4 CONTROL register bit assignments

Since we want to set bit 1 to 1, we feed R0 to 0X02

0x02 is hexadecimal for the binary value of 10

We then use the MSR instruction again and move its value to the CONTROL register.

This makes the current stack pointer PSP.

If you debug and step through this code, the SP register will now change to the value of the PSP.

If you go to the Window tab and select Show View and select Registers, you can see this.

This is shown in the following image below.

SP, MSP, PSP register values in STM32 software

You can see that the SP (current stack pointer) is now equal to the value of the psp register. The msp register is a different value.

The last line we need in our function is, __asm volatile("BX LR");

This allows the return back to the main() function.

The LR register stores the address to return to in the main() function after this function is complete. The value in the LR register is copied to the PC register, so the program knows to go back to in the main() function.

So we now have a program where the current stack pointer is now the PSP.

If you want to now force a return back to MSP, you can provoke a system exception or an interrupt, which will force the SP back to MSP. This is because MSP is always the stack pointer after a system exception or interrupt.

This is done in the following code below.

The code above adds a system exception after the stack pointer is PSP. This changes the stack pointer back to MSP.

So this is how to switch the stack pointer to PSP in an STM32F407G microcontroller board.

Related Resources

HTML Comment Box is loading comments...