一、简介:设备树 ≠ “能跑就行”,实时场景必须“精修”
瑞芯微 RK3568/RK3588 官方 SDK 默认设备树以“功能全开启”为导向,GPIO/SPI/ADC 中断默认绑在 CPU0,高并发传感器采集时:
中断抖动 > 120 µs → 图像帧撕裂、控制环震荡。
多个驱动竞争
regmap→ 偶发 5 ms 毛刺,实时性认证直接 FAIL。
本文聚焦“设备树层实时优化”:
中断亲和性绑定 → 专核专职
资源独占 (
resv) → 消灭竞争PREEMPT-RT 配合 → 中断线程化优先级可设
掌握这些套路,同等硬件下,外设数据抖动可压到 < 20 µs,给边缘视觉、高速运控打下“硬实时”地基。
二、核心概念:5 个关键词先搞懂
| 关键词 | 一句话 | 本文出现场景 |
|---|---|---|
| Device Tree (DT) | 描述硬件资源的“蓝图”,编译后 =.dtb | 定制rk3568-realtime.dts |
中断亲和性interrupt-affinity | 把中断绑到指定 CPU,避免抖动 | SPI 中断绑到 CPU2 |
reg = <...> | 外设寄存器地址 & 大小 | ADC 控制器基地址 |
pinctrl-* | 引脚复用/上下拉/驱动强度 | GPIO 切换功能 |
reserved-memory | 预留连续内存,DMA 零拷贝 | 图像帧 buffer 独占 |
三、环境准备:10 分钟搭好“瑞芯微实时工作台”
1. 硬件
RK3568 核心板(2 GB DDR)+ 载板(引出 GPIO/SPI/ADC)
逻辑分析仪 1 台 → 测中断抖动(可选)
2. 软件
| 组件 | 版本 | 获取 |
|---|---|---|
| Ubuntu Server | 20.04 aarch64 | 官方 SDK |
| 实时内核 | linux-5.15-rt | 见一键脚本 |
| 交叉工具链 | gcc-linaro-11.3 | 瑞芯微 GitHub |
| 设备树源码 | arch/arm64/boot/dts/rockchip/rk3568.dtsi | SDK 自带 |
3. 一键装 RT 内核(可复制)
#!/bin/bash # install_rt_rk3568.sh git clone https://github.com/rockchip-linux/kernel.git -b v5.15 cd kernel wget https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.15/patch-5.15-rt.patch git apply patch-5.15-rt.patch make ARCH=arm64 rockchip_defconfig ./scripts/config -e CONFIG_PREEMPT_RT make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) sudo make modules_install && sudo cp arch/arm64/boot/Image /boot/重启选 RT 内核即可。
四、应用场景(300 字):边缘视觉+运动控制混合场景
某国产分拣机器人采用 RK3568 + 4 路 GSML 相机(SPI 接口)+ 2 路光电编码器(GPIO 脉冲)+ 1 路电流环 ADC。
默认设备树下,相机帧中断与编码器中断同绑 CPU0,视觉线程和伺服环线程并行运行时,CPU0 负载 80% → 中断抖动 150 µs,图像丢帧 1%,伺服电流环超时报警。
通过本文“设备树优化”后:
SPI 帧中断迁至 CPU2,GPIO 脉冲中断迁至 CPU3,ADC DMA 使用预留内存;
CPU0 专供 Linux 调度,视觉线程绑 CPU2,伺服环绑 CPU3;
实测中断抖动 < 18 µs,丢帧率 0%,电流环抖动 < 5 µs,整机通过 SIL 2 实时认证。
五、实际案例与步骤:30 min 完成“GPIO+SPI+ADC”实时适配
所有 DTS 片段基于
rk3568-realtime.dts,可直接合并编译。
5.1 创建自定义设备树
cd ~/rk3568-sdk/kernel/arch/arm64/boot/dts/rockchip cp rk3568-evb.dts rk3568-realtime.dts5.2 GPIO 脉冲中断亲和性(编码器)
/* 保留 CPU1 给 Linux,CPU2/3 给实时 */ / { reserved-memory { gpio_rt_reserved: gpio_rt_reserved { reg = <0x0 0x30000000 0x0 0x100000>; /* 1 MB DMA buffer */ no-map; }; }; gpio_enc: gpio-enc { compatible = "gpio-pps"; pinctrl-names = "default"; pinctrl-0 = <&gpio_enc_pins>; interrupt-parent = <&gpio0>; interrupts = <RK_PA0 IRQ_TYPE_EDGE_RISING>; interrupt-affinity = <&cpu2>; /* 关键:绑核 */ }; }; &pinctrl { gpio_enc_pins: gpio-enc-pins { rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; }; };作用:编码器脉冲中断直接上 CPU2,绕过 CPU0 调度域。
5.3 SPI 帧中断亲和性(GSML 相机)
&spi1 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&spi1m1_pins>; cs-gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_LOW>; interrupt-parent = <&gpio1>; interrupts = <RK_PB1 IRQ_TYPE_LEVEL_HIGH>; interrupt-affinity = <&cpu3>; /* 绑 CPU3 */ /* 50 MHz 速率,实时低延迟 */ assigned-clock-rates = <50000000>; };5.4 ADC DMA 预留内存(零拷贝)
&adc { status = "okay"; dmas = <&dmac0 0>; dma-names = "rx"; memory-region = <&gpio_rt_reserved>; /* 复用同一块预留内存 */ };5.5 编译 & 验证
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- rk3568-realtime.dtb sudo cp rk3568-realtime.dtb /boot/dtbs/ # 编辑 extlinux.conf 新增 FDT 行,重启验证 1:中断亲和性
cat /proc/interrupts | grep -E "spi1|gpio0" # 看到 CPU2/3 计数增加,CPU0/1 几乎为 0验证 2:实时线程绑核
/* user_space.c */ cpu_set_t set; CPU_ZERO(&set); CPU_SET(2, &set); /* 与 GPIO 同核 */ sched_setaffinity(0, sizeof(set), &set);验证 3:抖动测量
sudo cyclictest -p95 -m -Sp90 -i200 -d60s # Max latency 从 120 µs → 18 µs六、常见问题与解答(FAQ)
| 问题 | 现象 | 解决 |
|---|---|---|
| dtc 编译报错 “interrupt-affinity” unknown | 旧版本设备树绑定未更新 | 升级 kernel 到 5.15+,或手动加属性定义 |
| 中断仍落在 CPU0 | affinity 写错核号 | 核对 cpu-map,确保 &cpu2 存在且 online |
| 预留内存无法 DMA | 物理地址非连续 | 使用no-map+dma-coherent属性 |
| SPI 速率改无效 | 时钟源未指定 | 加assigned-clocks+assigned-clock-rates |
| 实时线程迁移失败 | 权限不足 | 用sudo或给线程加CAP_SYS_NICE |
七、实践建议与最佳实践
CPU 分区
0/1 供 Linux 调度、文件系统;2/3 专供实时中断/线程,isolcpus=2,3 rcu_nocbs=2,3启动参数必加。中断优先级线程化
PREEMPT_RT 下,所有中断变线程,用chrt -f 95把 SPI 线程提至 FIFO 95,再测抖动。引脚复用检查
修改pinctrl后,执行gpioinfo | grep PA0确认未被其他驱动占用。DMA 对齐
预留内存起始地址按 1 MB 对齐,避免页表分裂。Git 追溯
每次 DTS 修改单独 commit,Message 写“SIL 2: isolate spi1 interrupt to cpu3”,审计时快速定位。CI 自动化
GitLab Runner 里加dtc -I dts -O dtb rk3568-realtime.dts编译检查,MR 即反馈语法错误。
八、总结:一张脑图带走全部要点
瑞芯微设备树实时优化 ├─ 中断亲和:interrupt-affinity → CPU2/3 ├─ 预留内存:no-map + dma-coherent ├─ 引脚复用:pinctrl-0 检查冲突 ├─ 线程绑核:isolcpus + sched_setaffinity └─ 验证:cyclictest + /proc/interrupts设备树不是“黑盒子”,而是实时性的“总开关”。
当你把 GPIO、SPI、ADC 一条一条绑到专属 CPU,再用 cyclictest 看到 Max 延迟从百微秒降到十微秒时,会深刻体会到——“实时性不是魔法,只是资源的精准规划。”
把这份模板 push 到你的仓库,下一款边缘视觉、运动控制、国产化 PLC 产品,就能在“硬实时”跑道上,先人一步起飞!