/*-------------------------------------------------------------------------------------------------------------------------*/
堆管理
而这里的内存管理,实质是预先分配固定大小的内存,
使用时只能使用相应大小的内存。
因为在裸机上做内存管理,固定分配的要优于动态分配。(应该说是,uCOS使用固定分配来模拟动态分配)
因为一般使用uCOS的地方,内存都不多,这时固定分配反而是更优的选择。
(对于内存受限系统(memory constrainted system)的嵌入式编程,这种方式应该说是最合适的方式了)
/*-------------------------------------------------------------------------------------------------------------------------*/
栈管理
那么在uCOS中一个任务操作超过了其堆栈设置会有什么样的后果呢?
从uCOS中os_tcb 结构体中发现默认的只有一个栈顶指针,这里的栈顶指针是如何使用的。
OSCtxSw(uCOS_II_V2.86/uC_Port/os_cpu_a.asm)这个函数,是由汇编语言写成的,为了触发pendsv中断引起切换。
`~uCOS_II_V2.86/
| |+Core/
| |+uC_CPU/
| |+uC_LIB/
| |~uC_Port/
| | |+ini/
| | `~src/
| | |-os_cpu_a.asm
| | |-os_cpu_c.c
| | `-os_dbg.c
| `+uCOS-II/
这里边在第一次切换时,使用的是最高优先级的代码。
对于栈空间的使用,方法如下:
首先由Task_Create函数设置好栈顶指针,
在任务切换时,将这个栈顶指针(而这里的这个栈顶指针既是在创建任务时,传入的一个数组的首地址,拿来当做栈使用)传递给sp,实现sp的切换。
当任务切换时,
除了保存所有寄存器意外,
最重要的就是要
在OSStartHighRdy函数中,将OSRunning置位TRUE,表示系统开始执行。
问题是,这个修改的栈指针,是什么时候修改的?
在切换时,sp保存在当前任务的OS_TCB结构体中,此时sp和OSTCBCur->OSTCBStkPtr指向的是任务堆栈的都一个内存位置。
里边有第一次切换的判断。第一次切换时,不保存堆栈,如果是以后切换需要保存堆栈。
这里确实没有关于栈溢出的操作,因为如果栈溢出,将覆盖其他任务的栈内容,修改备份的寄存器内容。
会造成其他任务运行异常,这样就会引起错误。
(栈空间的大小至少要能保存,芯片体系结构要求保存的所有寄存器内容)
//STM32F103CBT6任务切换代码
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);
; b) 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
; b) 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).
OS_CPU_PendSVHandler
CPSID I ; Prevent interruption during context switch
MRS R0, PSP ; PSP is process stack pointer
CBZ R0, OS_CPU_PendSVHandler_nosave ; Skip register save the first time
SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack
STM R0, {R4-R11}
LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;
LDR R1, [R1]
STR R0, [R1] ; R0 is SP of process being switched out
; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
PUSH {R14} ; Save LR exc_return value
LDR R0, =OSTaskSwHook ; OSTaskSwHook();
BLX R0
POP {R14}
LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0]
LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
LDM R0, {R4-R11} ; Restore r4-11 from new process stack
ADDS R0, R0, #0x20
MSR PSP, R0 ; Load PSP with new process SP
ORR LR, LR, #0x04 ; Ensure exception return uses process stack
CPSIE I
BX LR ; Exception return will restore remaining context
END
关于切换的具体实现,
到这里感觉清楚很多。
文章评论(0条评论)
登录后参与讨论