IMX6 Linux系统下串口丢包错包问题研究

来源:互联网 发布:java try catch嵌套 编辑:程序博客网 时间:2024/05/21 16:22

IMX6 Linux系统下串口丢包错包问题研究

IMX6芯片简介

摘自互联网

http://www.ic72.com/ZhanHui/2013-02-01/209182.html

1. IMX6 soc 芯片架构图

图1
IMX6 SOC

2. 串口的使用情况

IMX6 SOC系列芯片有5个异步串口可以使用,可以用于连接蓝牙,单片机,GPS模块等等外围芯片。串口的作用,就像神经系统一样,连接各个器官。因此串口通信的稳定性,还是非常重要的。

3. 串口接口定义

引用CSDN其他博客

http://blog.csdn.net/yangshuodianzi/article/details/8997478

这里要讨论的两点:数据传输和流量控制。

  1. 数据传输:
    一般使用串口的场景,使用三个引脚就可以进行正常的数据传输,TX,RX和GND。比如IMX6的调试串口,此时也仅仅是为了满足打印log这个需求,并不要求一个字节都不能丢,毕竟仅仅是为了调试方便。
  2. 流量控制:
    流量控制严格的讲,应该要区分软件流控和硬件流控。软件流控,指的是采用软件的方式,来控制数据流的传输与停止,从而来避免缓冲区的溢出,从而保障数据的安全。硬件流控,顾名思义,是由硬件层面直接参与的,软件配置使能之后,就可以无人值守自动运行的流量控制方式。
    但是,在嵌入式芯片里面,往往引脚的数量都是很有限的,需要在各个功能模块之间进行复用,因此,流控相关的引脚可能已经被其他功能模块占用,无法开启流控。

4. 串口丢包错包可能原因分析

  1. 串口线的问题:
    噪声干扰严重,导致数据某个比特位出现反转,1变成0,或者0变成1。造成这个问题的原因,一般是线路受损了,比如导线破损铜线外露,这个情况一般更换一根好的串口线一般可以解决。
  2. 串口FIFO溢出:
    直接会造成丢一个或者多个字节的情况。造成这个问题的直接原因,一般就是CPU处理不及时,来不及从串口FIFO里面读取数据,从而造成FIFO溢出丢数据。一般情况下,串口驱动收数据是采用异步中断的方式来进行,来个中断,然后CPU就巴拉巴拉的去FIFO里面取数据,然后丢到TTY层。但是,如果在串口数据到来,但是CPU中断又来不及响应的时候,就会丢包。

5. Linux 内核驱动层面规避串口丢包

  • 无硬件流控串口丢包发生时机点

    1. 处理当前串口中断的CPU被其他中断抢占
      IMX6系列CPU,默认的IRQ中断优先级,是中断号小的,优先级高,可以优先处理。所以,如果当串口的数据已经来临,FIFO接受到的数据,已经达到触发中断的阈值,此时应该是产生串口中断了,但是呢,此时此刻,刚好比其中断号小的其他中断:比如另外一个串口中断,或者MMC中断,刚好也有数据要处理,那么,中断号小的优先。

      IMX6部分中断列表

      比如我手头的一台IMX6 4核机器上面的中断列表,有三个串口,中断号分别为:58,60,和62。其中58号中断,就要比60号中断优先处理。如果58号中断狂飙了,导致60号中断一直得不到处理,那么60号中断所在串口,就有可能发生FIFO溢出的情况,数据就丢了。

    2. 处理当前串口中断的CPU,内核的其他代码,关闭中断时间太长。
      在内核代码里面,不乏有很多加锁的代码,目的是为了保证CPU访问目标代码片段的次序不被打断。当这个代码片段跟中断上下文紧密相关的时候,这个锁就需要关闭中断。如下这个代码片段,在调用__drain_alien_cache() 函数的前后,加上了spinlock_irqsave()和spinlock_irqrestore(),结合了spin_lock和中断关闭的操作。

static void drain_alien_cache(struct kmem_cache *cachep,                struct array_cache **alien){    int i = 0;    struct array_cache *ac;    unsigned long flags;    for_each_online_node(i) {        ac = alien[i];        if (ac) {            spin_lock_irqsave(&ac->lock, flags);            __drain_alien_cache(cachep, ac, i);            spin_unlock_irqrestore(&ac->lock, flags);        }    }}

很显然,在中断关闭的过程当中,IRQ中断是得不到处理得,因为关闭中断得操作,把本地CPU中断给禁用了暂时,不会响应IRQ中断。因此,以这个代码片段为例,如果__drain_alien_cache()执行时间太长,而恰好在这段时间之内,串口来数据了又得不到处理,那么就有可能造成FIFO溢出,从而丢包。
- 规避方案
一个简单暴力直接的方法:将需要避免丢包的串口的中断,绑定到一个CPU上,从而避免中断之间的干扰。另外,需要找到关闭中断的代码,确保其关闭中断时间不会太长,不然的话,丢包还是会发生的。

1 0
原创粉丝点击