# Load and store CPU registers in application context

I just recently started working with a bare STM32F103C8T6 (an ARM Cortex M3) and ran into some difficulties.

I have set up a SysTick_Handler to switch the current context of the application. The handler invokes a PendSV_Handler in which I want to save the registers of the CPU to a datastructure. This is the simplified code:

typedef struct Registers {
int r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12;
int sp, lr, pc, xPSR;
} Registers;

void PendSV_Handler()
{
Registers reg;

register int r0 asm("r0");
reg.r0 = r0;
/* and so on with all other registers */
}


However while testing the inline asm I ran across an issue. I adapted my handler like this:

void PendSV_Handler()
{
asm volatile(
"movw r0 100"  // This should store the integer 100 in register r0
);

register int temp asm("r0");  // This should store the value in
// register r0 into temp

toggleLED();     // Toggles an LED to visualise the behavior
delay_ms(temp);  // Delays the execution by [temp] ms, known to work
toggleLED();
}


Now the problem is that the LED to be toggled only switches on once and then stays stuck. Also in the SysTick_Handler another LED is toggled with SysTick-frequency, which also stops toggling after the first PendSV call. I know that they have the same priority, which is why I conclude, that the Tick-LED is stuck, because the delay is way too long and this lets me conclude, that the value from the register is not stored correctly. Did I miss out on how to store data from CPU registers or is there another flaw in my conclusions?

• 100 ms is a very short time. – Eugene Sh. Jun 5 '17 at 17:22
• You may want to show toggleLED(). Are you using any optimizations? (ie: did you forget to assign an LED state variable as "volatile" or possibly as "static" if declared within the function?) – Tut Jun 5 '17 at 17:23
• @StainlessSteelRat Not a random value, doesn't the assignment of the value 100 work how I thought it would (i.e. being stored in register r0)? – flashingx Jun 5 '17 at 17:25
• @Tut The problem lies not within the toggleLED function. I am able to see it if I manually enter 100 as an argument. The whole program is much more complicated, but I am sure it is the asm part, that doesn't work as I expect. – flashingx Jun 5 '17 at 17:27
• Have you tried disassembling the compiled code? (Try the -S compiler option if gcc) – pjc50 Jun 5 '17 at 18:08

I am not sure if you are aware the logic already stores the state of the machine during an event/interrupt. If you want to use this to task switch you need to remove/re-build the stack to account for the switch. You may want to pull that information and save it for the switch back sure.

Take a look at Atomthreads or FreeRTOS or others to see how to do a complete task switch in a Cortex-M (it is not like other processors where you take control of the registers and change the return address. For starters, the "return address" in LR from an event/interrupt is not a valid address -- "Cortex-M3 Devices Generic User Guide: Exception entry and return").

• I know that the Cortex-family stores r0-r4 plus some other registers on the stack, so I have to store the others like this. I also know, that I have to pop said registers from the stack and push others to be loaded by the exception return. Thank you for the Wikipedia link, I found one to have a really good documentation. – flashingx Jun 6 '17 at 7:56

in the SysTick_Handler another LED is toggled with SysTick-frequency, which also stops toggling after the first PendSV call. I know that they have the same priority

If SysTick and PendSV have the same priority, then SysTick_Handler will not be invoked again until PendSV_Handler returns. That's a problem because delay_ms() usually depends on SysTick_Handler updating a counter. That will never happen, therefore your program will hang there.

Using delay_ms() in an interrupt handler is a bad idea, but if you'd like to have it there for testing purposes, then make sure that SysTick_Handler has higher priority than any interrupt using delay_ms(). (Or modify delay_ms() to use a hardware timer.)

• The delay method is not using timers, but what you mentioned is what I concluded. As the PendSV takes longer than until the next SysTick interrupt is due, the SysTick_Handler is not invoked. – flashingx Jun 6 '17 at 8:42