1. 移植前準備
1.1 源碼下載
UCOS-III Kernel Source:? ?https://github.com/weston-embedded/uC-OS3.git
Micriμm CPU Source?:?https://github.com/weston-embedded/uC-CPU.git
Micriμm Lib Source: https://github.com/weston-embedded/uC-LIB.git?
1.2. 源碼介紹
1.2.1 源碼組織結構圖
1.2.2 源碼簡介
1)應用層模塊
2)BSP 與板子相關的BSP模塊 (需要移植) 主要為系統時鐘、時間戳相關API
3)μC-OS3/Source 內核源碼 與CPU無關的模塊
4)μC-OS3/Ports 與CPU相關的模塊 (需要移植 )
5)uC-CPU 與特定平臺CPU相關的模塊(由uc-cpu提供)
6)uC-LIB 與CPU無關的庫函數模塊
7) μC-OS3/Cfg 配置頭文件(需要配置的部分)
調用關系: UC/OS-III/Ports-->uC-CPU --> CPU_BSP
2. 移植配置列表
1)移植 uC-OS3 CPU 相關部分: os_cpu.h,?os_cpu_a.asm,? os_cpu_c.c
2)移植 uC/CPU 相關部分: cpu_a.asm , cpu_c.c
3)移植板級支持包(BSP) 部分: bsp.c ,bsp.h
4)配置UC/OS-III 以下部分:
?μC/OS-III 功能配置 (os_cfg.h)
μC/OS-III 堆棧、系統任務和其他數據大小 (os_cfg_app.h)
μC/OS-III 數據類型 (os_type.h)
具體配置參考: http://t.csdnimg.cn/GNZcY
3. 移植 uC-OS3 CPU
3.1 找到MCU使用的CPU架構
以GD32F303為例,翻閱其手冊,查找CPU對應的架構信息如下:
3.2 找到CPU架構對應的文件
????????在uC-OS3/Ports目錄下查找ARMv7-M,找到 ARMv7-M路徑: ARM-Cortex-M/ARMv7-M
3.3 開發編譯環境列表
ARM-Cortex-M/ARMv7-M 目錄下有4個文件夾,分別對應不同的編譯器
- ARM: ARM公司提供的編譯器,如Keil MDK開發環境。
- CCS: TI的Code Composer Studio編譯器。
- GNU: GNU工具鏈(如GCC)
- IAR: IAR 開發環境
3.4 使用Keil MDK編譯器
uC-OS3/Template/bsp_os_dt.c , 有以下系統時鐘相關接口需要移植:
BSP_OS_TickInit() //初始化系統時鐘滴答定時器
BSP_OS_TickISR() //系統時鐘滴答中斷服務程序
uC-OS3/Ports/Template目錄里的os_cpu.h ,有以下上下文切換相關接口需要實現:???
void OSCtxSw (void); // 任務級上下文切換,觸發PendSV異常
void OSIntCtxSw (void); // 中斷上下文中進行任務切換,觸發PendSV異常
void OSStartHighRdy (void); // 啟動最高優先級的就緒任務
void OS_CPU_PendSVHandler (void); // PendSV 異常處理程序,用切換當前任務的上下文到下一個準備就緒的任務
查看MCU的CPU架構及所選開發環境對應的文件
uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu_c.c
uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/ARM/os_cpu_a.asm
已實現上述的所有接口,如果原廠沒有實現的接口,則需要實現以上接口
3.4.1 BSP_OS_TickInit 接口實現
此函數接口用于初始化系統滴答定時器,設置操作系統時鐘中斷,該函數必須在 OSStart() 調用之后,并且在處理器初始化完成后調用。
優先級設置需要考慮系統中其他中斷的優先級配置,確保實時操作系統的滴答計時器中斷能夠按期觸發。
以下是偽代碼描述:
void BSP_OS_TickInit(CPU_INT32U freq) {Install the interrupt vector for the timer used to generate tick interrupts; // 安裝定時器中斷向量Configure the timer to generate interrupts at 'freq' Hz; // 配置定時器以產生指定頻率的中斷Enable timer interrupts; // 啟用定時器中斷
}
以下是ARM-Cortex-M/ARMv7-M/os_cpu_c.c已實現的接口:
voidOS_CPU_SysTickInit(CPU_INT32U cnts)
{CPU_INT32U prio;CPU_INT32U basepri;// 設置 BASEPRI 邊界basepri = (CPU_INT32U)(CPU_CFG_KA_IPL_BOUNDARY << (8u - CPU_CFG_NVIC_PRIO_BITS));CPU_REG_SYST_RVR = cnts - 1u; // 設置重載寄存器// 設置 SysTick 處理程序的優先級prio = CPU_REG_SCB_SHPRI3;prio &= 0x00FFFFFFu;prio |= (basepri << 24u);CPU_REG_SCB_SHPRI3 = prio;// 啟用計時器CPU_REG_SYST_CSR |= CPU_REG_SYST_CSR_CLKSOURCE | CPU_REG_SYST_CSR_ENABLE;// 啟用計時器中斷CPU_REG_SYST_CSR |= CPU_REG_SYST_CSR_TICKINT;}
3.4.2 BSP_OS_TickISR 接口實現
此接口函數用于處理系統時鐘滴答(SysTick)中斷
以下是該函數的偽代碼描述:
BSP_OS_TickISR:OS_CTX_SAVE ; 保存當前任務的上下文Disable Interrupts ; 禁用中斷OSIntNestingCtr++ ; 增加中斷嵌套計數器if (OSIntNestingCtr == 1) {OSTCBCurPtr->StkPtr = SP ; 如果這是第一個中斷,保存任務堆棧指針}Clear tick interrupt ; 清除滴答中斷標志OSTimeTick() ; 調用OSTimeTick,通知發生了一個滴答OSIntExit() ; 通知μC/OS-III中斷處理結束OS_CTX_RESTORE ; 恢復任務的上下文Return from Interrupt/Exception ; 返回到被中斷的任務
以下是ARM-Cortex-M/ARMv7-M/os_cpu_c.c已實現的接口:
void OS_CPU_SysTickHandler(void)
{CPU_SR_ALLOC();CPU_CRITICAL_ENTER();OSIntEnter(); /* 通知uC/OS-III我們正在進入一個ISR */CPU_CRITICAL_EXIT();OSTimeTick(); /* 調用uC/OS-III的OSTimeTick() */OSIntExit(); /* 通知uC/OS-III我們正在離開ISR */
}
3.4.3 OSCtxSw 接口移植
該函數接口實現任務級上下文切換,以下是該函數的匯編實現偽代碼:
; (1) 通過軟中斷調用OSCtxSw
OSCtxSw:OS_CTX_SAVE ; (2) 保存當前任務的CPU上下文LDR R0, =OSTCBCurPtrLDR R0, [R0]STR SP, [R0] ; (3) 將當前任務的堆棧指針保存到其TCBBL OSTaskSwHookLDR R0, =OSPrioHighRdyLDR R0, [R0]STR R0, =OSPrioCurLDR R0, =OSTCBHighRdyPtrLDR R0, [R0]LDR SP, [R0] ; (4) 從新任務的TCB中獲取堆棧指針OS_CTX_RESTORE ; (5) 恢復新任務的CPU上下文BX LR ; (6) 從中斷返回,恢復PC和SR
以下是ARM-Cortex-M/ARMv7-M/ARM/os_cpu_a.asm已實現的接口:
OSCtxSw
OSIntCtxSwLDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)LDR R1, =NVIC_PENDSVSETSTR R1, [R0]BX LR
3.4.4 OSIntCtxSw 接口移植
此函數用于在中斷上下文中進行任務切換,以下為該函數的匯編實現偽代碼:
在所有嵌套的ISR結束時由 OSIntExit() 調用
OSIntCtxSw:BL OSTaskSwHookLDR R0, =OSPrioHighRdyLDR R0, [R0]STR R0, =OSPrioCurLDR R0, =OSTCBHighRdyPtrLDR R0, [R0]LDR SP, [R0]OS_CTX_RESTOREBX LR
以下是ARM-Cortex-M/ARMv7-M/ARM/os_cpu_a.asm已實現的接口:
OSCtxSw
OSIntCtxSwLDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)LDR R1, =NVIC_PENDSVSETSTR R1, [R0]BX LR
3.4.5 OSStartHighRdy 接口移植
此函數用于啟動最高優先級的就緒任務,以下是該函數的匯編實現偽代碼:
OSStartHighRdy:BL OSTaskSwHook ; 調用任務切換鉤子函數LDR R0, =OSTCBHighRdyPtr ; 獲取最高優先級任務的TCB指針LDR R0, [R0]LDR SP, [R0] ; (1) 獲取最高優先級任務的堆棧指針OS_CTX_RESTORE ; (2) 恢復新任務的CPU上下文BX LR ; (3) 從中斷返回,恢復PC和SR
以下是ARM-Cortex-M/ARMv7-M/ARM/os_cpu_a.asm已實現的接口:
OSStartHighRdyCPSID I ; Prevent interruption during context switchMOV32 R0, NVIC_SYSPRI14 ; Set the PendSV exception priorityMOV32 R1, NVIC_PENDSV_PRISTRB R1, [R0]MOVS R0, #0 ; Set the PSP to 0 for initial context switch callMSR PSP, R0MOV32 R0, OS_CPU_ExceptStkBase ; Initialize the MSP to the OS_CPU_ExceptStkBaseLDR R1, [R0]MSR MSP, R1BL OSTaskSwHook ; Call OSTaskSwHook() for FPU Push & PopMOV32 R0, OSPrioCur ; OSPrioCur = OSPrioHighRdy;MOV32 R1, OSPrioHighRdyLDRB R2, [R1]STRB R2, [R0]MOV32 R0, OSTCBCurPtr ; OSTCBCurPtr = OSTCBHighRdyPtr;MOV32 R1, OSTCBHighRdyPtrLDR R2, [R1]STR R2, [R0]LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;MSR PSP, R0 ; Load PSP with new process SPMRS R0, CONTROLORR R0, R0, #2BIC R0, R0, #4 ; Clear FPCA bit to indicate FPU is not in useMSR CONTROL, R0ISB ; Sync instruction streamLDMFD SP!, {R4-R11, LR} ; Restore r4-11, lr from new process stackLDMFD SP!, {R0-R3} ; Restore r0, r3LDMFD SP!, {R12, LR} ; Load R12 and LRLDMFD SP!, {R1, R2} ; Load PC and discard xPSRCPSIE IBX R1
3.4.6 OS_CPU_PendSVHandler 接口實現
此接口函數用于引發上下文切換,以下是該函數的實現步驟和詳細代碼
獲取進程堆棧指針:將進程堆棧指針(PSP)保存到R0
保存剩余寄存器:將寄存器R4-R11和R14保存到進程堆棧
保存進程堆棧指針:將進程堆棧指針保存到當前任務的TCB中
調用OSTaskSwHook:執行任務切換鉤子函數
更新當前任務和準備就緒任務:更新當前任務的優先級和TCB指針
獲取新任務堆棧指針:從準備就緒任務的TCB中獲取堆棧指針,并將其加載到PSP中
恢復寄存器:從新任務堆棧恢復寄存器R4-R11和R14
恢復上下文:從異常返回,恢復剩余上下文
以下是ARM-Cortex-M/ARMv7-M/ARM/os_cpu_a.asm已實現的接口:
OS_CPU_PendSVHandler:CPSID I ; 禁止中斷MOV32 R2, OS_KA_BASEPRI_Boundary ; 設置BASEPRI優先級LDR R1, [R2]MSR BASEPRI, R1DSBISBCPSIE IMRS R0, PSP ; 獲取進程堆棧指針IF {FPU} != "SoftVFP"TST R14, #0x10IT EQVSTMDBEQ R0!, {S16-S31} ; 如果任務使用FPU,保存高位FPU寄存器ENDIFSTMFD R0!, {R4-R11, R14} ; 保存R4-R11和R14寄存器MOV32 R5, OSTCBCurPtr ; 保存當前任務的堆棧指針LDR R1, [R5]STR R0, [R1]MOV R4, LR ; 保存LR寄存器值BL OSTaskSwHook ; 調用任務切換鉤子函數MOV32 R0, OSPrioCur ; 更新當前任務優先級MOV32 R1, OSPrioHighRdyLDRB R2, [R1]STRB R2, [R0]MOV32 R1, OSTCBHighRdyPtr ; 更新當前任務的TCB指針LDR R2, [R1]STR R2, [R5]ORR LR, R4, #0x04 ; 確保異常返回使用進程堆棧LDR R0, [R2] ; 獲取新任務的堆棧指針LDMFD R0!, {R4-R11, R14} ; 恢復R4-R11和R14寄存器IF {FPU} != "SoftVFP"TST R14, #0x10IT EQVLDMIAEQ R0!, {S16-S31} ; 恢復高位FPU寄存器ENDIFMSR PSP, R0 ; 加載新的進程堆棧指針MOV32 R2, #0 ; 恢復BASEPRI優先級CPSID IMSR BASEPRI, R2DSBISBCPSIE IBX LR ; 異常返回,將恢復剩余上下文ALIGNEND
4. 移植 uC/CPU
uC-CPU/BSP/Template/bsp_cpu.c 有以下CPU時間戳相關接口需要實現:
CPU_TS_TmrInit() //CPU 時間戳計時器初始化
CPU_TS_TmrRd() //獲取當前 CPU 時間戳計時器的計數值?
CPU_TS32_to_uSec() //將時間戳計數轉換為微秒
如果啟用了 CPU 時間戳或 CPU 中斷禁用時間測量功能,必須實現這些接口
uC-CPU/Template/cpu_a.asm 有以下接口需要實現:
CPU_IntDis ;禁用中斷
CPU_IntEn ;啟用中斷
CPU_SR_Save ;保存CPU狀態寄存器
CPU_SR_Restore ;恢復CPU狀態寄存器
CPU_CntLeadZeros;計數前導零
uC-CPU/ARM-Cortex-M/ARMv7-M/ARM/cpu_a.asm 已實現上述接口
4.1 CPU_TS_TmrInit() 接口移植
該接口是CPU 時間戳計時器初始化函數 , 該計時器用于記錄精確的時間戳或測量 CPU 禁用中斷的時間。以下是基于GD32F303的實現代碼:
void CPU_TS_TmrInit (void)
{CPU_INT32U fclk_freq;fclk_freq = BSP_CPU_ClkFreq();BSP_REG_DEM_CR |= (CPU_INT32U)BSP_BIT_DEM_CR_TRCENA; /* Enable Cortex-M4's DWT CYCCNT reg. */BSP_REG_DWT_CYCCNT = (CPU_INT32U)0u;BSP_REG_DWT_CR |= (CPU_INT32U)BSP_BIT_DWT_CR_CYCCNTENA;CPU_TS_TmrFreqSet((CPU_TS_TMR_FREQ)fclk_freq);
}
4.2 CPU_TS_TmrRd 接口移植
該 函數用于獲取當前 CPU 時間戳計時器的計數值,以下是基于GD32F303的實現代碼:
CPU_TS_TMR CPU_TS_TmrRd (void)
{CPU_TS_TMR ts_tmr_cnts;ts_tmr_cnts = (CPU_TS_TMR)BSP_REG_DWT_CYCCNT;return (ts_tmr_cnts);
}
4.3 CPU_TS32_to_uSec 接口移植
該函數用于將時間戳計數轉換為微秒,以下是基于GD32F303的實現代碼:
CPU_INT64U CPU_TS32_to_uSec (CPU_TS32 ts_cnts)
{CPU_INT64U ts_us;CPU_INT64U fclk_freq;fclk_freq = BSP_CPU_ClkFreq();ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);return (ts_us);
}
5. 移植驗證
5.1. 構建工程目錄
├── app // 應用程序
├── bsp // 板級支持包,包含系統需要移植的接口及硬件相關庫文件及接口
????????└── gd32f30x
????????????????├── bsp.c //需要移植的接口
????????????????├── bsp.h
????????????????├── gd32f30x_it.c
????????????????├── gd32f30x_it.h
????????????????├── gd32f30x_libopt.h
????????????????├── Library
????????????????├── mdk-project
├── uC-CFG //把 uC-CPU 及uC-OS3 需要配置的文件集中到此文件夾
├── uC-CPU
├── uC-LIB
└── uC-OS3