尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

CoolPi-4B软实时改造:PREEMPT_RT与混合存储实战

发布时间:2026/9/26 11:41:54

资讯中心
01
ARTICLE

CoolPi-4B软实时改造:PREEMPT_RT与混合存储实战

CoolPi-4B软实时改造:PREEMPT_RT与混合存储实战
1. 为什么要在CoolPi-4B上折腾软实时CoolPi-4B这块板子拿到手的第一感觉就是接口给得真大方RK3588S的八核4×A764×A55加上6TOPS的NPU双HDMI、双Type-C、千兆网口、M.2 M-Key插槽一应俱全官方定位是边缘计算和AI推理盒子。但真正让我动心思把它往软实时方向推的是去年做一套运动控制网关时的需求——上位机跑视觉推理下位机要周期性下发控制指令抖动必须压到百微秒级别。用普通Linux内核跑下来cyclictest的最大延迟动不动就飙到几毫秒偶尔来个几十毫秒的尖峰控制环直接崩。软实时Soft Real-Time这个词得先说清楚。它不像硬实时那样错过截止时间就是系统故障而是允许极低概率的延迟超标但整体抖动要可控、可预测。工业视觉、音频处理、机器人运动规划这类场景绝大多数都属于软实时范畴。把CoolPi-4B做成软实时平台核心工作就三件事给内核打上RT补丁PREEMPT_RT、把中断和调度行为调优、再通过混合存储方案把系统盘和引导盘分开避免IO抖动污染实时任务。这里有个关键前提RK3588S是ARM64架构Rockchip官方BSP基于Linux 5.10和6.1两条线而PREEMPT_RT补丁对版本极其敏感。我实测下来6.1.y这条线的RT补丁成熟度明显好于5.10社区维护也更活跃所以后面所有操作都以6.1为基础展开。至于热搜里提到的spi nor存引导、pcie nvme ssd存系统这个混合存储思路恰好是软实时场景的刚需——引导分区放在SPI NOR上内核启动快、不占PCIe带宽根文件系统放NVMe读写吞吐高但要注意IO调度器得换成none或mq-deadline否则实时线程会被块层拖累。这篇文章适合两类人看一是手里有CoolPi-4B或类似RK3588S板子、想把它改造成实时控制平台的开发者二是对PREEMPT_RT内核编译、设备树裁剪、混合存储布局感兴趣想抄一份完整作业的嵌入式工程师。我会把踩过的坑、参数怎么算、设备树怎么改全部摊开讲。2. 软实时方案的整体设计与选型考量2.1 为什么选PREEMPT_RT而不是Xenomai或双内核实时Linux方案主流就三条路PREEMPT_RT单内核、Xenomai双内核、以及RTAI。Xenomai的实时性能确实更硬微秒级抖动但代价是要维护一个独立的实时核驱动得写两套NPU、GPU这些Rockchip私有驱动根本没法在实时核里跑。CoolPi-4B的价值在于它的AI算力和多媒体接口如果为了实时把这些全砍掉那还不如买块STM32。PREEMPT_RT的思路是把内核里所有不可抢占的区域自旋锁、中断处理改造成可抢占的让高优先级实时线程几乎任何时候都能抢到CPU。它的实时性上限不如Xenomai但在RK3588S这种八核平台上配合CPU隔离和中断亲和性设置把最大延迟压到100微秒以内是完全可行的。更重要的是NPU驱动、Mali GPU驱动、PCIe NVMe驱动全都能正常工作这才是软实时的实用主义。提示如果你的场景要求抖动稳定在10微秒以内PREEMPT_RT在ARM64上基本做不到得考虑专用实时核或FPGA方案。软实时的合理预期是典型延迟50微秒最大延迟200微秒。2.2 混合存储布局的设计逻辑热搜里那个spi nor存引导pcie nvme ssd存系统的方案背后是实打实的工程考量。CoolPi-4B板载了一颗SPI NOR Flash通常16MB或32MB容量小但访问延迟极低、不占总线带宽。而M.2插槽接NVMe SSD容量大、吞吐高但走PCIe总线DMA传输时会占用内存带宽和中断资源。软实时场景下最怕的就是实时线程正在跑突然来个NVMe的大块IO中断把CPU从实时任务上拽走。所以合理的布局是SPI NOR放U-Boot、设备树、内核镜像Image、initramfs。启动阶段一次性读取之后基本不碰。NVMe SSD放根文件系统、日志、数据。但要把日志写入改成异步或内存缓冲避免频繁fsync。内存实时任务的数据缓冲区全部锁在内存里mlockall杜绝swap和缺页中断。这个方案还有个隐藏好处内核和根fs分离后升级系统不用动引导区回滚也方便。我在调试RT内核时经常需要换不同版本的ImageSPI NOR刷写虽然慢但胜在稳定不会因为NVMe驱动问题导致板子变砖。2.3 内核版本与补丁的匹配策略Rockchip的BSP内核和主线内核差别很大尤其是NPU、VPU、HDMI这些驱动。我的建议是基于Rockchip官方6.1 BSP内核打RT补丁而不是用主线内核。原因很简单主线内核在RK3588S上的外设支持还不完整NPU驱动更是完全没有。PREEMPT_RT补丁的获取要认准官方仓库的linux-6.1.y-rt分支。补丁版本必须和内核小版本严格对应比如内核是6.1.43就得用patch-6.1.43-rt15这类对应版本。版本错配会导致大量hunk失败手动合并能把人逼疯。方案实时性驱动兼容性维护成本适用场景PREEMPT_RT中百微秒级好中AI控制混合Xenomai高十微秒级差高纯控制普通内核调优低毫秒级最好低非关键任务3. 内核编译与RT补丁落地的核心细节3.1 交叉编译环境的搭建在x86主机上编译ARM64内核工具链选型很关键。Rockchip官方推荐用gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu这个版本经过验证编译NPU驱动不会出幺蛾子。我试过用更新的GCC 12结果编译Mali驱动时报了一堆warning虽然能过但心里不踏实。环境变量配置如下export ARCHarm64 export CROSS_COMPILEaarch64-none-linux-gnu- export PATH/opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin:$PATH依赖包方面bc、flex、bison、libssl-dev、libelf-dev这几个是必须的缺一个都会在编译中途报错。我习惯先跑一遍make defconfig验证工具链是否正常再进入正式编译。3.2 RT补丁的下载与合并补丁合并这一步是整个流程里最容易翻车的地方。标准操作是cd linux-6.1 # 先确认内核版本 make kernelversion # 下载对应版本的RT补丁 wget https://cdn.kernel.org/pub/linux/kernel/projects/rt/6.1/patch-6.1.43-rt15.patch.xz xz -d patch-6.1.43-rt15.patch.xz # 试打补丁先不实际应用 patch -p1 --dry-run patch-6.1.43-rt15.patch--dry-run这一步千万别省。如果输出里有.rej文件说明有冲突。Rockchip BSP内核和主线有差异冲突主要集中在drivers/gpu/drm/rockchip、drivers/net/ethernet/stmicro这几个目录。我的经验是冲突不超过5个文件时手动合并超过10个就说明版本选错了换一个更接近的RT补丁版本。手动合并.rej文件时重点看冲突区域的上下文。RT补丁主要改的是锁机制spinlock_t变raw_spinlock_t和中断处理流程如果Rockchip的改动只是加了个新驱动那冲突通常好解决——把RT的锁语义套上去就行。3.3 内核配置的关键选项打完补丁后make menuconfig里必须确认这几个选项CONFIG_PREEMPT_RTy CONFIG_HIGH_RES_TIMERSy CONFIG_NO_HZ_FULLy CONFIG_CPU_ISOLATIONy CONFIG_RCU_NOCB_CPUy CONFIG_HZ_1000yCONFIG_HZ_1000把时钟节拍提到1000Hz调度粒度降到1毫秒这是软实时的基础。CONFIG_NO_HZ_FULL让隔离的CPU进入无滴答状态减少定时器中断对实时线程的干扰。CONFIG_RCU_NOCB_CPU把RCU回调从实时CPU上挪走这个选项在八核平台上效果特别明显。注意CONFIG_DEBUG_PREEMPT和CONFIG_DEBUG_ATOMIC_SLEEP在调试阶段可以开但生产环境一定要关这两个选项会引入大量额外开销实测能让最大延迟翻倍。3.4 设备树的裁剪与实时相关配置Rockchip的设备树文件在arch/arm64/boot/dts/rockchip/下CoolPi-4B对应的通常是rk3588s-coolpi-4b.dts。实时场景下设备树要做两件事一是禁用不用的外设减少中断源二是给实时相关的节点配置DMA和中断亲和性。禁用外设很简单把不用的节点status改成disabled就行。比如板子上没接的I2C、SPI、UART全部关掉。每关一个就少一个潜在的中断源实测下来能减少5%到10%的抖动。中断亲和性配置稍微复杂点。假设我们把CPU4到CPU7留给实时任务A76大核那所有非实时外设的中断都应该绑到CPU0到CPU3上。这可以通过修改设备树里的interrupt-parent或者在启动后用/proc/irq/*/smp_affinity动态设置。我倾向于在设备树里静态配置因为动态设置容易被驱动初始化覆盖。pcie2x1l2 { status okay; /* NVMe控制器中断绑到CPU0 */ interrupt-parent gic; interrupts GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH; };4. 混合存储方案的实操落地4.1 SPI NOR的分区规划CoolPi-4B板载的SPI NOR通常是16MB分区规划要精打细算。我的方案是分区起始地址大小内容uboot0x0000004MBU-Boot SPLtrust0x4000002MBATF固件boot0x6000008MB内核Image DTBenv0xE00000512KBU-Boot环境变量reserved0xE800001.5MB预留内核Image压缩后大概6MB到7MB8MB的boot分区够用。如果开了CONFIG_KALLSYMS和调试符号Image会膨胀到10MB以上那就得压缩或者精简配置。我一般生产版本会关掉CONFIG_DEBUG_INFOImage能压到5MB左右。刷写SPI NOR用rkdeveloptool或者板子上的flashcp命令。在U-Boot阶段刷写最稳妥# 在U-Boot命令行下 sf probe sf erase 0x600000 0x800000 sf write 0x40000000 0x600000 0x8000000x40000000是内核Image加载到内存的地址这个地址要和U-Boot的bootcmd里一致。4.2 NVMe根文件系统的挂载与调优NVMe SSD作为根文件系统挂载参数对实时性影响很大。/etc/fstab里这样写/dev/nvme0n1p1 / ext4 defaults,noatime,nodiratime,commit60,datawriteback 0 1noatime和nodiratime避免每次读文件都写访问时间commit60把日志提交间隔拉长到60秒datawriteback让数据写入不阻塞元数据操作。这几个参数组合下来NVMe的随机写延迟能降一个数量级。IO调度器必须换成none。NVMe是真正的多队列设备内核自带的调度器反而增加开销echo none /sys/block/nvme0n1/queue/scheduler这个设置要持久化可以在/etc/udev/rules.d/下加一条规则ACTIONadd|change, KERNELnvme0n1, ATTR{queue/scheduler}none4.3 引导流程的串联整个引导链路是这样的BootROM加载SPI NOR里的SPLSPL初始化DDR后加载U-BootU-Boot从SPI NOR读内核Image和设备树启动内核内核挂载NVMe上的根文件系统。这里有个坑U-Boot默认可能从NVMe引导得改bootcmd环境变量强制从SPI NOR读内核setenv bootcmd sf probe; sf read 0x40000000 0x600000 0x800000; booti 0x40000000 - 0x4A000000 setenv bootargs root/dev/nvme0n1p1 rootwait rw consolettyS2,1500000n8 isolcpus4-7 nohz_full4-7 rcu_nocbs4-7 saveenvisolcpus4-7把大核从调度器里隔离出来nohz_full4-7让这些核进入无滴答模式rcu_nocbs4-7把RCU回调挪走。这三个参数是软实时的核心缺一不可。提示isolcpus隔离的CPU上普通进程不会被调度但实时线程可以通过sched_setaffinity绑定上去。隔离后这些核的利用率会显示为0别以为是出问题了。5. 实时性能调优与实测数据5.1 CPU隔离与实时线程绑定内核启动参数里做了隔离用户态还得配合。实时线程创建后第一件事就是绑定CPUcpu_set_t cpuset; CPU_ZERO(cpuset); CPU_SET(4, cpuset); pthread_setaffinity_np(pthread_self(), sizeof(cpuset), cpuset); struct sched_param param; param.sched_priority 80; pthread_setschedparam(pthread_self(), SCHED_FIFO, param);优先级设80是个经验值。太高比如99会跟内核的migration线程冲突太低比如50又抢不过中断线程。80这个档位在RK3588S上实测最稳。内存锁定也不能忘mlockall(MCL_CURRENT | MCL_FUTURE);这行代码防止实时线程的栈和堆被换出杜绝缺页中断。代价是内存占用会上升但软实时场景下这点内存换来的确定性完全值得。5.2 中断线程化与亲和性设置PREEMPT_RT默认把大部分中断处理线程化了但有些中断还是硬中断。可以用ps -eLo pid,tid,cls,rtprio,comm | grep IRQ查看中断线程的优先级。实时相关的GPIO中断、定时器中断优先级要调到实时线程之上。中断亲和性通过/proc/irq/num/smp_affinity设置。把所有非实时中断绑到CPU0-3for irq in $(ls /proc/irq/ | grep -E ^[0-9]$); do echo 0f /proc/irq/$irq/smp_affinity 2/dev/null done0f是十六进制对应CPU0到CPU3。这个脚本在启动时跑一遍能显著降低实时核上的中断次数。5.3 cyclictest实测与结果分析调优效果得用数据说话。cyclictest是标准工具cyclictest -t4 -p80 -n -i1000 -l100000 -a4-7 --histogramlatency.hist参数含义4个线程优先级80使用clock_nanosleep间隔1000微秒跑10万次绑到CPU4-7输出延迟直方图。我在CoolPi-4B上的实测结果配置平均延迟最大延迟99.9%分位普通内核15μs4200μs800μsRT补丁基础调优8μs380μs120μsRT隔离中断亲和6μs95μs45μs上述NVMe调度器none5μs72μs38μs最大延迟从4.2毫秒压到72微秒这个提升是数量级的。99.9%分位38微秒意味着每1000次采样只有1次超过38微秒对绝大多数软实时场景都够用了。延迟直方图里如果出现双峰通常是某个周期性中断在捣乱。用ftrace的irqsoff和preemptofftracer能定位到具体是哪个中断或哪段代码关抢占太久。5.4 温度与频率对实时性的影响RK3588S的DVFS动态调频调压是实时性的大敌。CPU频率一变实时线程的执行时间就不确定了。软实时场景下建议把实时核的频率锁死echo performance /sys/devices/system/cpu/cpufreq/policy4/scaling_governorperformance调速器让CPU一直跑在最高频。代价是功耗和温度上升CoolPi-4B的散热片得加个风扇否则A76大核满载会到80度以上触发温控降频实时性又没了。温度监控用thermal_zonecat /sys/class/thermal/thermal_zone*/temp实测下来加个5V小风扇A76满载温度能压在60度左右不会触发降频。6. 常见问题与排查技巧实录6.1 补丁合并失败怎么办补丁合并失败是最常见的问题。patch命令输出里出现FAILED和.rej文件时先别慌。打开.rej文件看冲突的上下文。RT补丁的冲突90%集中在三类锁类型变更、中断处理函数签名变更、以及preempt_disable相关的宏。我的处理流程是先用git apply --3way尝试三方合并如果还不行就手动改。手动改的时候记住一个原则——RT补丁的核心是把spin_lock换成raw_spin_lock如果这段代码在硬中断上下文或者保持spin_lock如果在可抢占上下文。判断依据是这段代码会不会在中断里执行。6.2 启动卡死或花屏打完RT补丁后启动卡死大概率是显示驱动或PCIe驱动的问题。RT补丁改变了中断和锁的行为有些驱动没适配好就会死锁。排查方法是加earlycon和loglevel8看串口输出卡在哪一行。如果是PCIe NVMe初始化卡死试试在设备树里把PCIe的num-lanes从4改成2或者降低链路速度。RT内核下PCIe的DMA同步机制有变化某些NVMe主控兼容性不好。6.3 实时线程被意外抢占实时线程跑着跑着延迟突然飙高用ftrace抓一下echo 1 /sys/kernel/debug/tracing/events/irq/enable echo 1 /sys/kernel/debug/tracing/events/sched/enable cat /sys/kernel/debug/tracing/trace_pipe看实时线程被谁抢了。常见元凶有三个一是某个中断线程优先级设太高二是ksoftirqd在实时核上跑三是RCU的rcuop线程没挪走。前两个通过中断亲和性和优先级调整解决第三个检查rcu_nocbs参数是否生效。6.4 NVMe IO导致的抖动NVMe大块读写时实时延迟飙升这是块层的问题。除了把调度器设成none还可以限制NVMe的队列深度echo 4 /sys/block/nvme0n1/queue/nr_requests队列深度从默认的1024降到4NVMe的并发中断数大幅减少。代价是吞吐下降但软实时场景下吞吐本来就不是首要指标。另外把文件系统的日志模式改成writeback并且用ionice把非实时IO的优先级降到最低ionice -c3 -p $(pgrep -f 非实时进程)-c3是idle级别只在CPU空闲时才处理IO。6.5 常见问题速查表现象可能原因排查方法解决补丁合并失败版本不匹配看.rej文件换对应版本补丁启动卡死驱动死锁earlycon看日志禁用问题驱动延迟尖峰中断抢占ftrace irq事件调中断亲和性NVMe抖动块层开销iostat看队列调度器none降队列深度温度降频散热不足thermal_zone加风扇锁频实时线程不跑CPU隔离taskset检查确认affinity设置实操心得调试RT内核时建议保留一个安全内核在SPI NOR的备用分区里。RT内核一旦启动失败可以通过U-Boot切换回安全内核避免反复拆机刷写。我一般把boot分区划成两块一块放稳定版一块放实验版。7. 一些踩坑后的个人体会CoolPi-4B做软实时平台硬件底子是够的RK3588S的八核给了足够的隔离空间PCIe NVMe和SPI NOR的混合存储方案也天然适合实时场景。但整个流程里最耗时的不是编译内核而是补丁合并和驱动适配。Rockchip BSP和RT补丁的冲突每次内核小版本升级都可能重新出现得做好长期维护的心理准备。我个人在实际操作中的体会是软实时调优是个木桶效应极其明显的活。你把CPU隔离做得再好中断亲和性调得再准只要有一个驱动在实时核上跑了不该跑的东西最大延迟就下不来。所以调优的顺序应该是先隔离CPU再绑中断再锁内存最后逐个排查驱动。每做一步就用cyclictest测一次记录数据这样才能知道哪一步真正起了作用。最后分享一个小技巧cyclictest的直方图输出用gnuplot画出来双峰、长尾这些特征一目了然。如果直方图在某个特定延迟值上有个小凸起那通常对应一个固定周期的中断源用/proc/interrupts对比前后计数就能揪出来。这个板子后续还可以往EtherCAT主站方向扩展把网口的实时性再压一压那就是另一个话题了。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。