Цитата(Arlleex @ Sep 3 2018, 14:08)

При явной работе с PC адрес инструкции, записываемой в этот регистр, должен быть с установленным 0-м битом, указывающим на Thumb-режим.
А как она туда (в стек) попадёт с 0 в мл.бите? Если только специально постараться.
Цитата(Arlleex @ Sep 3 2018, 14:08)

Кстати,
тут прямо пишут
Так что ISB надо вставлять. Выглядит даже логично - действительно конвейер надо сбросить, т.к. SP может наадресовать чего-нибудь не того в конвейверной обработке...
Вы похоже не поняли того, что сами процитировали.....
Эта фраза дана
после рекомендации как правильно менять CONTROL.SPSEL. И относится именно к этому изменению.
Подумайте сами логически: если-б ISB нужно менять после любой модификации SP, то компилятор генерил бы ISB во всех случаях когда генерит PUSH/POP/ADD SP/SUB SP. А также ему пришлось бы обрамлять запретами прерываний все такие места. Загляните в листинги.
А также из этой фразы и того что перед ней следует что Вы в своём примере неправильно меняете SPSEL. Там же указано:
Код
By default, Thread mode uses the MSP. To switch the stack pointer used in Thread mode to the
PSP, either:
• use the MSR instruction to set the Active stack pointer bit to 1, see MSR on page 3-164.
• perform an exception return to Thread mode with the appropriate EXC_RETURN value,
see Table 2-17 on page 2-28.
А где у Вас exception return с правильным EXC_RETURN? Каково вообще значение LR при ближайшем входе в ISR? Я что-то подозреваю что оно неверное.
Я ещё неск. сообщений назад говорил, что решается это одной командой ORR LR, LR, #4. Да и вообще сам старт многозадачности он много проще чем у Вас тут наворочено.
Также из этой фразы следует что и изменение CONTROL.SPSEL нужно делать
при запрещённых прерываниях, чего у Вас нет. Понятно что Вам везёт и у Вас просто сейчас не попадает туда прерывание. Но завтра попадёт.
Цитата(Arlleex @ Sep 3 2018, 14:08)

В примере от индусов (старый порт RTOS) в бит FPCA CONTROL пишется 0 и вызывается SVC.
Не нужно индусов и SVC. uCOS-II всё это делает без них.

Приведу пример переключателя контекста и запускателя многозадачности из uCOS-II оптимизированного мной:
CODE
;**********************************************************************
**********************************
; START MULTITASKING
; void OSStartHighRdy(void)
;
; Note(s) : 1) This function triggers a PendSV exception (essentially, causes a context switch) to cause
; the first task to start.
;
; 2) OSStartHighRdy() MUST:
; a) Setup PendSV exception priority to lowest;
;

Set initial PSP to 0, to tell context switcher this is first run;
; c) Set the main stack to end of OS_CPU_ExceptStk
; d) Set OSRunning to TRUE;
; e) Trigger PendSV exception;
; f) Enable interrupts (tasks will run with interrupts enabled).
;*******************************************************************************
*************************
THUMB
OSStartHighRdy LDR R0, =NVIC_SYSPRI14 ;Set the PendSV exception priority
LDR R1, =NVIC_PENDSV_PRI
STRB R1, [R0]
LDR R1, stkBase ;Initialize the MSP to the end of OS_CPU_ExceptStk
MSR MSP, R1
LDR R0, =OSRunning ;OSRunning = TRUE
MOVS R1, #1
STRB R1, [R0]
BL OSCtxSw
LDR R3, =OSGlobalV
LDRB R2, [R3, #OSPrioHighRdy] ;OSPrioHighRdy
STRB R2, [R3, #OSPrioCur] ;OSPrioCur = OSPrioHighRdy
LDR R2, [R3, #OSTCBHighRdy] ;OSTCBHighRdy
STR R2, [R3, #OSTCBCur] ;OSTCBCur = OSTCBHighRdy;
LDR R0, [R2, #OSTCBStkPtr] ;R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
#ifdef __ARMVFP__
LDRH R1, [R2, #OSTCBOpt] ;OSTCBHighRdy->OSTCBOpt
LSLS R1, R1, #31 - OS_TASK_OPT_SAVE_FP_BIT
ITTT MI
VLDMIAMI R0!, {S0-S31}
LDMIAMI R0!, {R1}
VMSRMI FPSCR, R1
#endif
LDMFD R0!, {R4-R11} ;Restore r4-11 from new process stack
MSR PSP, R0 ;Load PSP with new process SP
CPSIE I ;Exception return will restore remaining context
startHR_01: B startHR_01
DATA
stkBase DC32 OS_CPU_ExceptStk + OS_CPU_EXCEPT_STK_SIZE * 4
здесь Notes 2b более недействительно - я изменил порядок старта многозадачности перенеся часть переключателя контекста в эту функцию. Так что PSP=0 больше не нужно.
На входе в функцию прерывания должны быть запрещены!
Функция OSCtxSw просто возбуждает прерывание PendSV. Которое сработает после CPSIE I.
Переключатель контекста:
CODE
;**********************************************************************
**********************************
; HANDLE PendSV EXCEPTION
; void OS_CPU_PendSVHandler(void)
;
; Note(s) : 1) PendSV is used to cause a context switch. This is a recommended method for performing
; context switches with Cortex-M3. This is because the Cortex-M3 auto-saves half of the
; processor context on any exception, and restores same on return from exception. So only
; saving of R4-R11 is required and fixing up the stack pointers. Using the PendSV exception
; this way means that context saving and restoring is identical whether it is initiated from
; a thread or occurs due to an interrupt or exception.
;
; 2) Pseudo-code is:
; a) Get the process SP, if 0 then skip (goto d) the saving part (first context switch);
;

Save remaining regs r4-r11 on process stack;
; c) Save the process SP in its TCB, OSTCBCur->OSTCBStkPtr = SP;
; d) Call OSTaskSwHook();
; e) Get current high priority, OSPrioCur = OSPrioHighRdy;
; f) Get current ready thread TCB, OSTCBCur = OSTCBHighRdy;
; g) Get new process SP from TCB, SP = OSTCBHighRdy->OSTCBStkPtr;
; h) Restore R4-R11 from new process stack;
; i) Perform exception return which will restore remaining context.
;
; 3) On entry into PendSV handler:
; a) The following have been saved on the process stack (by processor):
; xPSR, PC, LR, R12, R0-R3
;

Processor mode is switched to Handler mode (from Thread mode)
; c) Stack is Main stack (switched from Process stack)
; d) OSTCBCur points to the OS_TCB of the task to suspend
; OSTCBHighRdy points to the OS_TCB of the task to resume
;
; 4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we
; know that it will only be run when no other exception or interrupt is active, and
; therefore safe to assume that context being switched out was using the process stack (PSP).
;*******************************************************************************
*************************
THUMB
OS_CPU_PendSVHandler:
CPSID I ;Prevent interruption during context switch
MRS R0, PSP ;PSP is process stack pointer
LDR R3, =OSGlobalV
STMFD R0!, {R4-R11} ;Save remaining regs r4-11 on process stack
LDR R2, [R3, #OSTCBCur] ;OSTCBCur
#ifdef __ARMVFP__
LDRH R1, [R2, #OSTCBOpt] ;OSTCBCur->OSTCBOpt
LSLS R1, R1, #31 - OS_TASK_OPT_SAVE_FP_BIT
ITTT MI
VMRSMI R1, FPSCR
STRMI R1, [R0, #-4]!
VSTMDBMI R0!, {S0-S31}
STR R0, [R2, #OSTCBStkPtr] ;OSTCBCur->OSTCBStkPtr = SP;
LDR R2, [R3, #OSTCBHighRdy] ;OSTCBHighRdy
STR R2, [R3, #OSTCBCur] ;OSTCBCur = OSTCBHighRdy;
LDR R0, [R2, #OSTCBStkPtr] ;R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
LDRH R1, [R2, #OSTCBOpt] ;OSTCBHighRdy->OSTCBOpt
LSLS R1, R1, #31 - OS_TASK_OPT_SAVE_FP_BIT
ITTT MI
VLDMIAMI R0!, {S0-S31}
LDMIAMI R0!, {R1}
VMSRMI FPSCR, R1
#else
STR R0, [R2, #OSTCBStkPtr] ;OSTCBCur->OSTCBStkPtr = SP;
LDR R0, [R3, #OSTCBHighRdy] ;OSTCBHighRdy
STR R0, [R3, #OSTCBCur] ;OSTCBCur = OSTCBHighRdy;
LDR R0, [R0, #OSTCBStkPtr] ;R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
#endif
LDRB R1, [R3, #OSPrioHighRdy] ;OSPrioCur = OSPrioHighRdy;
STRB R1, [R3, #OSPrioCur]
ORR LR, LR, #4 ;Ensure exception return uses process stack
LDMFD R0!, {R4-R11} ;Restore r4-11 from new process stack
MSR PSP, R0 ;Load PSP with new process SP
CPSIE I
BX LR ;Exception return will restore remaining context
Замечу что при переключении контекста OSTCBHighRdy (TCB - task control block) - готовой к выполнению самой приоритетной задачи должен быть переписан на место OSTCBCur - TCB текущей активной задачи. И то же самое для OSPrioHighRdy и OSPrioCur (это приоритеты задач, являются в uCOS-II собственно идентификаторами задач).
Также замечу что код по веткам
#ifndef __ARMVFP__ я не тестировал - тестил только на CM4 с программой имеющей задачи использующие FPU.
И поясню, что в OSTCBOpt TCB бит OS_TASK_OPT_SAVE_FP_BIT - это флаг о том что задача использует FPU и его контекст нужно тоже сохранять/восстанавливать.
Как видите - нигде нет манипуляций с регистром CONTROL. В нём предполагаются исходные значения == 0 или 4.
Также добавлю описание формата хранения контекста задач в uCOS (для задач с FPU и без):
CODE
+------------+ +------------+
| xPSR | | xPSR |
+------------+ +------------+
|Return Addr | |Return Addr |
+------------+ +------------+
| LR(R14) | | LR(R14) |
+------------+ +------------+
| R12 | | R12 |
+------------+ +------------+
| R3 | | R3 |
+------------+ +------------+
| R2 | | R0 |
+------------+ +------------+
| R1 | | R1 |
+------------+ +------------+
| R0 | | R0 |
+------------+ +------------+
| R11 | | R11 |
+------------+ +------------+
| R10 | | R10 |
+------------+ +------------+
| R9 | | R9 |
+------------+ +------------+
| R8 | | R8 |
+------------+ +------------+
| R7 | | R7 |
+------------+ +------------+
| R6 | | R6 |
+------------+ +------------+
| R5 | | R5 |
+------------+ +------------+
| R4 | | R4 |
+------------+ +------------+
(a) | FPSCR |
+------------+
| S31 |
+------------+
.
.
.
+------------+
| S1 |
+------------+
| S0 |
+------------+
Верхние 8 слов соответствуют аппаратному сохранению контекста в Cortex-M.