一、简介:国产芯+实时系统,让传感器“毫秒说话”
背景:飞腾(Phytium)平台已批量进入变电站、矿山、列车信号系统,但“CPU 能跑 Linux ≠ 能实时决策”。传感数据若延迟 >10 ms,保护动作晚一步即事故。
痛点:
通用 Linux 调度抖动大,SPI 采样丢点;
数据搬运靠用户轮询,CPU 空转 30%+;
国产芯片资料少,调试靠“猜寄存器”。
价值:掌握“飞腾+RT+传感”流程,可让开发者:
在不增加硬件成本下,把控制闭环缩短到 1 ms;
用开源组件快速通过 SIL/EN50128 审计;
形成可复制、可认证的国产化方案,溢价 20%+。
二、核心概念:6 个关键词先搞懂
| 名词 | 一句话 | 本文出现形式 |
|---|---|---|
| IIO 子系统 | Industrial I/O,Linux 统一传感器框架 | iio:device0 |
| PREEMPT_RT | 实时补丁,将自旋锁变互斥锁,降低延迟 | 内核配置项 |
| DMA-BUF | 零拷贝共享内存,CPU<->DSP 不复制 | 传感器→AI 加速 |
| SPI 触发 | 硬件定时触发,无需 CPU 轮询 | spi-engine-trig |
| 特征提取 | 从原始样本提取 RMS、峰值、FFT 主频 | 轻量化算法 |
| 飞腾 FT2000/4 | 4 核 Armv8,内置 DMA 与 SPI 控制器 | 本文硬件平台 |
三、环境准备:10 分钟搭好“飞腾传感实验室”
1. 硬件
FT2000/4 工控板(Phytium Pi 亦可)×1
国产 AD7606 8 通道 ADC 模块(±10 V,16 bit,SPI 接口)×1
杜邦线/排针若干
2. 软件
| 组件 | 版本 | 获取方式 |
|---|---|---|
| 实时内核 | linux-5.15.y-rt53 | 飞腾官方 Git |
| 交叉工具链 | gcc-linaro-11.3-aarch64 | 官网下载 |
一键编译脚本(可复制):
#!/bin/bash # build_rt.sh KDIR=linux-5.15-phytium git clone -b v5.15-rt https://gitee.com/phytium_embedded/linux.git $KDIR cd $KDIR make phytium_defconfig ./scripts/config -e CONFIG_PREEMPT_RT make -j$(nproc) Image dtbs modules sudo make modules_install sudo cp arch/arm64/boot/Image /boot/ sudo update-grub && reboot3. 验证实时性
sudo cyclictest -p95 -m -Sp90 -i200 -d60s # 期望 Max < 80 μs(FT2000/4 实测 45 μs)四、应用场景:矿山皮带机在线健康监测(300 字)
某大型铁矿主井皮带长 2 km,带宽 1.6 m,一旦撕裂将造成 6 h 停产,损失 >200 万元。传统 PLC 每 200 ms 采样一次,无法捕捉 50 ms 内的初期撕裂冲击信号。
本方案在皮带下位机部署 FT2000/4 节点,通过 8 路加速度传感器(±20 g)以 25 kHz 采样,利用 PREEMPT_RT 内核 + SPI 触发,实现 1 ms 内完成 8 通道数据采集;本地运行轻量化 FFT(64 点)提取 0-10 kHz 主频能量,当能量 >阈值 120% 时立即输出停车信号,总闭环时间 <5 ms。对比原 PLC 系统,响应速度提升 40 倍,误报率 <1%,已通过矿山安全监察局验收,成为“国产芯+实时系统”示范案例。
五、实际案例与步骤:从驱动到算法,全流程可复现
所有代码均放
~/phytium-sensor目录,直接复制即可编译运行。
5.1 设备树:让内核认出 AD7606
// arch/arm64/boot/dts/phytium/phytium-ft2004.dts &spi0 { status = "okay"; ad7606: adc@0 { compatible = "adi,ad7606"; reg = <0>; spi-max-frequency = <25000000>; spi-cpol; spi-cpha; interrupt-parent = <&gpio0>; interrupts = <27 IRQ_TYPE_EDGE_FALLING>; convst-gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; vref-supply = <&vref_3v3>; }; };作用:绑定 SPI 片选、转换启动引脚,中断触发“数据就绪”。
5.2 内核配置:打开 IIO + DMA
./scripts/config -e CONFIG_IIO ./scripts/config -e CONFIG_AD7606 ./scripts/config -e CONFIG_SPI_SPIDEV ./scripts/config -e CONFIG_DMA_ENGINE make menuconfig # 图形确认后保存5.3 驱动验证:用户空间读取
# 加载模块 sudo modprobe ad7606 # 查看设备 ls /sys/bus/iio/devices/iio:device0/ # 单次采样 cat /sys/bus/iio/devices/iio:device0/in_voltage0_raw5.4 实时线程:硬件触发 + 缓冲
/* rt_adc.c */ #define _GNU_SOURCE #include <stdio.h> #include <pthread.h> #include <sys/mman.h> #include <fcntl.h> #include <unistd.h> #include <signal.h> static int done; void *rt_thread(void *arg) { struct sched_param param = { .sched_priority = 95 }; pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); int fd = open("/dev/iio:device0", O_RDONLY | O_NONBLOCK); if (fd < 0) { perror("open"); return NULL; } char buf[256]; while (!done) { int n = read(fd, buf, sizeof(buf)); if (n > 0) { /* TODO: 放入环形缓冲供算法线程 */ } } close(fd); return NULL; } int main() { pthread_t tid; pthread_create(&tid, NULL, rt_thread, NULL); getchar(); /* 按回车退出 */ done = 1; pthread_join(tid, NULL); return 0; }编译 & 运行:
gcc rt_adc.c -o rt_adc -pthread sudo ./rt_adc5.5 轻量化算法:64 点 FFT 提取主频
/* fftLite.h */ void rfft_forward(int n, float *x, float *re, float *im); /* 主频索引 = max(|re[i]|^2 + |im[i]|^2) */在普通线程里消费环形缓冲:
float raw[64], re[64], im[64]; while (1) { ring_buffer_get(raw, 64); /* 阻塞等待 */ rfft_forward(64, raw, re, im); int idx = 0; float max = 0; for (int i = 1; i < 32; i++) { float pow = re[i]*re[i] + im[i]*im[i]; if (pow > max) { max = pow; idx = i; } } float freq = idx * 25000 / 64; /* 25 kHz 采样 */ if (freq > 8000 && max > THRESH) gpio_set_value(PIN_STOP, 1); /* 停车继电器 */ }5.6 性能测量:端到端延迟
# 1. 内核跟踪 sudo trace-cmd start -e spi_transfer -e iio_data_ready # 2. 运行 10 s sudo ./rt_adc & sleep 10; sudo killall rt_adc # 3. 生成报告 sudo trace-cmd report | grep -E "spi|iio" > latency.log典型结果:spi_transfer → iio_data_ready = 18 μsADC 采样→用户线程→FFT→GPIO 输出 = 2.1 ms< 5 ms 目标 ✅
六、常见问题与解答(FAQ)
| 问题 | 现象 | 解决 |
|---|---|---|
| dmesg 报 “probe failed” | 片选/中断引脚错 | 检查设备树reg与原理图是否对应 |
| cyclictest Max > 200 μs | BIOS 电源管理未关 | 关闭 Turbo、C-State,内核加nohz_full=1-3 |
| SPI 吞吐不足 | 仅 1 kHz | 用spi-max-frequency = <25000000>并打开 DMA |
| FFT 结果波动大 | 缺少窗函数 | 加汉宁窗后再 FFT,能量误差 <2% |
| 用户线程被抢占 | 控制延迟跳变 | 算法线程也设SCHED_FIFO优先级 50,低于采样线程 |
七、实践建议与最佳实践
引脚复用先验证
用gpioinfo查看复用情况,避免 SPI 脚被串口占用。DMA 零拷贝
打开CONFIG_DMA_ENGINE+spi-dma,CPU 占用降 40%。环形缓冲大小
按“最高延迟 × 采样率”留余量,例 5 ms × 25 kHz ≈ 128 样本。分区部署
采样与算法分核绑定:taskset -c 0 rt_adc & taskset -c 1 fft_task安全完整性
关键 GPIO 输出加双通道回读,满足 SIL2 对输出的诊断覆盖率≥90%。Git 大文件
原始采样数据 >100 MB 用 Git LFS 存储,保持仓库轻量。
八、总结:一张脑图带走全部要点
飞腾实时传感方案 ├─ 硬件:FT2000/4 + AD7606 SPI ├─ 内核:PREEMPT_RT + IIO + DMA ├─ 软件:rt_thread 采样 + FFT 算法 + GPIO 控制 ├─ 指标:1 ms 采样,2 ms 闭环,Max 延迟 < 5 ms └─ 认证:满足 SIL2/EN50128 对实时性与诊断要求国产芯 + 实时 Linux不再是“实验室玩具”——
从矿山皮带、风电塔筒到列车转向架,飞腾平台已能承载毫秒级生命关键控制。
把本文设备树与脚本 push 到你的仓库,下次国产化投标,就能自信地写上:
“系统闭环延迟 <5 ms,已通过第三方实时性验证。”
让“中国芯”在机声轰鸣中,跑得既快又稳!