Ucos III系统移植到复旦微FMQL
一、写在前面
本文记录将µC/OS-III从Zynq平台移植到复旦微FMQL20(国产Zynq)的完整过程。整体思路是:先在Zynq上跑通官方移植方案,再以此为参考,逐一替换平台相关模块,移植到FMQL平台。
之所以采用这个路线,是因为:
- Zynq平台有Micrium官方提供的开箱即用移植方案,网上资料丰富
- FMQL是国产化Zynq替代方案,ARM部分为四核Cortex-A7(Zynq为双核Cortex-A9),同属Armv7架构
- 复旦微没有像Xilinx SDK那样完整的闭环开发工具链,需要使用IAR + Procise的组合
关于开发环境:Zynq使用Vivado + SDK(eclipse定制版),生态闭环;FMQL使用Vivado + Procise + IAR的组合。Procise相当于“低配版SDK”,负责生成BSP和导出工程到IAR。
二、Zynq平台µC/OS-III移植(参考基础)
2.1 环境准备
- Vivado 2018.3:与Zynq-7000系列兼容性最佳
- 正点原子Zynq开发板
- USB转串口工具:用于调试信息输出
2.2 Vivado硬件工程创建
- 创建Vivado工程
- 添加ZYNQ Processing System IP,创建PS系统
- 导出硬件到SDK,创建PS SDK程序
2.3 获取并导入µC/OS-III源码
- 获取官方移植包:Micrium官方为ZYNQ Cortex-A9提供了开箱即用的移植方案,从GitHub获取:zynq_guide/ucos at main · suisuisi/zynq_guide · GitHub,下载
ucos_v1_45.7z压缩包
- 将其移动到Vivado目录下方便管理,我是保存在了
...\Xilinx2018.3\SDK\2018.3\data\embeddedsw\ucos_v1_45 - 在SDK中导入源码(Local Repositories方式):
- 菜单
Xilinx → Repositories
- 在
Global Repositories中添加ucos,并确认(如果不想全局使用只想单个项目使用就添加到Local Repositories)
- 菜单
2.4 创建µC/OS-III应用工程
- 在SDK中新建Application Project,关键参数:
- Project name: ucos_hello_world
- OS Platform: 选择"ucos"(导入源码后才会出现)
- Template: Micrium uc/OS-III Hello World

- 工程创建后自动生成:
src/app.c- 主程序入口system.mss- BSP配置文件ucos_bsp/- 板级支持包
2.5 BSP关键配置
- 点击打开Ucos III BSP支持包界面
- 选择
Modify this BSP's Settings- 勾选这几个必要选项:

- 打开
ucos_standalone配置stdin和stdout
- 勾选这几个必要选项:
三、从Zynq到FMQL的移植
3.1 FMQL与Zynq的核心差异
在开始移植前,需要理解两个平台的关键差异:
- ARM 核:Xilinx Zynq 采用双核 Cortex‑A9,复旦微 FMQL 采用四核 Cortex‑A7。
- ARM 架构:两者同属 Armv7‑A,指令集兼容,为移植提供了基础。
- 开发环境:Zynq 使用 Vivado + SDK(Xilinx 定制 Eclipse);FMQL 使用 Vivado + Procise + IAR EWARM。
- 调试工具:Zynq 通常使用标准 JTAG;FMQL 可使用 JTAG‑Cable 或 J‑Link。
- IDE:Zynq 的 SDK 基于 Eclipse 定制;FMQL 以 IAR EWARM 为主 IDE。
- BSP 生成:Zynq 由 SDK 自动生成;FMQL 由 Procise 生成后再导出到 IAR 工程。
ARM核同属Armv7架构,指令集兼容,但外设寄存器地址、中断控制器、定时器等底层硬件不同,需要逐个替换平台相关代码。
3.2 环境搭建
必备工具:
- Vivado:与Zynq相同,用于PL端开发
- Procise:复旦微配套软件,用于生成BSP和导出IAR工程
- IAR EWARM:FMQL ARM端的主开发环境
3.3 移植总体策略
µC/OS-III内核源码保持Micrium原版不变,所有平台相关部分按以下原则替换:
- 中断控制器:Zynq 使用 Xilinx 的 XScuGic 驱动;FMQL 替换为复旦微自研的 FGicPs 驱动,两者接口不同,需重新适配 GIC 初始化、中断使能/禁止及中断连接函数。
- 系统 Tick 定时器:Zynq 常用 SCU Timer 作为系统时钟节拍源;FMQL 采用 TTC(Triple Timer Counter),对应驱动为 FTtcPs,需要重新实现定时器配置、中断处理及
OSTimeTick()的调用。 - 串口打印:Zynq 使用
xil_printf系列函数输出调试信息;FMQL 底层打印接口为fmsh_print,因此需要将UCOS_Printf和UCOS_Print的实现替换为基于fmsh_print的版本。 - PS 初始化:Zynq 的板级初始化入口为
ps7_init;FMQL 对应的初始化函数为ps_init,需要在底层启动流程中调用正确的初始化函数。 - 启动与异常向量:Zynq 使用 GNU 汇编文件
ucos_vectors.S提供向量表及安装逻辑;FMQL 在 IAR 环境下使用ucos_cstartup.s,这是一个完整的复位启动文件,包含resetHandler入口、向量表、栈初始化及 VBAR 设置,且链接时必须指定入口为resetHandler。 - CPU/OS 汇编 port:Zynq 的 CPU 抽象层和 OS 移植层使用 GNU 汇编(
.S文件);FMQL 配合 IAR 编译器,必须使用对应的 IAR 汇编语法文件(.s),包括cpu_a.s和os_cpu_a_vfp-none.s,不能混用不同工具链的汇编源文件。
3.4 移植文件组织情况
Export Hardware:选择导出Empty和FSBL(也可以不导出Empty在IAR直接创建UCOS III工程)- 在IAR修改Empty工程为UCOS III工程
- 添加组织文件:用于保存各类源码,其中FM_QL_bsp是Procise导出工程自动生成的,FM_QL_ucos_bsp是需要自己组织的,UcosIII_Test是应用工程

- 添加组织文件:用于保存各类源码,其中FM_QL_bsp是Procise导出工程自动生成的,FM_QL_ucos_bsp是需要自己组织的,UcosIII_Test是应用工程
- FM_QL_ucos_bsp的文件作用:
- ucos_common_v1_45:提供 uC/CPU 硬件抽象层(中断开关、临界区、位操作等)和 uC/LIB 基础库(字符串、内存、数学辅助)

- ucos_osiii_v1_45:包含 uC/OS-III 全部内核源文件,以及针对 ARMv7-A + IAR 的汇编移植文件(
os_cpu_a_vfp-none.s)
- ucos_standalone_v1_45:提供 FMQL 平台的最小初始化与打印支撑,替代原 Xilinx standalone 库。

- ucos_v1_45:包含顶层 BSP 适配文件
fmql_ucos_bsp.c、启动汇编ucos_cstartup.s、中断接口声明ucos_int.h以及应用配置app_cfg.h。
- ucos_common_v1_45:提供 uC/CPU 硬件抽象层(中断开关、临界区、位操作等)和 uC/LIB 基础库(字符串、内存、数学辅助)
四、新增与修改的平台适配文件说明
本章说明在移植过程中新增编写和基于原 Zynq BSP 修改的文件。其中一部分是工具链相关的汇编 port 文件,另一部分是 FMQL 平台自己的 BSP 胶水层。这些文件的共同点是:它们都与具体硬件平台或编译工具链绑定,不能直接沿用 Zynq BSP 中对应文件。
4.1 新增的平台适配文件
cpu.h- 文件位置:
ucos_common_v1_45/src/uC-CPU/ARM-Cortex-A/ARMv7-A/IAR/cpu.h - 本文件定义 ARMv7-A CPU port 的数据类型、堆栈格式、大小端配置、临界区进入/退出接口、内存屏障指令封装,以及若干底层汇编函数的声明。本工程移植时,参照了 Micrium 官方提供的 ARMv7-A GNU port 的接口定义与运行语义,将其按 IAR EWARM 编译器的语法规则重新编写,形成此 IAR 版本。
- 文件位置:
cpu_a.s- 文件位置:
ucos_common_v1_45/src/uC-CPU/ARM-Cortex-A/ARMv7-A/IAR/cpu_a.s - 本文件是
cpu.h中声明的底层 CPU 操作的汇编实现,包括关中断/开中断(含状态保存与恢复)、WFI/WFE等待指令、前导零/尾随零计数(CLZ/RBIT+CLZ)、数据同步屏障(DSB)等。该文件以 GNU 版本cpu_a.S的功能语义为蓝本,按 IAR 汇编语法重新实现。
- 文件位置:
os_cpu.h- 文件位置:
ucos_osiii_v1_45/src/uCOS-III/Ports/ARM-Cortex-A/ARMv7-A/IAR/os_cpu.h - 本文件是 uC/OS-III 与 ARMv7-A CPU port 的接口头文件,定义了异常编号、任务栈初始化接口、上下文切换相关声明等。其内容与工具链相关,同样必须选用 IAR 版本。
- 文件位置:
os_cpu_a_vfp-none.s- 文件位置:
ucos_osiii_v1_45/src/uCOS-III/Ports/ARM-Cortex-A/ARMv7-A/IAR/os_cpu_a_vfp-none.s - 本文件是 uC/OS-III 最核心的 ARMv7-A 汇编 port,负责首次任务启动、任务切换、异常入口现场保存与恢复、调用
OS_CPU_ExceptHndlr()进行中断分发,以及在中断退出时调用OSIntExit()检查是否需要任务切换。本文件是以 GNU 版本os_cpu_a_vfp-none.S的功能为基准,按 IAR 汇编语法重新编写而成的 IAR 版本。文件名的vfp-none后缀表示不保存 VFP 浮点上下文,这是当前工程的一个配置选择;如果后续任务使用硬浮点或 NEON 指令,需要重新评估该选项。
- 文件位置:
fmql_ucos_bsp.c- 文件位置:
ucos_v1_45/src/fmql_ucos_bsp.c - 本文件是 FMQL 平台 BSP 适配层的核心 C 文件,它并非简单地“裁剪” Zynq 的某个文件,而是将 Zynq BSP 中分散在多个文件里的平台相关功能,统一在 FMQL 的硬件接口上重新实现。具体替代关系如下:
- 替代
ucos_startup.c中的启动流程函数:UCOSStartup():负责调用底层初始化、CPU_Init()、Mem_Init()、OSInit(),创建启动任务并启动调度器。UCOSStartupTask():作为启动任务实体,调用后续各项子初始化,最后跳转到用户主函数。UCOS_StdInOutInit()和UCOS_PrintfInit():在 FMQL 中为空实现,实际打印功能由UCOS_Print/Printf直接驱动硬件。UCOS_Print()和UCOS_Printf():用于调试追踪输出,FMQL 直接实现为调用fmsh_print,替代了原版基于outbyte的输出方式。
- 替代
ps7/ucos_impl.c中的底层初始化:UCOS_LowLevelInit():FMQL 版本执行init_platform()(更完整的板级初始化)和UCOS_IntInit(),取代了 Zynq 版本的Xil_DCacheFlush()+UCOS_IntInit()。UCOS_StartupInit():FMQL 版本为空实现,因为向量表安装已在汇编文件ucos_cstartup.s中完成,而 Zynq 版本需要调用_install_ucos_vector_table()。
- 替代
ps7/ucos_int_impl.c中的 GIC 中断控制接口:UCOS_IntInit():负责初始化 GIC 中断控制器。Zynq 使用XScuGic+Xil_Exception,FMQL 使用自研的FGicPs驱动完成初始化。UCOS_IntSrcEn()/UCOS_IntSrcDis():分别调用FGicPs_Enable()/FGicPs_Disable()使能或禁止指定中断。UCOS_IntPrioSet()、UCOS_IntTargetSet()、UCOS_IntTypeSet():通过FGicPs_SetPriorityTriggerType()和FGicPs_InterruptMaptoCpu()设置中断优先级、目标 CPU 和触发类型。UCOS_IntVectSet():一站式注册中断,调用FGicPs_Connect()绑定 ISR。OS_CPU_ExceptHndlr():由汇编异常入口调用,负责分发 IRQ/FIQ。Zynq 版本通过switch调用IRQInterrupt()/FIQInterrupt(),FMQL 版本直接调用FGicPs_InterruptHandler_IRQ()或FGicPs_InterruptHandler_FIQ()。
- 替代
bsp/ps7/ucos_osiii_bsp.c中的系统 tick 实现:UCOS_TmrTickInit():初始化系统时钟节拍定时器,FMQL 使用 TTC,Zynq 使用 SCU Timer,配置方式不同但功能等价。UCOSTmrTickHandler():作为定时器中断服务函数,清除中断标志并调用OSTimeTick()。
- 替代
ucos_printf.c和ucos_stdinout.c中的打印与输入输出:UCOS_Printf():使用标准vsnprintf()格式化后调用fmsh_print()输出,替代原版的自定义格式解析和outbyte方式。UCOS_Print():直接调用fmsh_print()输出字符串。UCOS_Read():空实现,返回 0。
- 替代
- 文件位置:
ucos_cstartup.s- 文件位置:
ucos_v1_45/src/ucos_cstartup.s - 本文件是 FMQL 平台完整的 IAR 复位启动文件,提供
resetHandler入口、异常向量表、各 CPU 模式栈初始化、CP15 系统控制寄存器配置、VFP 使能、VBAR 设置,最后跳转到main。它与 Zynq 的ucos_vectors.S有本质区别:Zynq 版本仅提供向量表和安装函数,在运行时将向量表切换到 uC/OS 版本;而 FMQL 版本是芯片复位后的第一段执行代码,从复位入口开始完整接管启动流程。因此 IAR 链接配置中必须将程序入口指定为resetHandler,并配合a7_axisram.icf链接脚本使用。
- 文件位置:
4.2 基于原文件修改的配置文件
以下文件是在原 Zynq BSP 对应文件基础上修改而来。修改分为两类:一类是平台相关的必要调整(如中断号、硬件初始化方式),另一类是根据当前应用需求对内核功能模块做裁剪。裁剪部分并非 FMQL 硬件强制要求,而是为了精简系统、减小资源占用;如果后续应用需要对应功能,可以重新打开。
cpu_cfg.h- 文件位置:
ucos_common_v1_45/src/cpu_cfg.h - 本文件的主要修改包括:
- 关闭 32 位和 64 位时间戳支持(
CPU_CFG_TS_32_EN/CPU_CFG_TS_64_EN设为DEF_DISABLED),说明当前工程不依赖 uC/CPU 的时间戳模块。 - 保持启用 ARM 汇编优化的前导零和尾随零计数(
CPU_CFG_LEAD_ZEROS_ASM_PRESENT/CPU_CFG_TRAIL_ZEROS_ASM_PRESENT),使用CLZ和RBIT+CLZ指令实现,这也是 ARMv7-A port 的常规做法,并非 FMQL 特有。 - 关闭缓存管理 API(
CPU_CFG_CACHE_MGMT_EN = DEF_DISABLED)。当前 PL UART echo 应用不涉及 DMA 或 cacheable buffer 与外设共享,因此可以关闭;后续若使用 DMA、网络、USB、SD 卡等,需要重新启用并提供 FMQL 对应的 cache flush/invalidate 实现。 CPU_CFG_NVIC_PRIO_BITS宏设为 4,该宏原本是 Cortex-M NVIC 控制器的配置项,在 Cortex-A7 + GIC 路径上没有实际作用,属于模板遗留配置,保留它不影响当前功能。
- 关闭 32 位和 64 位时间戳支持(
- 文件位置:
os_cfg.h- 文件位置:
ucos_osiii_v1_45/src/os_cfg.h - 本文件主要对 uC/OS-III 内核功能模块进行开关控制。与 Zynq 模板相比,以下模块被关闭:
- 事件标志组(
OS_CFG_FLAG_EN = 0u) - 内存分区管理(
OS_CFG_MEM_EN = 0u) - 消息队列(
OS_CFG_Q_EN = 0u) - 任务消息队列(
OS_CFG_TASK_Q_EN = 0u) - 软件定时器(
OS_CFG_TMR_EN = 0u,不影响 TTC 硬件 tick) - 任务私有寄存器(
OS_CFG_TASK_REG_TBL_SIZE = 0u)
- 事件标志组(
- 保留开启的模块包括信号量(
OS_CFG_SEM_EN = 1u)和互斥量(OS_CFG_MUTEX_EN = 1u),用于 PL UART 回显应用中的 ISR 与任务同步,以及控制台打印的互斥保护。
- 文件位置:
os_cfg_app.h- 文件位置:
ucos_osiii_v1_45/src/os_cfg_app.h - 本文件与应用级配置相关。主要修改是将消息池容量设为 0(
OS_CFG_MSG_POOL_SIZE = 0u),与消息队列裁剪保持一致。系统 tick 频率保持为 1000 Hz(OS_CFG_TICK_RATE_HZ = 1000u),空闲任务栈大小保持为 256 字,这两项与 Zynq 模板一致。
- 文件位置:
app_cfg.h- 文件位置:
ucos_v1_45/src/app_cfg.h - 本文件是 FMQL 顶层 BSP 的应用配置头文件,与 Zynq 模板相比有以下新增和调整:
- 新增启动任务参数:
UCOS_START_TASK_PRIO设为 5,UCOS_START_TASK_STACK_SIZE设为 1024,以及UCOS_START_DEBUG_TRACE启用调试打印。这些宏被fmql_ucos_bsp.c直接使用。 - 新增中断相关配置:
UCOS_TICK_INT_PRIO设为 0xA0(即 160),指定系统 tick 中断在 GIC 中的优先级;UCOS_GIC_CPU0_TARGET设为 0x01,指定中断目标为 CPU0。 - 关闭
APP_COMMON_ENABLED(设为DEF_DISABLED),进一步精简对 µC/Common 通用模块的依赖。
- 新增启动任务参数:
- 文件位置:
ucos_bsp.h- 文件位置:
ucos_v1_45/src/ucos_bsp.h - 本文件是 BSP 对应用层暴露的接口声明。与 Zynq 版本相比:
- FMQL 版本只定义了三种简单类型宏(CPU 类型、UART 类型、系统定时器类型),没有引入 TCP/IP、Shell、文件系统、USB 等可选中间件相关的类型或声明。
- 声明的 BSP 函数仅限于最基础的 9 个:
UCOS_LowLevelInit、UCOS_StartupInit、UCOS_TmrTickInit、UCOSStartup、UCOS_StdInOutInit、UCOS_PrintfInit、UCOS_Print、UCOS_Printf、UCOS_Read。去除了 Zynq 版本中大量的可选中间件初始化函数声明(如 Shell、DHCP、DNS、HTTP、MQTT、Telnet、iPerf、USB 等)。 - FMQL 版本只包含
cpu.h和lib_def.h,不依赖ucos_impl.h或 Xilinx 异常框架头文件,所有的平台实现细节都封闭在fmql_ucos_bsp.c内部。
- 文件位置:
ucos_int.h- 文件位置:
ucos_v1_45/src/ucos_int.h - 本文件是中断接口声明头文件。与 Zynq 版本相比:
- FMQL 版本只包含
cpu.h和lib_def.h,没有引入xil_exception.h或ucos_int_impl.h,因此不依赖 Xilinx 的异常处理框架。 - 在自身文件中直接定义了
UCOS_INT_FNCT_PTR(中断回调函数指针类型)和UCOS_INT_TYPE(中断号类型),确保了头文件的完整性和自包含性。 - Zynq 版本则将这两个类型的定义放在
ucos_int_impl.h中,通过包含关系间接获取,与 Xilinx 的Xil_InterruptHandler类型绑定。
- FMQL 版本只包含
- 文件位置:
五、总结
从Zynq到FMQL的µC/OS-III移植,核心是平台相关代码的逐块替换,而非从头移植。关键工作包括:
- 工具链适配:GNU汇编 → IAR汇编
- 启动代码重写:ucos_vectors.S → ucos_cstartup.s
- 中断控制器替换:XScuGic → FGicPs
- 定时器替换:SCU Timer → FTtcPs
- 打印输出替换:xil_printf → fmsh_print
- 开发环境切换:SDK → Procise + IAR
FMQL与Zynq同属Armv7架构,指令集兼容,这大大降低了移植难度。主要工作量集中在外设驱动层和工具链适配层。掌握Zynq上的移植流程后,对照替换上述模块,即可在FMQL平台上顺利运行µC/OS-III。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)