热度 13
2013-2-20 20:23
1773 次阅读|
0 个评论
/*-------------------------------------------------------------------------------------------------------------------------*/ 堆管理 而这里的内存管理,实质是预先分配固定大小的内存, 使用时只能使用相应大小的内存。 因为在裸机上做内存管理,固定分配的要优于动态分配。(应该说是,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, STR R0, ; 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, STRB R2, LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy; LDR R1, =OSTCBHighRdy LDR R2, STR R2, LDR R0, ; 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 关于切换的具体实现, 到这里感觉清楚很多。