|
將uCOSii 加入到工程,編譯,如果報(bào)以下錯(cuò)誤錯(cuò)誤:
compiling ucos_ii.c...
linking...
.\out\test.axf: Error: L6200E: Symbol OSEventTbl multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSFlagTbl multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSTaskStatStk multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSRdyTbl multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSTaskIdleStk multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSTCBPrioTbl multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSTCBTbl multiply defined (by ucos_ii.o and os_core.o).
.... 還有很多
解決方法:將ucos_ii.c 從工程中移除。
如果出現(xiàn)以下未定義錯(cuò)誤:
.\out\test.axf: Error: L6218E: Undefined symbol OSCtxSw (referred from os_core.o).
.\out\test.axf: Error: L6218E: Undefined symbol OSIntCtxSw (referred from os_core.o).
.\out\test.axf: Error: L6218E: Undefined symbol OSStartHighRdy (referred from os_core.o).
.\out\test.axf: Error: L6218E: Undefined symbol OS_CPU_SR_Restore (referred from os_core.o).
.\out\test.axf: Error: L6218E: Undefined symbol OS_CPU_SR_Save (referred from os_core.o).
是因?yàn)?os_cpu_a.s 沒(méi)有加入工程,將其加入工程即可解決問(wèn)題。
------------------------------------------------------------------------
移植步驟:
1、修改OS_CPU.H 文件
1、重定義與編譯器、uCOS II 有關(guān)的數(shù)據(jù)類型
typedef unsigned char BOOLEAN;
typedef unsigned char INT8U; /* Unsigned 8 bit quantity */
typedef signed char INT8S; /* Signed 8 bit quantity */
typedef unsigned short INT16U; /* Unsigned 16 bit quantity */
typedef signed short INT16S; /* Signed 16 bit quantity */
typedef unsigned int INT32U; /* Unsigned 32 bit quantity */
typedef signed int INT32S; /* Signed 32 bit quantity */
typedef float FP32; /* Single precision floating point */
typedef double FP64; /* Double precision floating point */
typedef unsigned int OS_STK; /* Each stack entry is 32-bit wide */
typedef unsigned int OS_CPU_SR; /* Define size of CPU status register (PSR = 32 bits) */
2、定義中斷的實(shí)現(xiàn)方式,一般是為了實(shí)現(xiàn)臨界區(qū)代碼保護(hù)
#define OS_CRITICAL_METHOD 3
#if OS_CRITICAL_METHOD == 3
#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}
#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}
#endif
3、定義棧的生長(zhǎng)方式
/* 堆棧1是從上往下長(zhǎng)的,0-從下往上的生長(zhǎng)方式 */
#define OS_STK_GROWTH 1 /* Stack grows from HIGH to LOW memory on ARM */
4、宏定義 優(yōu)先級(jí)任務(wù)切換 函數(shù),用于現(xiàn)場(chǎng)保護(hù)以及現(xiàn)場(chǎng)恢復(fù)實(shí)現(xiàn)任務(wù)切換
#define OS_TASK_SW() OSCtxSw() // 任務(wù)級(jí)任務(wù)切換
5、定義開(kāi)、關(guān)中斷的函數(shù),在保護(hù)臨界區(qū)代碼時(shí)會(huì)用到。
#if OS_CRITICAL_METHOD == 3 /* See OS_CPU_A.ASM */
OS_CPU_SR OS_CPU_SR_Save(void);
void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);#endif
6、聲明函數(shù) 這些函數(shù)都是要自己實(shí)現(xiàn)或修改
void OSCtxSw(void); // 任務(wù)級(jí)切換 觸發(fā)PendSV異常
void OSIntCtxSw(void); // 中斷級(jí)切換 觸發(fā)PendSV異常
void OSStartHighRdy(void); // 運(yùn)行最高優(yōu)先級(jí)的任務(wù)
void OS_CPU_PendSVHandler(void); // 發(fā)生PendSV異常時(shí)被觸發(fā),OSCtxSw()、OSIntCtxSw() 最終實(shí)現(xiàn) 即任務(wù)切換
void OS_CPU_SysTickHandler(void); /* See OS_CPU_C.C */
void OS_CPU_SysTickInit(void); // 系統(tǒng)時(shí)鐘節(jié)拍初始化 用于任務(wù)切換
INT32U OS_CPU_SysTickClkFreq(void); /* See BSP.C OS_CPU_SysTickInit(void);用來(lái)獲得硬件的時(shí)鐘頻率,這里是直接指定并沒(méi)有用上。*/
OS_CPU_PendSVHandler(void)、OS_CPU_SysTickHandler(void) 需要在 startup_LPC11xx.s 定義

2、修改OS_CPU_C.C 文件
1、修改OSTaskStkInt()函數(shù)
主要修改OSTaskStkInit()函數(shù),其他的HOOK函數(shù)根據(jù)需要實(shí)現(xiàn)(將文件OS_CFG.H中的#define constant OS_CPU_HOOKS_EN設(shè)為1,設(shè)為0表示不使用這些函數(shù))
用戶創(chuàng)建任務(wù)時(shí),OSTasKCreat()會(huì)調(diào)用OSTaskStkInt()函數(shù)初始化該任務(wù)的堆棧,并把返回的堆棧指針保存到該任務(wù)的TCB結(jié)構(gòu)中
的最前面的參數(shù)OSTCBStkPtr中,當(dāng)該任務(wù)要被恢復(fù)時(shí),任務(wù)切換函數(shù)從其TCB塊中取得其任務(wù)堆棧指針,依次將堆棧內(nèi)容彈到處理器
對(duì)應(yīng)的CPSR、r0、r1,…,r12,lr,pc的寄存器中,完成現(xiàn)場(chǎng)的恢復(fù)和程序指針PC的返回。
// 創(chuàng)建任務(wù)時(shí)被調(diào)用 初始化任務(wù)堆棧 具體實(shí)現(xiàn)不是很明白
OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)
{
OS_STK *stk;
(void)opt; /* 'opt' is not used, prevent warning */
stk = ptos; /* Load stack pointer 獲取堆棧指針 */
/* Registers stacked as if auto-saved on exception */
*(stk) = (INT32U)0x01000000L; /* xPSR */
*(--stk) = (INT32U)task; /* Entry Point 保存任務(wù)函數(shù)地址 */
*(--stk) = (INT32U)0xFFFFFFFEL; /* R14 (LR) (init value will cause fault if ever used)*/
*(--stk) = (INT32U)0x12121212L; /* R12 */
*(--stk) = (INT32U)0x03030303L; /* R3 */
*(--stk) = (INT32U)0x02020202L; /* R2 */
*(--stk) = (INT32U)0x01010101L; /* R1 */
*(--stk) = (INT32U)p_arg; /* R0 : argument 保存參數(shù) */
/* Remaining registers saved on process stack */
*(--stk) = (INT32U)0x11111111L; /* R11 */
*(--stk) = (INT32U)0x10101010L; /* R10 */
*(--stk) = (INT32U)0x09090909L; /* R9 */
*(--stk) = (INT32U)0x08080808L; /* R8 */
*(--stk) = (INT32U)0x07070707L; /* R7 */
*(--stk) = (INT32U)0x06060606L; /* R6 */
*(--stk) = (INT32U)0x05050505L; /* R5 */
*(--stk) = (INT32U)0x04040404L; /* R4 */
return (stk);
}
2、實(shí)現(xiàn) void OS_CPU_SysTickInit (void)、void OS_CPU_SysTickHandler (void)
// 初始化SysTick 用于在固定時(shí)產(chǎn)生中斷
void OS_CPU_SysTickInit (void)
{
INT32U cnts;
/* cnts = OS_CPU_SysTickClkFreq() / OS_TICKS_PER_SEC; */
cnts = 48000000 / OS_TICKS_PER_SEC; // OS_TICKS_PER_SEC 10ms 產(chǎn)生一次中斷
OS_CPU_CM3_NVIC_ST_RELOAD = (cnts - 1);
OS_CPU_CM3_NVIC_ST_CURRENT = 0;
/* Set Priority of SysTick to 2 (0-3, 0 is highest) */
cnts = OS_CPU_CM0_NVIC_SHPR3;
cnts &= 0x00FFFFFF;
cnts |= 0x80000000;
OS_CPU_CM0_NVIC_SHPR3 = cnts;
/* Enable timer. */
OS_CPU_CM3_NVIC_ST_CTRL |= OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC | OS_CPU_CM3_NVIC_ST_CTRL_ENABLE;
/* Enable timer interrupt. */
OS_CPU_CM3_NVIC_ST_CTRL |= OS_CPU_CM3_NVIC_ST_CTRL_INTEN;
}
// SysTick中斷服務(wù)函數(shù) 用于產(chǎn)生系統(tǒng)節(jié)拍
void OS_CPU_SysTickHandler (void)
{
OS_CPU_SR cpu_sr;
OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR */
OSIntNesting++;
OS_EXIT_CRITICAL();
OSTimeTick(); /* Call uC/OS-II's OSTimeTick() */
OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR */
}
3、修改OS_CPU_A.S 文件
1、定義寄存器地址
NVIC_INT_CTRL EQU 0xE000ED04 ; Interrupt control state register.
NVIC_SCB_SHPR3 EQU 0xE000ED20
NVIC_PENDSV_PRI EQU 0x00FF0000
NVIC_PENDSVSET EQU 0x10000000 ; Value to trigger PendSV exception.
2、實(shí)現(xiàn) OS_CPU_SR_Save()、OS_CPU_SR_Restore()、OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()、OS_CPU_PendSVHandler()
// 實(shí)現(xiàn)OS_CPU_SR_Save()、OS_CPU_SR_Restore()
// 通過(guò)保存中斷狀態(tài)來(lái)禁用、啟用中斷 用在
OS_CPU_SR_Save ; 保存中斷狀態(tài) MRS R0, PRIMASK ; Set prio int mask to mask all (except faults) CPSID I BX LR
OS_CPU_SR_Restore ; 恢復(fù)中斷狀態(tài) MSR PRIMASK, R0 BX LR
// 實(shí)現(xiàn) OSStartHighRdy()
// 啟動(dòng)優(yōu)先級(jí)最高的任務(wù) OSStartHighRdy
; 設(shè)置PendSV 異常優(yōu)先級(jí)為最低
ldr r0, =NVIC_SCB_SHPR3
ldr r1, [r0]
ldr r2, =NVIC_PENDSV_PRI
orrs r1, r1, r2
str r1, [r0]
; 初始化PSP設(shè)置為 0 MOVS R0, #0 ; Set the PSP to 0 for initial context switch call MSR PSP, R0 ; PSP為0 告訴上下文切換,這是第一次運(yùn)行
; 設(shè)置 任務(wù)運(yùn)行狀態(tài)為 1 LDR R0, =OSRunning ; OSRunning = TRUE MOVS R1, #1 STRB R1, [R0]
; 觸發(fā)PendSV 異常,實(shí)現(xiàn)任務(wù)切換 LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0]
; PendSV 異常處理函數(shù)會(huì)關(guān)閉中斷,所以需要開(kāi)中斷 CPSIE I ; 使能中斷 Enable interrupts at processor level
OSStartHang B OSStartHang ; Should never get here
[size=14.44444465637207px]// 實(shí)現(xiàn) OSCtxSw() 任務(wù)級(jí)切換任務(wù)
// 觸發(fā)PendSV 異常,實(shí)現(xiàn)任務(wù)切換
OSCtxSw LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0] BX LR
[size=14.44444465637207px]// 實(shí)現(xiàn) OSIntCtxSw() 中斷級(jí)切換任務(wù)
// 觸發(fā)PendSV 異常,實(shí)現(xiàn)任務(wù)切換
OSIntCtxSw
LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
BX LR
;/* Pendsv 中斷函數(shù) */
;/* 用于實(shí)現(xiàn)時(shí)間片輪轉(zhuǎn)法 中斷級(jí)任務(wù)調(diào)度、任務(wù)級(jí)中斷調(diào)度 切換上下文*/
; 進(jìn)入PendSV時(shí):
; xPSR、PC、LR、R12、R0~R3 已經(jīng)在處理?xiàng)V斜槐4?/font>
; 處理模式切換到線程模式
; 棧是主堆棧
OS_CPU_PendSVHandler
CPSID I ; 關(guān)閉中斷,避免上下文切換時(shí)發(fā)送中斷。
MRS R0, PSP ; PSP is process stack pointer
;CBZ R0, OS_CPU_PendSVHandler_nosave ; Skip register save the first time
cmp r0, #0 ; 如果獲取任務(wù)的SP 為0 則跳到 OS_CPU_PendSVHandler_nosave
beq OS_CPU_PendSVHandler_nosave
; 保存R3~R11和SP
SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack
stm r0!, {r4-r7}
mov r1, r8
mov r2, r9
mov r3, r10
mov r4, r11
stm r0!, {r1-r4}
subs r0, r0, #0x20
; 將當(dāng)前的堆棧指針給當(dāng)前進(jìn)程的任務(wù)塊
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
; 調(diào)用 OSTaskSwHook() 函數(shù) 用于擴(kuò)展
mov r0, lr
push {r0}
ldr r0, =OSTaskSwHook
blx r0
pop {r0}
mov lr, r0
; 獲取當(dāng)前最高優(yōu)先級(jí)的任務(wù)
LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
; 獲取當(dāng)前就緒的線程
LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0]
; 得到新任務(wù)的SP和線程恢復(fù) R4~R11
LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
ldm r0!, {r4-r7}
ldm r0!, {r1-r3}
mov r8, r1
mov r9, r2
mov r10, r3
ldm r0!, {r1}
mov r11, r1
; 載入新的SP和返回
MSR PSP, R0 ; Load PSP with new process SP
mov r0, lr
movs r1, #0x04
orrs r0, r0, r1
mov lr, r0
CPSIE I ; 開(kāi)啟中斷
BX LR ; Exception return will restore remaining context
b .
END
移植uCOS II 的難點(diǎn)在于:函數(shù)的實(shí)現(xiàn)。
總結(jié):
OS_CPU_C.C:
void OS_CPU_SysTickInit (void)、void OS_CPU_SysTickHandler (void)
任務(wù)調(diào)度,產(chǎn)生系統(tǒng)時(shí)鐘節(jié)拍,每一次節(jié)拍就切換一次當(dāng)前就緒表中優(yōu)先級(jí)最高的任務(wù)
OS_CPU_A.S:
OS_CPU_SR_Save()、OS_CPU_SR_Restore():
用于任務(wù)保存和恢復(fù)自身的中斷狀態(tài)。用于臨界區(qū)代碼。
OSStartHighRdy():
尋找就緒表中優(yōu)先級(jí)最高的任務(wù)。
OSCtxSw()、OSIntCtxSw()、OS_CPU_PendSVHandler()
OSCtxSw()、OSIntCtxSw()都是通過(guò)觸發(fā)PendSV異常進(jìn)行任務(wù)切換
OSCtxSw():一般是在任務(wù)調(diào)用延時(shí)函數(shù) 如OSTimeDlyHMSM(0, 0, 0, 300); 時(shí)調(diào)用的。
OSIntCtxSw():一般用在系統(tǒng)時(shí)鐘節(jié)拍中斷時(shí),會(huì)采用這種方式調(diào)度新的任務(wù)。
OS_CPU_PendSVHandler() 產(chǎn)生異常PendSV異常就進(jìn)行一次任務(wù)切換
|
|