Linux高速SPI ADC驱动4k采样率丢数问题求解及优化建议
问题根因
你当前出现丢数的核心原因是工作队列的调度优先级过低+同步SPI传输的阻塞开销,4k采样率对应的中断间隔仅250μs,默认工作队列属于进程上下文底半,很容易被系统其他进程抢占,只要调度延迟超过250μs就会出现中断堆叠、数据丢失的问题。
优化方案
- 替换底半调度机制
不要使用系统默认的共享工作队列,自行创建带WQ_HIGHPRI标志的专用高优先级工作队列,还可以将工作队列线程绑定到孤立的CPU核心上(关闭该核心的其他进程调度),最大程度降低调度延迟。如果还不够可以直接改用线程化中断(threaded irq),直接设置中断线程的实时优先级(SCHED_FIFO优先级设为90以上),优先级远高于普通进程,基本不会被抢占。 - 替换SPI传输接口
你当前用的spi_sync_transfer是同步阻塞接口,调用后会主动睡眠等待传输完成,额外增加了调度开销。改用spi_async异步传输接口,注册传输完成回调处理数据,不需要阻塞等待,底半执行时间可以压缩到微秒级。 - 删除不必要的性能损耗操作
你代码中的printk是非常重的操作,4k采样率下每次传输都打印日志会占用大量CPU资源,直接注释掉所有调试用的打印,必要时可以用tracepoint代替日志输出。如果你的SPI控制器支持硬件CS管脚管理,不要自己用gpio_set_value控制CS,交给SPI核心自动处理,减少额外的GPIO操作开销。 - 复用原生子系统能力
不需要自己从零实现ADC采样、缓冲、用户态通知的逻辑,直接用Linux原生的IIO子系统,该子系统已经针对高速ADC采样做了专门优化,支持硬件触发、环形缓冲区、mmap直接映射到用户空间,不需要拷贝数据,性能和稳定性都远高于自定义实现,4k采样率的场景完全可以做到零丢数。 - 开启SPI硬件加速
检查你的SPI控制器驱动是否支持DMA模式,开启DMA传输后,SPI数据传输不需要CPU参与,传输效率比PIO模式高很多,CPU开销也会大幅降低。
如果以上软件优化都无法满足需求,可以在硬件层面做小修改:给ADC加一级带FIFO的微控制器,先缓存一定量的ADC数据再批量传给Linux主机,降低中断触发频率,从根源上避免短时间中断过多的问题。
内容的提问来源于stack exchange,提问作者gaosiy
相关产品推荐
相关产品推荐

