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      LR3.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      LR3.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       R13.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                              ; 异常返回,将恢复剩余上下文ALIGNEND4. 移植 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
5.2 构建Keil工程

