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.
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.
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.)
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.
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.