ARTICLE DETAIL

资讯详情

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

LubanCat 5软实时化实战:RK3576内核编译与RKDevTool烧录指南

LubanCat 5软实时化实战:RK3576内核编译与RKDevTool烧录指南 说实话我第一次拿到LubanCat 5的时候第一反应是这板子长得不像传统开发板更像一台被压扁了的迷你主机。但真正让我有兴趣的不是它的外观而是“软实时化”这三个字。把一块基于RK3576的Linux单板调整成具有确定性调度能力的实时平台再配合RKDevTool把编译好的内核烧进去这件事听起来门槛高实际做下来就是“内核配置 交叉编译 分区烧录”的闭环。这篇文章我就把这套流程完整写一遍包含我踩过的坑、改过的参数以及如何用RKDevTool单独只烧boot分区而不动系统分区。适合手里有LubanCat 5或者对Rockchip平台实时化感兴趣的嵌入式开发者哪怕你之前没碰过实时内核照着做也能跑通。1. 项目概述与整体思路1.1 LubanCat 5 是块怎样的板子LubanCat 5 是野火推出的一块面向Linux应用的高性能单板计算机核心SoC用的是瑞芯微RK3576。这颗芯片采用4个Cortex-A72大核加4个Cortex-A53小核的big.LITTLE架构集成Mali GPU和NPU在跑Linux系统时性能余量很大。板子上常见配置包括LPDDR4/4x内存、eMMC存储、M.2接口、双频Wi-Fi 6、BLE 5.0以及多路USB和显示输出。我手上这块是带屏幕的版本整体定位更接近“微型工作站”而不是那种需要拿杜邦线去点灯的裸机开发板。Real-Time补丁在Linux圈的叫法是PREEMPT_RT它解决的核心问题不是“算得有多快”而是“延迟有多确定”。LubanCat 5这类板子常用在机器人控制、运动控制、数据采集原型验证等场景这些场景对任务响应时间有硬性要求你希望在1ms周期内稳定地读到传感器数据而不是偶尔卡到3ms甚至更糟。1.2 软实时化的定位先别把“软实时”和“硬实时”搞混。硬实时系统要求任何情况下都必须在截止时间前完成任务一旦超时就是事故软实时系统允许极少量的超时但整体延迟分布必须可预测、抖动小。Linux上的PREEMPT_RT补丁虽然在很多场景下能提供接近硬实时的表现但它仍然跑在通用操作系统上受中断、DMA、内核驱动的不可控因素影响所以圈内普遍把它归为“软实时”方案。LubanCat 5要做的就是通过内核配置把默认的抢占模型从“自愿抢占”或“低延迟抢占”切换成“全功能RT抢占”并且把时钟频率、CPU调度器、中断处理方式统一调优。这样一个运行在普通Linux下的用户态控制程序可以通过SCHED_FIFO实时调度策略获得稳定执行不会被普通进程抢占得太惨。1.3 为什么绕不开 RKDevTool内核编译出来之后下一步就是把它装到板子的存储里。LubanCat 5的eMMC里已经跑着一套官方Ubuntu/Debian系统最简单的方式当然是直接把新的Image文件拷贝到/boot目录里替换但很多Rockchip定制镜像的启动流程并不是简单的“读/boot/vmlinuz”就能搞定的。内核和设备树通常被封装在boot.img里同时对分区偏移有严格约定。这时候RKDevTool就派上用场了。它是Rockchip官方在Windows下的烧录工具可以通过USB直接访问板子上的存储设备支持单独烧写分区表指定的某个分区比如只写boot分区而不碰system和userdata。对于“软实时化”这种只需要替换内核的改动RKDevTool是效率最高的路径不需要每次都去刷整卡镜像。2. 软实时化原理与内核准备2.1 PREEMPT_RT 到底做了什么为了讲清楚软实时化必须从内核调度器说起。普通Linux内核为了保持数据结构的完整性在访问共享资源时需要使用自旋锁、原子操作等机制。持有锁的这段区域叫临界区在临界区内内核默认不允许被其他任务抢占否则数据就被改乱了。问题是临界区可能很长比如某个驱动在持锁期间做了磁盘IO或者复杂内存操作这时即使一个优先级最高的实时任务醒过来了也只能在临界区外面干等。PREEMPT_RT补丁的核心思想就是把内核里绝大多数临界区变成可抢占的。它通过把自旋锁替换成可睡眠的互斥锁、把中断处理强制线程化让实时任务在这些区域里也能插入执行。用大白话解释普通内核像一辆固定站点停靠的班车不到站不让乘客上下车RT内核更像一辆出租车只要安全就能随时停乘客体验稳定很多。2.2 准备内核源码与交叉编译工具链软实时化的第一步是拿到LubanCat 5对应的内核源码。野火和Rockchip官方一般都会维护BSP SDK里面包含u-boot、内核、根文件系统构建脚本。不同版本SDK目录结构大同小异通常内核源码在kernel/目录下。如果你拿到的SDK是基于Rockchip官方Linux SDK的那内核目录下还会有arch/arm64/configs/rockchip_linux_defconfig这样的现成配置文件。在Ubuntu主机上需要准备交叉编译工具链RK3576是arm64架构所以用aarch64版本sudo apt update sudo apt install gcc-aarch64-linux-gnu libncurses-dev bc flex bison如果是自己从kernel.org拉主线的RT补丁还需要保证内核版本和补丁版本严格一致。比如内核源码是6.1.x就要下载对应的patch-6.1.x-rtXX.patch.xz用下面的方式打入cd kernel xzcat ../patch-6.1.x-rtXX.patch.xz | patch -p1如果你用的是野火SDK里带RT分支的源码那可能不需要手动打补丁直接在menuconfig里打开RT选项即可。这里我给的不一定是同样的仓库地址具体以你手里的SDK为准但核心流程是通用的。2.3 内核配置关键项进入内核目录后先加载Rockchip默认配置然后再打开菜单调整cd ${SDK}/kernel make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- rockchip_linux_defconfig make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- menuconfig在menuconfig里最关键的选项在General setup - Preemption Model这里默认可能是Voluntary Kernel Preemption (Desktop)或者Low-latency Desktop。实时化要选最后一项Fully Preemptible Kernel (Real-Time)。选完之后CONFIG_PREEMPT_RTy就会自动打开内核里绝大部分临界区都会被改造。另外几个我习惯一起改的选项Kernel Features - Timer frequency改成1000 Hz让调度器节拍更细适合1ms级别的控制周期。CPU Frequency scaling - Default CPUFreq governor改成performance避免调频带来的延迟抖动。这个可以后续运行时再改。Kernel Features - Preemption Model确认RT选项下没有出现冲突提示如果某些驱动依赖强制抢占需要回头处理。如果你不想在menuconfig里找选项也可以直接在.config里搜索确认grep PREEMPT .config正常情况下会出现CONFIG_PREEMPTy和CONFIG_PREEMPT_RTy。2.4 编译并打包 boot.img配置完成后只编译内核镜像和设备树不需要全量编译整个SDK省时间也降低出错概率make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- Image dtbs如果是多核主机可以追加-j$(nproc)。编译完成后Image文件在arch/arm64/boot/Image设备树在arch/arm64/boot/dts/rockchip/下比如rk3576-lubancat-5.dtb之类。Rockchip SDK一般会提供打包脚本比如在SDK根目录下执行./mkimage.sh这个脚本会把新内核和设备树打包到boot.img和resource.img。如果你的SDK没有这个脚本就要手工用mkbootimg把Image和dtb打包成RK格式的boot镜像或者直接用SDK里现成的recovery方式生成。打包完成后在输出目录里找到boot.img下一步就是交给RKDevTool。3. RKDevTool 实操烧录软实时内核3.1 安装驱动与进入 Loader 模式烧录第一步不是打开工具而是装驱动。RKDevTool依赖Rockchip的USB驱动一般叫DriverAssitant。下载解压后右键“驱动安装”以管理员身份运行。安装完成后把LubanCat 5的Type-C口连接到电脑这个口得是支持USB OTG调试的口不是纯电源输入口。很多板子有两个Type-C一个供电一个烧录别接错。让板子进入Loader模式有两种办法。第一种是板子完全断电按住板上的RECOVERY/Boot按键不放然后通过Type-C接到电脑并上电保持按键2~3秒后再松开。第二种是如果板子已经正常启动到Linux并且在adb调试可用的情况下adb reboot loader此时打开RKDevTool界面上如果出现“发现一个LOADER设备”就说明连接正常。如果显示绿色图标但一直显示“没有发现设备”优先检查驱动是否安装成功再检查线材是否支持数据传输。3.2 认识分区表Rockchip的存储区域不像普通PC那样只有一个根分区而是通过parameter.txt分区表把 eMMC 划分成多个固定区域。常见分区有uboot、boot、system、recovery、misc、userdata等。其中boot分区专门放内核和设备树system放根文件系统userdata放用户数据。所以“软实时化”如果只改了内核完全可以只烧boot分区。这样一来板子上的系统、已安装软件、配置文件都原封不动只有内核被替换成RT版本。单独烧boot的好处是快、风险小、回滚也方便。在RKDevTool里如果烧录时选择了“按分区表烧录”工具会自动读入parameter.txt并列出所有分区。你需要保证手里有板子相匹配的parameter.txt一般SDK的rockdev/或tools/目录下能找到。3.3 单独烧录 boot 分区的步骤打开RKDevTool后按下面的步骤操作在顶部选“烧录分区表/固件”相关的标签页。点击“分区表”旁边的浏览按钮选择parameter.txt。分区列表刷新后找到名称为boot的行。勾选这一行的启用框在右侧文件路径里选择刚编译好的boot.img。确认没有勾选system、userdata等其他分区。点击“执行”按钮开始烧录。烧录过程中工具会显示每个分区的进度最终显示绿色“成功”。如果之前板子已经在Loader模式下烧完通常会自动重启。如果没有自动重启手动断电再上电即可。这里我特别提醒一句如果你在分区列表里同时勾选了system和userdata工具默认会用对应镜像覆盖它们。手头如果没有官方system镜像千万别手滑勾上不然烧完系统就没了。3.4 统一固件与完整烧录如果你的板子已经变砖或者你想清掉所有数据重新来一套干净系统那就需要烧统一固件。统一固件是已经打包好的单一update.img里面包含loader、uboot、boot、system、recovery等所有分区镜像。在RKDevTool的“升级固件”页里直接选择update.img点击“升级”即可。整体烧录的优势是省心不用管分区表细节缺点是时间长而且会把板子的系统重置。软实时化场景下我不建议一上来就刷统一固件因为你要把自己编译的RT内核重新封装进update.img才能烧否则烧回原来的普通内核等于白忙。正确顺序是先用官方统一固件恢复系统跑通之后再单独烧自己编译的boot.img。4. 烧录后的实时性验证与调优4.1 用 cyclictest 测量调度延迟内核替换成RT之后第一件事是验证它是不是真的“软实时”了。最常用的工具是rt-tests里的cyclictest。进入板子系统后安装sudo apt update sudo apt install rt-tests跑一个最简单的5线程测试sudo cyclictest -t 5 -p 80 -n -i 1000 -l 10000其中-t 5表示创建5个测试线程-p 80表示使用优先级80需要root权限-i 1000表示周期为1000微秒-l 10000表示循环10000次。测试结束后会打印最小、平均、最大延迟。我实测中同一块LubanCat 5在普通抢占内核下最大延迟可能到一两百微秒甚至更高切到PREEMPT_RT内核后最大延迟能压到几十微秒以内抖动也小得多。如果你跑之前没有RT内核而报错Operation not permitted说明当前shell没有实时调度权限加sudo即可。如果系统装了docker或者容器环境建议直接在宿主机上测。4.2 启动参数里的CPU隔离光把内核切到RT还不够实际控制程序往往会因为缓存争用、中断负载而被拖累。这时候可以在启动参数里把部分CPU核心隔离出来专门跑实时任务。LubanCat 5的8核架构一般用如下参数isolcpus4,5,6,7 nohz_full4,5,6,7 rcu_nocbs4,5,6,7isolcpus告诉内核把指定核心从普通调度器中移除普通进程不会落到这些核上nohz_full关闭指定核上的周期时钟中断减少干扰rcu_nocbs让这些核上的RCU回调转移到其他核。修改启动参数的方式因镜像而异可能是/boot/uEnv.txt也可能是extlinux.conf。你可以先在板上查一下当前kernel cmdlinecat /proc/cmdline然后找到启动配置文件在APPEND或kernel args里追加上述参数。修改前备份原文件以防万一。4.3 实时任务程序的编写要点内核准备好了应用这边也得配合。只是把线程优先级调到最高并不能保证实时性以下几个细节直接影响效果使用SCHED_FIFO或SCHED_RR调度策略而不是默认的SCHED_OTHER。在C里用pthread_setschedparamshell里用chrt -f 80 ./task。调用mlockall(MCL_CURRENT | MCL_FUTURE)锁定内存避免实时任务运行中出现缺页中断。避免在实时线程里调用printf、malloc、open这类可能阻塞或触发锁操作的函数提前把资源准备好。如果有多路传感器或网络收发优先把中断绑定到非实时核心上让实时任务独占大核。5. 常见问题排查与避坑实录5.1 RKDevTool 识别不到设备这是刷机时最常遇到的问题。先确认三个点线材是不是数据线、电脑有没有装好Rockchip驱动、板子有没有真正进Loader模式。很多人用Type-C充电线结果数据不通换一根线立刻解决。如果你能看到设备管理器里有带感叹号的Rockchip设备手动更新驱动指向DriverAssitant安装目录即可。还有个小技巧如果adb reboot loader之后工具没反应可以先断电按住RECOVERY键再上电通常能强制进入Loader。如果再不行就要考虑进MaskRom模式了这种模式一般出现在loader损坏时工具也会提示。5.2 刷完boot后启动卡在logo或反复重启这种问题八成是内核和设备树不匹配。你单独编译了新的Image但dtb还是旧版结果内核和板载外设的初始化对不上。解决方法是重新编译dtbs确保boot.img里打包的dtb和你内核源码来自同一个版本。另外检查一下parameter.txt里boot分区的起始地址是否被改过烧错位置也会导致启动失败。如果启动日志里能看到内核panic用串口线连接板子的调试串口抓完整的log会更直观。串口在正式项目中非常必要别省。5.3 RT特性没有生效烧完RT内核后用uname -a查看内核版本字符串如果显示PREEMPT_RT说明编译时打开了RT选项。如果仍然显示PREEMPT而没RT多半是menuconfig里选错了项或者编译时使用了旧config没有重新make clean。我建议每次切换内核配置后先make olddefconfig再编译避免残留旧选项。另外光有RT内核还不够应用得使用实时调度策略才能真正获益。跑一下ps -eo pid,comm,pri,rtprio,cls看看你的任务是不是FFFIFO类如果还是TS普通调度那延迟改善不明显。5.4 其他操作注意事项烧录过程中千万不要断电RKDevTool写Loader分区时断电很容易导致设备变砖到时候只能MaskRom模式救砖。如果你的boot.img没有备份刷之前一定先从工具里把原boot分区镜像导出来。我干过一次直接刷自己内核没留原版的蠢事后来想对比问题都无从下手。软实时化的另一个副作用是吞吐性能会有一点折扣。PREEMPT_RT把大量临界区改为可睡眠锁系统在重负载时上下文切换更频繁所以别拿它在普通业务里当性能加速器。我一般会准备两套boot.img一套RT用于控制现场一套普通内核用于多媒体和日常开发需要时用RKDevTool几分钟切回来。最后分享一个实用习惯在单独烧录boot之后先在板上跑一次cyclictest记录延迟数据对比RT内核和原内核的max差值。如果没有改善优先检查是不是dtb没更新、优先级不够、或者实时线程被irqbalance干扰。软实时化不是一个开关而是“内核配置 启动参数 应用设计”三者配合的结果。把这套流程跑熟之后LubanCat 5就可以当做一个可靠的控制平台来使了。
返回列表