最近在调试一个SPI转串口驱动WK2204,应用端读取串口数据时,会偶发性的出现丢数据的现象(每次传输3K字节,每3S传输一次,平均传输3次会丢失一次),大体分析思路及解决方案如下
分析:
硬件逻辑:物理串口数据是先通过SPI控制器传入内核,再通过内核驱动将数据发送至虚拟串口中。
uart--spi--CPU
代码逻辑:中断触发,启动工作队列,在队列线程中读取数据,并将数据发送到虚拟串口中。
irq_handle-->queue_work{ read_spi -->send_uart };
由于SPI转换模块是BUF只有256个字节,也就是说当超过一定时间驱动未读取BUF数据,则就会导致丢失现象。
那么先判断数据是在哪一个环节丢失的。我是先将驱动上报端代码屏蔽,丢失数据的现象有所降低,则说明上报程序影响到了SPI读取动作。所以就开辟一个线程用于执行send_uart
irq_handle-->queue_work{ read_spi } --kfifo-->{send_uart };
此方法还是不能彻底解决丢失问题,那就得从线程调度的思路上分析,由于queue_work中所开辟的线程优先级很低,所以我将工作队列修改成线程,并将优先级提高到了99。
s->kthread_r = kthread_create(wk2xxx_kthread_r, s, "wk2xxx_kthread_r");
struct sched_param param = {.sched_priority = 99,};
sched_setscheduler(s->kthread_r,SCHED_FIFO , ¶m);修改后丢失数据现象得到较大的改善,但还是不太理想。这时就得一一分析内核中其他驱动,是否过度的抢占了CPU资源。从三个角度分析:1.中断中是否存在大量耗时操作 2.自旋锁中的临界区是否执行大量任务。3.是否有大量的打印信息。最终找出几个驱动存在上述现象,对其进行优化后,此问题才最终解决。