Открыл вот порт FreeRTOS на Cortex-M4.
В этой RTOS переключатель контекста построен по следующей модели:
1. Сохранить контекст прерванной задачи;
2. Переключить указатель на контекст новой задачи;
3. Восстановить регистры из этого контекста.
Все 3 пункта выполняются в обработчике исключения PendSV.
Для того, чтобы начать выполнение, нужно как-то запустить первую задачу.
FreeRTOS предлагает решение на исключении SVC
Код
__asm void prvStartFirstTask( void )
{
PRESERVE8
/* Use the NVIC offset register to locate the stack. */
ldr r0, =0xE000ED08
ldr r0, [r0]
ldr r0, [r0]
/* Set the msp back to the start of the stack. */
msr msp, r0
/* Clear the bit that indicates the FPU is in use in case the FPU was used
before the scheduler was started - which would otherwise result in the
unnecessary leaving of space in the SVC stack for lazy saving of FPU
registers. */
mov r0, #0
msr control, r0
/* Globally enable interrupts. */
cpsie i
cpsie f
dsb
isb
/* Call SVC to start the first task. */
svc 0
nop
nop
}
Сам обработчик
Код
__asm void vPortSVCHandler( void )
{
PRESERVE8
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r1, [r3]
ldr r0, [r1]
/* Pop the core registers. */
ldmia r0!, {r4-r11, r14}
msr psp, r0
isb
mov r0, #0
msr basepri, r0
bx r14
}
А меня жаба душит транжирить SVC на такое... Вообще не хочу, чтобы FreeRTOS использовала SVC.
Есть идея сделать почти все то же самое, что в обработчике, но вызовом функции: только вместо bx r14 перевести процессор на использование PSP + непривилегированный режим. Ну и регистры все восстановить, потому как не в прерывании находимся. И это будет возможно сделать, поскольку после сброса CPU находится в привилегированном режиме, соответственно все системные функции работы с регистрами специального назначения ему разрешены.
Нужно попробовать, но хотелось бы выслушать критику... Работать будет?
Итого, что-то типа
Код
__asm void prvStartFirstTask( void )
{
PRESERVE8
/* Use the NVIC offset register to locate the stack. */
ldr r0, =0xE000ED08
ldr r0, [r0]
ldr r0, [r0]
/* Set the msp back to the start of the stack. */
msr msp, r0
/* Clear the bit that indicates the FPU is in use in case the FPU was used
before the scheduler was started - which would otherwise result in the
unnecessary leaving of space in the SVC stack for lazy saving of FPU
registers. */
mov r0, #0
msr control, r0
/* Globally enable interrupts. */
cpsie i
cpsie f
dsb
isb
// Финт ушами
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r1, [r3]
ldr r0, [r1]
// восстановить контекст первой задачи в нужной последовательности
ldmia r0!, {тут список регистров R0-R12, LR, XPSR в правильном порядке}
msr psp, r0
isb
mov r0, #0
msr basepri, r0
// а тут восстановить PC и поехали
}