Context switching on Arduino Zero

Hi Dude,

I've Arduino Zero board and try to learn about ARM context switching feature.

I understand that ARM Context-M0 has two separate stack pointers (main and process stack pointers) for privilege/unprivileged thread mode.

This feature is mainly used in multitasking like RTOS, but it's too complicated for me to understand the feature and how it works.

Can someone please guide me how to get started for this feature with simple examples?

Best regards,
Pak

The multiple stack pointers are normally a separate thing from a “context switch.” Most arm Cortex apps and even rtoses stay in privileged mode all the time.

Thanks for reply.

Is there any example for this feature? I've learnt avr interrupt subroutine (ISR) background/foreground applications, but come to arm cortex switching, it still new and cannot figure out where to start.

Best regards,
pak

Are you looking to understand ISRs, or are you looking to understand context switching for the purposes of an RTOS?

I'm trying to understand context switching for purpose of rtos.

Best regards,
Pak

In general, the multiple stack pointers available on ARM cortex-m chips are a bit of a red herring WRT context switching. The usual case is to never enter "unprivileged mode", and to always use the Main SP.

The general strategy is that each task has its own stack - an area of memory somewhat unrelated to the Stack Pointer. A task will be running along with the MSP pointing into its particular stack memory, when suddenly a SysTick comes along and it's time to switch to a different task. That will result in an interrupt, which will save some important parts of the context on the current stack.
To switch tasks, you save "the rest" of the context on that stack, load a different task's stack pointer pointing to a different stack, and then let the context for that task restore. You've then switched context to the new task.

If you're using both stack pointers, the SP switches after the hardware-initiated saves, and you have to go to additional effort to save the rest of the context via the PSP rather than the (current) MSP. (Ditto for restoring context.)

There was an EdX MOOC by John Valvano (et al) at UTexas Austin that covered ARM-CM3 context switching pretty well (the CM0 should be very similar.) It turns out that this was largely based on a live UT class, whose lectures and class materials are also online. I don't recall whether they specifically cover using PSP or unprivileged modes. There was a prior class in embedded systems that covered a lot of ARM architecture stuff that was also pretty neat.
I'm also not sure whether these classes are offered "continuously" now, or whetheryou have to wait for a specific date to roll around. For the initial classes, the online community/forum of people taking the class at the same time was a big asset.

Valvano is quite the character; fun to listen to, and the EdX class went to a lot of effort to come up with labs that student could do at home, given standard hardware (a TI Launchpad, but there's no reason it couldn't work on an Arduino.)

EdX class covering ARM CM3 RTOS Concepts
Lectures from the in-person class. (You want Lectures 3 and 4, I think.)
Video of live class
Intro class on Embedded systems using ARM.

To switch tasks, you save "the rest" of the context on that stack, load a different task's stack pointer pointing to a different stack, and then let the context for that task restore. You've then switched context to the new task.

Thanks, westfw, that give me some idea of context switching.

In Arduino UNO (AVR), saving critical register(s) to get the data "atomically" in wring.c as follow:

unsigned long millis()
{
 unsigned long m;
 uint8_t oldSREG = SREG;  //save the current SREG (status register)

 // disable interrupts while we read timer0_millis or we might get an
 // inconsistent value (e.g. in the middle of a write to timer0_millis)
 cli();
 m = timer0_millis;
 SREG = oldSREG;    //restore the SREG (status register)

 return m;
}

In Arduino Zero (ARM), how can I save the critical register(s)? I can't see anything from wring.c, maybe somewhere else.

My objective is not to create and understand the whole rtos, just to understand context switch to get the data "atomically" or to save the critical register(s) during two or more interrupts racing.

Best regards,
pak

The millis() code for SAMD doesn't have the "atomicity" code because it has 32bit memory and registers, so the load of timer0_millis (or equiv) is inherently atomic (whereas on AVR, you're looking a 4 separate load operations.)

You can do critical sections in the same general way - completely disable interrupts and re-enable them when you're done, with code like I used here: SAMD10-experiments/ticker_rtc.c at master · WestfW/SAMD10-experiments · GitHub
ARM has additional features for setting interrupt priorities, implementing locks and exclusive access, and similar, most of which I don't understand. In the simplest case, you'd leave all your interrupts at the same priority level, and then doing context switches inside of an ISR (systick or pendsv, for example) would automatically have stopped other interrupts.

CpuEnterCritical() you wrote:

#define CpuEnterCritical() \
  do { \
    asm ( \
 "MRS   R0, PRIMASK\n\t" \
 "CPSID I\n\t" \
 "STRB R0, %[output]" \
 : [output] "=m" (cpuSR) :: "r0"); \
  } while(0)

#define CpuExitCritical() \
  do{ \
    asm ( \
 "ldrb r0, %[input]\n\t" \
 "msr PRIMASK,r0;\n\t" \
 ::[input] "m" (cpuSR) : "r0"); \
  } while(0)

In Arduino Zero, I found these codes below [cmsis_gcc.h]:

__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_irq(void)
{
  __ASM volatile ("cpsie i" : : : "memory");
}
__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_irq(void)
{
  __ASM volatile ("cpsid i" : : : "memory");
}

So CpuEnterCritical(), CpuExitCritical() in SAMD10 and __enable_irq(void), __disable_irq(void) in SAMD21, are they doing the same feature?

Best regards,
pak