ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

华为LiteOS在STM32F103ZET6上的移植实战:从零到跑通多任务

华为LiteOS在STM32F103ZET6上的移植实战:从零到跑通多任务 简介面向嵌入式与物联网开发者针对STM32F103ZET6硬件平台提供华为LiteOS移植的完整工程包解决在Cortex-M3内核微控制器上高效运行LiteOS的关键问题适合需要掌握RTOS移植流程或快速搭建低功耗物联网应用的中高级嵌入式工程师使用。压缩包共506个文件以C语言源码与头文件、编译中间文件、工程配置文件和说明文档等为主包含野火标准库基础例程整体大小约8.49MB已有1840人学习下载。资源不仅包含可直接编译的移植源码还覆盖内核参数配置、中断服务适配、外设初始化、LED任务创建、时钟源选择与启动调试等完整移植要点配合串口调试与排错思路可帮助理解LiteOS任务调度和内存管理机制同时提供信号量、消息队列等复杂功能的扩展思路适合作为开发基础和工程参考。 最近要给一个基于STM32F103ZET6的设备选嵌入式操作系统需求很明确轻量、免费、能跑多任务和消息队列后面还可能要对接物联网平台。FreeRTOS我熟但这回更倾向华为生态最后翻牌的是华为LiteOS。网上讲FreeRTOS移植的文章一抓一大把LiteOS在F103上的完整移植教程却没那么多而且版本差异大照着老文章容易卡壳。这篇就记录我从零开始的LiteOS移植过程包括源码选型、内核配置、中断适配、真机调试踩坑帮你避开我走过的弯路。已经在用STM32标准库、想从裸机或FreeRTOS过渡到LiteOS的开发者可以直接参考我的路线。1. 移植前先把内核和硬件都摸个底1.1 LiteOS到底是怎么一款系统华为LiteOS是面向物联网终端的轻量级实时操作系统内核代码精炼支持任务、信号量、互斥锁、消息队列、软定时器还有事件、内存管理等组件。它和OpenHarmony的LiteOS-M在实现思路上有不少相通之处你在Gitee或GitHub上拉到的LiteOS仓库核心目录基本都是kernel、arch、components、targets这个结构。与FreeRTOS相比LiteOS不只是一个内核它还围绕物联网场景提供shell、文件系统、联网协议等组件方便和华为云IoT生态对接。缺点也很明显版本迭代快文档跟着版本走网上教程参差不齐新手直接上手最新代码容易被各种宏定义搞晕。我的建议是第一轮移植别追求新挑一个官方targets里有相近芯片例程的分支先把内核跑通再说。1.2 ZET6这块板子跑LiteOS够不够STM32F103ZET6属于F1系列里的高配72MHz主频、512KB Flash、64KB SRAM、144引脚外设丰富。LiteOS内核本身非常小一个最小可调度内核编译出来ROM往往只有几KB到十几KBRAM占用也才几KB跟裸机开几个外设的差异不大。所以从资源占用看ZET6跑LiteOS绰绰有余512KB Flash对后续接LVGL、协议栈、文件系统也都是友好配置。唯一需要注意的是Cortex-M3没有FPU官方一些demo会使用浮点类型做运算搬到F1上要么改用定点要么接受软浮点的性能开销。比如智能小车场景里做PID直接用float在F1上仍可接受但尽量避免在高频中断里做大量浮点运算。2. 环境准备和源码选型2.1 开发环境怎么配我使用的是MDK5加ST-Link配合STM32标准外设库StdPeriph。为什么不直接用HAL因为LiteOS内核移植和HAL关系不大标准库生成的裸机工程更干净容易看清中断、时钟这些底层逻辑。如果你习惯寄存器开发也没有问题只要能保证“LED能点、串口能打印”这个最小工程稳定即可。调试器方面ST-Link/V2几十块钱配合MDK的调试功能足够用。另外串口助手必须备好后面移植成功的标志很大程度靠串口输出判断别等出了问题才临时找工具。我习惯用串口打印代替在线调试因为RTOS跑起来后单步调试经常会遇到“一暂停就进HardFault”的尴尬串口输出反而更可靠。2.2 源码拉取和目录识别拉LiteOS源码有两种思路一种直接clone整个仓库体积大但完整另一种只下载release分支或tag相对稳定。打开仓库后先别急着全编先看targets目录找找有没有Cortex-M3/M4内核的开发板例程。官方一般会提供STM32F429、STM32F407这类芯片的target工程里面包含了内核代码的组织方式、配置文件位置以及arch层汇编文件。我是这样操作的把targets里某个相近芯片的工程复制作为底盘然后把板级驱动部分删掉替换成自己ZET6的外设初始化代码。这样比凭空创建目录树要高效得多也能避免漏掉某个必要文件。第一次移植时我建议不要打开某个“精简专区”就开始对照尽量以官方targets工程为准因为LiteOS不同分支的目录变化确实不小。3. 移植实操一次跑通的完整路径3.1 先把裸机工程跑起来这一步容易被人省略我建议不要省。基于标准外设库新建一个最小工程把系统时钟配成72MHz串口1初始化LED引脚初始化printf重定向到串口然后烧进去确认能正常输出。为什么非要做这一步因为后面加入RTOS代码后所有问题都从“外设有没有问题”和“内核有没有问题”两个方向排查。如果裸机部分都没验证过一开始就把LiteOS加进来一旦不工作排查面会非常广。这个最小工程后面会作为整个移植的宿主。我实际测试时裸机printf输出正常后才开始动LiteOS相关文件整体定位问题的速度明显快很多。3.2 把LiteOS核心文件加进工程从官方相近targets工程里把内核相关源文件加进MDK工程。通常需要包括arch层针对Cortex-M3的汇编启动切换文件、调度器相关文件kernel层任务管理、软件定时器、信号量、互斥锁、消息队列等实现lib层内核依赖的基础库实现。头文件路径也要同步添加主要是los_config.h所在目录、arch相关目录、kernel目录。加文件时注意官方target工程里可能会有与开发板强相关的板级驱动这些不要复制。我的习惯是新建一个“LiteOS”分组把添加的文件按arch、kernel、lib归类放好后面查代码、看编译错误都方便。如果编译报错说找不到某头文件先把include路径补全如果报函数重复定义重点看是不是把官方targets里的main也复制进来了。这一步看起来枯燥但文件组织越清晰后面和版本差异斗争时越省心。3.3 内核配置los_config.h是关键每个版本的内核配置文件名字可能不同有的是los_config.h有的是target_config.h本质都是内核裁剪的总开关。以下是我这一版用到的主要配置项可以参考对照自己的源码配置宏作用备注LOSCFG_BASE_CORE内核基础功能总开关关掉就没有任务调度了LOSCFG_BASE_CORE_TICK_HW_TIME硬件时钟源相关配合SysTick使用LOSCFG_BASE_CORE_TICK_HW_INT使能tick中断需要配置SysTick周期LOSCFG_BASE_CORE_TIMESLICE时间片轮转多个同优先级任务调度LOSCFG_BASE_CORE_TASK任务管理必须开启LOSCFG_BASE_IPC_SEM信号量按需开启LOSCFG_BASE_IPC_MUX互斥锁按需开启LOSCFG_BASE_IPC_QUEUE消息队列按需开启配置原则很简单用到的开用不到的关。很多教程喜欢把所有功能全开结果编译出来体积大还可能在中断逻辑上出现意料之外的优先级问题。第一次移植只开任务管理、时间片、软件定时器即可等跑通了再加其他组件。另外要注意有些宏之间存在依赖关系比如开了消息队列大概率需要同时开启内存管理相关配置具体看编译报错缺哪个补哪个。3.4 main函数启动流程LiteOS的启动顺序很固定和FreeRTOS在main里各种初始化是同一个套路不同点在于API名字。以下代码是基于我用的这一版内核新版本API名字可能有改动但整体结构保持一致#include los_config.h #include los_printf.h static UINT32 TaskA_Entry(UINT32 arg) { (void)arg; while (1) { printf(Task A running...\n); LOS_TaskDelay(1000); } return LOS_OK; } static UINT32 TaskB_Entry(UINT32 arg) { while (1) { printf(Task B running...\n); LOS_TaskDelay(2000); } return LOS_OK; } int main(void) { UINT32 ret; TSK_INIT_PARAM_S taskParam; BSP_Init(); // 时钟、串口、LED等硬件初始化 ret LOS_KernelInit(); if (ret ! LOS_OK) { printf(LOS_KernelInit failed: 0x%x\n, ret); return -1; } memset(taskParam, 0, sizeof(TSK_INIT_PARAM_S)); taskParam.pfnTaskEntry TaskA_Entry; taskParam.uwStackSize 1024 * 4; taskParam.pcName TaskA; taskParam.usTaskPrio 5; ret LOS_TaskCreate(g_TaskAHandle, taskParam); // TaskB创建类似优先级可以设为6 // 具体字段名以你的源码版本为准 LOS_StartToRun(); // 新版本可能叫LOS_Start启动调度后不返回 return 0; }代码里有几个关键点。LOS_KernelInit必须最先调用它负责初始化内核对象用户任务必须在调度启动前创建完LOS_StartToRun之后主函数就回不来了和FreeRTOS的vTaskStartScheduler一样。如果有任务创建失败先检查任务栈大小和任务优先级是否合法LiteOS对优先级范围有要求不能随手写一个超范围的数字。任务栈建议先给大一点比如4KB等跑通了再按实际情况压减。3.5 SysTick和PendSV怎么处理这部分是整个移植最核心的地方。Cortex-M3上LiteOS和FreeRTOS一样用SysTick提供系统节拍用PendSV做任务切换。具体要处理三件事。第一SysTick中断函数。启动文件startup_stm32f10x_hd.s里的中断向量表通常已经放好了SysTick_Handler我们需要在C文件里实现它并调用LiteOS的tick处理函数。不同版本的函数名可能不一样可能是osTickHandler或LOS_TickHandler直接在内核源码里搜tick就能找到。调用之后LiteOS才能实现延时、时间片轮转这些功能。第二PendSV优先级设成最低。典型写法是在内核初始化时由arch层完成但如果你的工程没有自动设置需要在代码里显式加一行NVIC_SetPriority(PendSV_IRQn, 0xFF); NVIC_SetPriority(SysTick_IRQn, 0xFF);为什么PendSV要最低想想任务切换的时机如果在某个外设中断正在处理时来了一个更高优先级的中断触发任务切换就可能在中断服务程序内部切换上下文导致现场保存不完整。PendSV是可悬起异常只有其它异常都不执行时才真正处理相当于把切换推迟到安全时机。这一行设置错误最典型的故障现象就是任务不定期乱跳甚至HardFault。第三注意启动文件里的异常函数名要和LiteOS汇编里保持一致。比如LiteOS的调度汇编文件里也许用的就是PendSV_Handler这个名字那启动文件就不用改如果名字对不上编译时不会报错但运行时PendSV一触发就会进HardFault相当隐蔽。我的排查方法是直接在启动文件里搜索PendSV、SysTick确认向量表名字和内核汇编文件导出的符号一致。SysTick周期的计算也顺手说一下。STM32F103的SysTick时钟可以选择HCLK或HCLK/8通常配成HCLK/8也就是72/89MHz。要得到1ms的系统Tick把重装载值配成9000-1即可。如果直接用72MHz则是72000-1对24位计数器来说都没压力。在配置内核的tick周期时这个数值要和配置文件里的tick定义一致否则系统时间会比实际快或慢延时全都不准。4. 真机验证和踩坑排查4.1 跑两个任务验证调度移植完成后第一件事不是写业务代码先跑两个最简单的任务验证调度正常工作。参考上面3.4的代码一个任务每1秒打印并翻转LED另一个任务每2秒打印。烧录后理想输出是Task A running... Task B running... Task A running... Task A running... Task B running...如果能看到这个输出说明至少三件事是对的定时器中断正常、任务创建正常、上下文切换正常。反过来如果卡在第一个任务里出不来优先怀疑时间片或SysTick没起作用如果连printf都没有先查串口和时钟再查内核初始化是否失败。注意一个细节LED翻转放到两个不同优先级的任务里比单纯串口打印更能直观判断实时性。任务优先级不同高优先级的输出会明显更频繁这也是验证优先级抢占是否生效的好办法。4.2 真机上的常见问题和排查速查表这次移植和帮朋友调试过程中遇到的高频问题比较多我整理成了表格方便直接对照排查。故障现象常见原因排查方向HardFault任务栈溢出、栈未对齐、PendSV名字与汇编不一致加大任务栈并检查栈对齐看汇编断点位置任务不切换只有一个任务死循环SysTick没配置或未调用tick处理函数确认SysTick_Handler里有LiteOS tick入口printf不输出或卡死半主机模式未关闭勾选MicroLIB或重定向fputc并处理半主机串口乱码时钟、波特率不匹配确认SystemInit把时钟配到72MHz再核对波特率编译宏冲突工程里已有INLINE、assert之类定义搜索重复宏定义统一保留一份偶发异常或中断卡死外设中断优先级高于PendSV中断里调用LOS接口检查NVIC分组和优先级设置这些坑基本每个刚接触LiteOS的人都会遇到尤其HardFault。我调试时一度怀疑是源码问题后来发现是自己任务栈开小了。LiteOS任务栈虽然最小没有硬件上限但任务里如果用了printf做格式化输出栈开销会明显变大建议默认先给1KB以上第一次跑通后再慢慢压。另外如果printf卡死多半是MDK的微库没有开启或者标准库的半主机模式没处理干净这个问题和LiteOS本身无关裸机上就会遇到但很多人在裸机阶段没踩过反而在移植RTOS后被坑了一次。4.3 内核跑通之后还能往哪延伸如果说裸机是单车道LiteOS跑通后就是带红绿灯的十字路口任务、消息、同步机制都能用了。接下来常见的延伸方向有这几个开启shell组件在串口上注册命令查看当前任务运行状态排障效率高很多用消息队列把传感器采集任务和处理任务解耦比如按键采集、数据处理两个任务各干各的在ZET6这种大Flash芯片上接一块RGB屏可以移植LVGL做图形界面LiteOS里开一个GUI任务负责刷新即可智能小车方向很典型车控任务、超声避障任务、遥控接收任务各一个线程配合信号量做互斥和同步比裸机状态机直观串口协议类应用也不少见比如Modbus从站LiteOS里用一个任务持续处理串口报文再用消息队列把解析结果送给控制任务这套结构配合ZET6完全跑得动。外围设备接入联网模块以后也能在LiteOS之上做远程控制或Web配置页面用户在浏览器里调整参数设备端实时响应。这个方向很适合做物联网网关类产品也是LiteOS相对FreeRTOS更有吸引力的地方。整个移植跑通之后我的最大感受是LiteOS移植难不在“加文件”而在于理解操作系统和硬件中断之间的协作关系。FreeRTOS照着教程抄也能跑但LiteOS因为版本杂逼着你去读源码反而把调度、PendSV、SysTick这些底层机制弄得更清楚了。如果你也是第一次接触我强烈建议不要直接拿别人整理好的“一键移植包”自己从标准库工程开始一个文件一个文件地加一个坑一个坑地踩。跑通过一次之后再回来看任何RTOS的移植文档都会觉得通透。最后提醒一句生产项目用LiteOS之前一定要确认版本维护状态和许可搭配好组件再做选型别等产品定型了才发现某个组件不再维护。本文还有配套的精品资源点击获取
返回列表