首先必須要謝謝正點原子的uCOS開發手冊V3.0,介紹的很詳細,大神就是大神
然後呢,這幾天就在看的時候發現移植uCOSIII出現了開啟FPU的時候就會HardFault,然後上網搜了一下,果然這個問題爛大街了已經,然後我也稍微研究了一下,發現出問題的是uCOS官方的檔案不符合浮點寄存器的入棧和出棧順序,然後呢,經過兩個小時的尋找解決方案,最終還是在安富萊電子的uCOSIII教程1-11期中找到了解決方案,出現問題的點有兩個: 一個是 CPU_STK *OSTaskStkInit(), 另一個是 PendSV中斷。其餘的地方按照原子哥的方法修改,然後融合到一起就沒問題了。
以下解決方案是基于uCOSIII 3.04版本,其他版本自行測試
具體的移植方法是:
1,按照原子哥的方法移植到編譯沒有錯誤為止,然後試一下,添加一個列印浮點數的任務,Debug一下試試會不會死在
/**
* @brief This function handles Hard Fault exception.
* @param None
* @retval None
*/
void HardFault_Handler(void)
{
/* Go to infinite loop when Hard Fault exception occurs */
while (1)
{
}
}
其實根本不用試,這是必須的。
2,找到OSTaskStkInit(在OS_CPU_c.c)函數,改為以下代碼
CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task,
void *p_arg,
CPU_STK *p_stk_base,
CPU_STK *p_stk_limit,
CPU_STK_SIZE stk_size,
OS_OPT opt)
{
CPU_STK *p_stk;
(void)opt; /* Prevent compiler warning */
p_stk = &p_stk_base[stk_size]; /* Load stack pointer */
/* Align the stack to 8-bytes. */
p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8);
/* Registers stacked as if auto-saved on exception */
*--p_stk = (CPU_STK)0x01000000u; /* xPSR */
*--p_stk = (CPU_STK)p_task; /* Entry Point */
*--p_stk = (CPU_STK)OS_TaskReturn; /* R14 (LR) */
*--p_stk = (CPU_STK)0x12121212u; /* R12 */
*--p_stk = (CPU_STK)0x03030303u; /* R3 */
*--p_stk = (CPU_STK)0x02020202u; /* R2 */
*--p_stk = (CPU_STK)p_stk_limit; /* R1 */
*--p_stk = (CPU_STK)p_arg; /* R0 : argument */
/* Remaining registers saved on process stack */
*--p_stk = (CPU_STK)0x11111111u; /* R11 */
*--p_stk = (CPU_STK)0x10101010u; /* R10 */
*--p_stk = (CPU_STK)0x09090909u; /* R9 */
*--p_stk = (CPU_STK)0x08080808u; /* R8 */
*--p_stk = (CPU_STK)0x07070707u; /* R7 */
*--p_stk = (CPU_STK)0x06060606u; /* R6 */
*--p_stk = (CPU_STK)0x05050505u; /* R5 */
*--p_stk = (CPU_STK)0x04040404u; /* R4 */
*--p_stk = (CPU_STK)0xFFFFFFFDUL;
return (p_stk);
}
3,找到PendSV_Handler(在os_cpu_a.asm),改為以下代碼
PendSV_Handler
CPSID I ; Prevent interruption during context switch
MRS R0, PSP ; PSP is process stack pointer
CBZ R0, PendSVHandler_nosave ; Skip register save the first time
CBZ R0, PendSVHandler_nosave ; Skip register save the first time
TST LR, #0x10
IT EQ
VSTMDBEQ R0!, {S16-S31}
MOV R3, LR
STMDB R0!,{R3-R11}
LDR R1, =OSTCBCurPtr ; OSTCBCurPtr->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
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, =OSTCBCurPtr ; OSTCBCurPtr = OSTCBHighRdyPtr;
LDR R1, =OSTCBHighRdyPtr
LDR R2, [R1]
STR R2, [R0]
LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;
LDMIA R0!,{R3-R11}
MOV LR, R3
TST LR, #0x10
IT EQ
VLDMIAEQ R0!, {S16-S31}
MSR PSP, R0 ; Load PSP with new process SP
CPSIE I
BX LR ; Exception return will restore remaining context
END
這個時候再編譯下,排錯,然後下載下傳試下應該就可以了