am335x spi 在中断里直接调用底层api接口,提高数据读取速度。避免内核调用工作队列导致读取数据不及时,丢数据

项目描述:最近做一个am335x主控板做数据读取显示,fpga做采集板,FPGA数据采集玩后会给am335x发送一个中断,当am335x收到中断后,开启一个软中断通过spi总线读取fpga的数据

问题:由于fpga每个中断间隔是 < 1ms,在中断读取的时候调用sync接口,底层会开启一个工作队列,这样就会超时。导致数据读取错误。

解决思路:在中断里掉用底层的发送接口。这样避开内核创建工作队列的代码

一、中断里的修改

static irqreturn_t fpga_to_arm_hard_irq(int irq, void *dev_id)
{
    int ret = IRQ_WAKE_THREAD;
    return ret;
}

static irqreturn_t fpga_to_arm_soft_irq(int irq, void *dev_id)
{
    struct ad7606_spi_chip *ad7606_chip = dev_id;
    struct spi_device *spi = (struct spi_device*)ad7606_chip->spi;
	struct spi_message message;
	struct spi_transfer msg_buf;

	memset(&msg_buf, 0, sizeof(msg_buf));
	msg_buf.bits_per_word = 8;
	msg_buf.speed_hz = spi->max_speed_hz;

        spi_message_init(&message);
	message.spi = spi;
	msg_buf.rx_buf = ad7606_chip->data;
	msg_buf.len = MAX_FRAME_LEN;
	spi_message_add_tail(&msg_buf, &message);
	//spi_sync(spi, &message);

	spi->master->cur_msg = &message;
	spi->master->prepare_message(spi->master,&message);
	spi->master->cur_msg_prepared = true;
	spi->master->transfer_one(spi->master,spi,&msg_buf);


    if(ad7606_chip->data[0] != 0x55) {
        pr_err("data 55 receive error, %d\n", ad7606_chip->data[0]);
    }
    if(ad7606_chip->data[1] != 0xAA) {
        pr_err("data AA receive error\n");
    }
    if(ad7606_chip->data[2] != 0x33) {
        pr_err("data 33 receive error\n");
    }
    if(ad7606_chip->data[3] != 0xBB) {
        pr_err("data BB receive error\n");
    }
    if(ad7606_chip->data[22] != 0x66) {
        pr_err("data 66 receive error\n");
    }
    if(ad7606_chip->data[23] != 0x66) {
        pr_err("data 66 receive error\n");
    }

    memcpy((void*)&ad7606_chip->arm_map->buf[ad7606_chip->arm_map->tail], (void*)&ad7606_chip->data[4], MAX_FRAME_DATA_LEN);
    if(ad7606_chip->arm_map->tail < DATA_LEN)
        ad7606_chip->arm_map->tail += MAX_FRAME_DATA_LEN;
    if(ad7606_chip->arm_map->tail == DATA_LEN)
        ad7606_chip->arm_map->tail = 0;

    return IRQ_HANDLED;
}

 二、spi核心层

   导出spi_map_msg 接口,改接口在使用dma时必须要调用

//static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
int spi_map_msg(struct spi_master *master, struct spi_message *msg)

EXPORT_SYMBOL_GPL(spi_map_msg);

 三、omap驱动

  C:\z_linux_picohood_prj\board-support\linux-4.4.x-mainline\drivers\spi\spi-omap2-mcspi.c

            3.1 omap2_mcspi_transfer_one 修改

            当使用dma 方式时,发现调用系统卡死,发送数据到4096个字节就奔溃了,调试发现需要关闭fifo,应该是fifo有个阈值,dma发送速度超过这个fifo大小就卡死了

            3.2 omap2_mcspi_transfer_one 修改

     在调试时。因为我的spi-omap2-mcspi.c是模块加载的方式,因此在内核加载时就崩溃。

       经过调试发现,直接调用底层时需要再次打开电源管理,否则内核直接挂掉。

    出错的现象,这个原因找了很久才知道时电源的问题,还要抽空仔细看看电源管理

 

     3.3 omap2_mcspi_transfer_one 修改

    当驱动直接调用底层接口时为了实现快速的数据读取,采用dma的方式。dma的方式需要修改2个地方

              添加映射

	/*add by lsh*/
	spi_map_msg(master, master->cur_msg);

        修改最小字节数

 /*add by lsh*/
//#define DMA_MIN_BYTES			160
#define DMA_MIN_BYTES			0

        3.3 omap2_mcspi_prepare_message修改

    改了上面接口。发现驱动能跑起来。但是一直卡在驱动里。提示数据接收超时

    又是艰苦的调试。分析代码加打印。各种折腾。最后确定是底层接口还需要调用 omap2_mcspi_set_cs

	/*add by lsh*/
	omap2_mcspi_set_cs(msg->spi, msg->spi->mode & SPI_CS_HIGH);  
     pm_runtime_get_sync(mcspi->dev);

到此算是满足了要求

解决的思路:从spi_sync(spi, &message);

  分析spi_sync的具体调用过程。看其中用到哪些接口。排除不必要的接口,过程是很漫长。有空再写

posted on 2019-01-20 16:17  紫枫术河  阅读(836)  评论(0)    收藏  举报

导航