核心内容摘要
ADC年龄确认:一场关于“大驾光临大象”的奇遇
简介中断延迟决定“实时”天花板工业视觉打标飞拍 1 ms 窗口中断延迟 50 µs → 拍照位置偏移
1 mm废标。
伺服驱动器编码器 Z 脉冲捕获延迟 100 µs → 过零误差速度环震荡。
瑞芯微 GIC-600 虽支持亲和性/优先级但默认 BSP 为吞吐量优化未考虑实时。
本文给出“中断线程化 亲和性 ftrace 定位”三板斧适配 RK 官方 SDK 与开源 PREEMPT_RT零硬件改动即可达微秒级响应。
核心概念5 张图看懂 RK 中断链路名词一句话寄存器/节点GIC-600瑞芯微集成中断控制器支持 256 优先级基址 0xfd400000IRQ Domain内核映射“硬件 IRQ 号 → 虚拟 irq_desc”/proc/interrupts线程化 IRQ把中断下半部变成实时线程可设 SCHED_FIFO 优先级request_threaded_irq()中断亲和性指定 CPU 核处理中断避免迁移/proc/irq/xxx/smp_affinityftrace irqsoff追踪“关中断”时间片定位延迟源头trace-cmd
环境准备10 分钟搭好“RKRT”工作台
硬件RK3568 EVB 或 RK3588 行业板≥4 核 Cortex-A55/A76串口线 网线SSH 调参更方便
软件组件版本获取方式RK SDKrelease/rk356x_linux
15_202303GitHub 官方仓库PREEMPT_RT 补丁patch-
5.
1
71-rt
patch.xzkernel.org交叉工具链gcc-arm-
1
3-
2
07瑞芯微百度云调试工具trace-cmd
3.
5apt install trace-cmd
一键打 RT 补丁可复制cd kernel xzcat ../patch-
5.
1
71-rt
patch.xz | patch -p1 ./scripts/config -e CONFIG_PREEMPT_RT ./scripts/config -e CONFIG_DEBUG_PREEMPT make ARCHarm64 rockchip_linux_defconfig make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- -j$(nproc) Image dtbs # 烧录到板子参考 SDK 文档重启后uname -r #
5.
1
71-rt53
应用场景边缘视觉缺陷检测300 字某 3C 产线使用 RK3568 500 万像素工业相机帧率 120 fps触发信号为外部光电传感器 IRQ。
痛点默认中断延迟
µs图像采集时刻滞后导致打标坐标整体偏移
15 mm良率仅 92%。
目标把中断响应传感器上升沿 → 中断服务第一条指令压缩到 ≤20 µs同时保持 CPU 负载 30%。
方案传感器 IRQ 号 55 线程化SCHED_FIFO:95亲和性绑定 CPU2隔离核关闭 CPU 变频ftrace 验证 irqsoff 10 µs最终延迟稳定
µs良率提升至
9
2%满足客户 SIL 2 安全完整性等级对实时性的要求。
实际案例与步骤从 200 µs 到 14 µs 的 4 步实操所有脚本放/home/rk/rt_irq/可直接复制运行。
1 步骤1确定 IRQ 号 当前延迟基线# 查传感器所用中断号GPIO Bank0 IRQ 合并为 gic-55 cat /proc/interrupts | grep gpio0 # 55: 120000 gic-0 20 Edge gpio0基线测试用户按钮模拟触发# 编译内核模块 irq_latency.c代码见附录 make sudo insmod irq_latency.ko irq55 # 结果avg185 µs, max210 µs
2 步骤2中断线程化 优先级/* 在内核驱动中使用 request_threaded_irq */ dev-irq gpio_to_irq(sensor_gpio); request_threaded_irq(dev-irq, NULL, /* 无需快速上半部 */ sensor_thread_fn, /* 实时线程 */ IRQF_ONESHOT, sensor_rt, dev); /* 在线程函数里提升优先级 */ static int sensor_thread_fn(int irq, void *data) { struct sched_param param { .sched_priority 95 }; sched_setscheduler(current, SCHED_FIFO, param); /* 用户处理点亮 GPIO、唤醒队列 */ return IRQ_HANDLED; }重新编译内核模块加载后ps -eo pid,pri,rtprio,comm | grep sensor_rt # 1234 99 95 sensor_rt
3 步骤3亲和性绑定 CPU 隔离# 将 IRQ 55 绑定到 CPU2 echo 4 /proc/irq/55/smp_affinity # 4 12 # 隔离 CPU2 免受普通任务干扰 echo isolcpus2 nohz_full2 rcu_nocbs2 /boot/cmdline reboot验证隔离taskset -c 2 stress-ng --cpu 1 top -1 # 仅 CPU2 负载 100%其余空闲 killall stress-ng
4 步骤4ftrace 定位剩余 irqsoff#
采集 10 s 关中断片段 sudo trace-cmd start -e irq_disable -e irq_enable -f cpu2 sudo trace-cmd stop sudo trace-cmd report trace.txt #
查看最大关中断时间 grep irq_disable trace.txt | awk {print $4} | sort -n | tail -1 # 预期max8 µs若 20 µs继续排查关闭CONFIG_DEBUG_PREEMPT量产关闭关闭 CPU 变频echo performance /sys/devices/…/scaling_governor最终复测sudo ./irq_latency.ko irq55 # avg15 µs, max18 µs
六、
常见问题与解答FAQ问题现象解决绑核后中断不再触发亲和性掩码写错echo 4代表 CPU212确认二进制位线程化后系统卡死线程里调用阻塞 API线程函数禁止msleep()用wait_queueftrace 无 irq_disable 事件事件未编译进内核打开CONFIG_TRACE_IRQFLAGSlatency 抖动 50→200 µs变频 电源管理BIOS 关闭 P-State内核加cpufreq.default_governorperformanceGPIO 中断丢失边沿触发过快改用双沿触发或输入去抖电路
实践建议与最佳实践统一封装提供rk_request_rt_irq()公共接口自动完成线程化 绑定 优先级驱动层零重复代码。
CPU 分区CPU0/1 跑业务CPU2 跑高优先级中断CPU3 跑ksoftirqd 日志避免相互抢占。
生产关闭调试量产内核关闭CONFIG_DEBUG_PREEMPT、CONFIG_LOCK_STAT减少额外关中断。
持续监控通过trace-cmd每晚自动采样 5 min latency 25 µs 自动发 Prometheus 告警。
热补丁更新使用livepatch更新中断处理函数避免停机产线。
文档同步中断号、CPU 亲和性、优先级全部写入《BSP 实时性配置表》变更需 MR 评审。
八、
总结一张脑图带走全部要点RK 实时中断优化 ├─ 线程化request_threaded_irq SCHED_FIFO ├─ 亲和性/proc/irq/XX/smp_affinity isolcpus ├─ 追踪trace-cmd irqsoff / latency histogram ├─ 降抖动关变频、关调试、绑核 └─ 持续 nightly trace 告警中断延迟每降低 10 µs产线良率就能提升
5%。
把本文脚本加入你的 RK SDK今晚就让cyclictest跑出第一条 20 µs 的曲线——瑞芯微 PREEMPT_RT实时性同样硬核