I'm porting a tasking library over to MSP430 and am tossing around ideas for how to perform a task switch. Task is in this context is a simplified thread. Normally these only occur in an interrupt context:
1. Interrupt happens
2. Interrupt handler initiates a context switch (by for example waking a task), which results in a software interrupt.
3. The handler completes, and may wake other tasks before it gets there. At the end, a software interrupt is still pending, and the pending task is the highest priority activated one.
4. The handler RETI's. Now the pending software interrupt is entered immediately when interrupts are reenabled.
5. The SWI handler loads up the pending contexts and RETI's to it.
The critical part here is that in an interrupt context posting an SWI leaves it pending and not executing immediately. And that if there is no context switch there is no additional overhead with regard to saving and loading state. (On ARM Cortex-M this is trivial and there is even an interrupt tail chain optimization for it.)
From a non-interrupt context:
1. The running context saves its state, with an adjusted stored PC (pointing to step 4 below)
2. It sets the pending task and posts an SWI
3. The SWI handler loads up and returns via RETI to the other context
4. When this task becomes active again it continues executing here
Would this work, using DMA channel 7 for example, then:
set DMA7CTL = DMAIFG | DMAIE to post a pending software interrupt (all other bits including DMAEN set to zero).
In the DMA interrupt handler:
Recognize DMAIV == 0x10 as indicating an SWI and perform a context switch.
This would be the easiest. But the documentation isn't clear whether setting IFG actually posts an interrupt...
Or is there an easier way to accomplish the same? Am I missing something?