UCOS-III 系统移植

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, =OSTCBCurPtr
    LDR     R0, [R0]
    STR     SP, [R0]         ; (3) 将当前任务的堆栈指针保存到其TCB
    BL      OSTaskSwHook
    LDR     R0, =OSPrioHighRdy
    LDR     R0, [R0]
    STR     R0, =OSPrioCur
    LDR     R0, =OSTCBHighRdyPtr
    LDR     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
OSIntCtxSw
    LDR     R0, =NVIC_INT_CTRL      ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]
    BX      LR

3.4.4 OSIntCtxSw 接口移植

此函数用于在中断上下文中进行任务切换,以下为该函数的汇编实现伪代码:

在所有嵌套的ISR结束时由 OSIntExit() 调用
OSIntCtxSw:
    BL      OSTaskSwHook
    LDR     R0, =OSPrioHighRdy
    LDR     R0, [R0]
    STR     R0, =OSPrioCur
    LDR     R0, =OSTCBHighRdyPtr
    LDR     R0, [R0]
    LDR     SP, [R0]
    OS_CTX_RESTORE
    BX      LR

以下是ARM-Cortex-M/ARMv7-M/ARM/os_cpu_a.asm已实现的接口:

OSCtxSw
OSIntCtxSw
    LDR     R0, =NVIC_INT_CTRL      ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     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已实现的接口:

OSStartHighRdy
    CPSID   I                                                   ; Prevent interruption during context switch
    MOV32   R0, NVIC_SYSPRI14                                   ; Set the PendSV exception priority
    MOV32   R1, NVIC_PENDSV_PRI
    STRB    R1, [R0]
    MOVS    R0, #0                                              ; Set the PSP to 0 for initial context switch call
    MSR     PSP, R0
    MOV32   R0, OS_CPU_ExceptStkBase                            ; Initialize the MSP to the OS_CPU_ExceptStkBase
    LDR     R1, [R0]
    MSR     MSP, R1
    BL      OSTaskSwHook                                        ; Call OSTaskSwHook() for FPU Push & Pop
    MOV32   R0, OSPrioCur                                       ; OSPrioCur   = OSPrioHighRdy;
    MOV32   R1, OSPrioHighRdy
    LDRB    R2, [R1]
    STRB    R2, [R0]
    MOV32   R0, OSTCBCurPtr                                     ; OSTCBCurPtr = OSTCBHighRdyPtr;
    MOV32   R1, OSTCBHighRdyPtr
    LDR     R2, [R1]
    STR     R2, [R0]
    LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;
    MSR     PSP, R0                                             ; Load PSP with new process SP
    MRS     R0, CONTROL
    ORR     R0, R0, #2
    BIC     R0, R0, #4                                          ; Clear FPCA bit to indicate FPU is not in use
    MSR     CONTROL, R0
    ISB                                                         ; Sync instruction stream
    LDMFD    SP!, {R4-R11, LR}                                  ; Restore r4-11, lr from new process stack
    LDMFD    SP!, {R0-R3}                                       ; Restore r0, r3
    LDMFD    SP!, {R12, LR}                                     ; Load R12 and LR
    LDMFD    SP!, {R1, R2}                                      ; Load PC and discard xPSR
    CPSIE    I
    BX       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, R1
    DSB
    ISB
    CPSIE   I
    MRS     R0, PSP                         ; 获取进程堆栈指针
    IF {FPU} != "SoftVFP"
        TST       R14, #0x10
        IT        EQ
        VSTMDBEQ  R0!, {S16-S31}            ; 如果任务使用FPU,保存高位FPU寄存器
    ENDIF
    STMFD   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, OSPrioHighRdy
    LDRB    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, #0x10
        IT        EQ
        VLDMIAEQ  R0!, {S16-S31}            ; 恢复高位FPU寄存器
    ENDIF
    MSR     PSP, R0                         ; 加载新的进程堆栈指针
    MOV32   R2, #0                          ; 恢复BASEPRI优先级
    CPSID   I
    MSR     BASEPRI, R2
    DSB
    ISB
    CPSIE   I
    BX      LR                              ; 异常返回,将恢复剩余上下文
    ALIGN
    END

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

5.2  构建Keil工程 

5.3 编译验证

编译运行,发现系统没有跑起来, 用单步调试定位到时系统时钟没有正常工作,检查发现gd32f30x 的启动文件startup_gd32f30xx.s 定义的PendSV Handler SysTick Handler 中断入口与前面移植的接口名称不一致,修改startup_gd32f30xx.s后,编译运行正常。

5.4 工程代码

请参考:https://github.com/jslaobing/techIot_ucosiii_porting

  • 52
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TechIoT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值