打印
[i.MX]

imx6q spi从模式通过DMA接收数据异常

[复制链接]
2650|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
使用过imx6q spi从模式dma方式接收的朋友帮我看以下问题出在哪里?
1、 spi主模式给spi从发送数据(1k),时钟是15M,

2、spi从模式dma接收,定义每次dma搬运20个字节,在回调函数中把20个字节的数据memcpy到我指定的buf中,
     在回调函数中重新启动搬运,回调函数中累计搬运50次,把1000个字节打印出来。

3、从模式dma先使能,主模式在发送。

现在的现象是:
                1、打印的数据混乱.
                2、50次回调应该搬完数据了,后面还有SPI fifo溢出的打印。


下面是我的回调函数和dma配置使能的函数

/*回调函数中每次调用的函数*/
static int spidev_rxdma_start(struct spi_imx_data *spi_imx)
{
        int ret=0;
              struct dma_async_tx_descriptor *desc;
              int dir=DMA_TO_DEVICE;
              struct scatterlist * sg=NULL;
        unsigned long flag;
              struct dma_chan *chan;

        spin_lock_irqsave(&spi_imx->lock, flag);
        sg=&spi_imx->rx_sg;

        chan = spi_imx->dma_chan_rx;


        sg_init_one(sg,re_tstdata,20);

        ret=dma_map_sg(spi_imx->dev,sg,1,dir);
             if(ret!=1){
                 printk("spidev_rxdma_start: dma_map_sg  map failed ret = %d \n",ret);
                 return -EINVAL;       
              }


        //dma_sync_sg_for_device(spi_imx->dev, sg, 1, DMA_FROM_DEVICE);


             desc=chan->device->device_prep_slave_sg(chan,sg,1,DMA_DEV_TO_MEM,0);

        if(!desc){
                printk("device_prep_slave_sg---> Can not init dma descriptor \n");
        }

             desc->callback=spi_imx_dma_rx_callback;

        desc->callback_param=spi_imx;

             dmaengine_submit(desc);

             dma_async_issue_pending(spi_imx->dma_chan_rx);

             /* enable rx/tx DMA transfer */
             spi_imx->devtype_data.trigger(spi_imx);

        spin_unlock_irqrestore(&spi_imx->lock, flag);
        return 0;      
}


/*回调函数*/
static void spi_imx_dma_rx_callback(void * data)
{
        struct spi_imx_data *spi_imx=data;
        struct scatterlist  *sg=&spi_imx->rx_sg;
        u32 val = 0;
        int i;

        unsigned long flag;


        spin_lock_irqsave(&spi_imx->lock, flag);

        rec_num++;

        val = readl(spi_imx->base + SPI_IMX2_3_STAT);
        if(val & SPI_IMX2_3_STAT_RO){
               
             printk(" rx FIFO overflow!! \n");

        }
       
        //dma_sync_sg_for_cpu(spi_imx->dev, sg, 1, DMA_FROM_DEVICE);  //gxl 2016.6.27

        dma_unmap_sg(spi_imx->dev,sg,1,DMA_FROM_DEVICE);       

        memcpy(&rec_process[rec_num*20],re_tstdata,20);


        spin_unlock_irqrestore(&spi_imx->lock, flag);
        if(rec_num==50){
              printk("   rec_num = %d \n",rec_num);
              trigger_flag = 1;
              //for(i=0;i<250;i++)
              for(i=0;i<1000;i++)
                {
                            printk("   rec_process[  %d ] = %d, ",i,rec_process);
                            if(((i+1)%5)==0){
                                    printk("\r\n");
                            }

                }
              rec_num = 0;   
              //memset(rec_process, 0, 250);
              memset(rec_process, 0, 1000);
        }
        memset(re_tstdata,0,20);

        spidev_rxdma_start(spi_imx);


}
/*dma初始化*/
static int spi_imx_dma_init(struct spi_imx_data        *spi_imx)
{
        dma_cap_mask_t mask;
        struct imx_dma_data        dma_data;
        int ret=0;
        unsigned long flag;

        spin_lock_irqsave(&spi_imx->lock, flag);
       
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);

        dma_data.priority=DMA_PRIO_HIGH;       
        dma_data.dma_request=spi_imx->dma_req_rx;
        //dma_data.peripheral_type =IMX_DMATYPE_CSPI_SP;
        dma_data.peripheral_type =IMX_DMATYPE_CSPI;
        spi_imx->dma_chan_rx=dma_request_channel(mask,imx_spi_filter,&dma_data);
        if(!spi_imx->dma_chan_rx){
                pr_err("request spi rx dma chan failed");
                goto err;
        }
        //printk("spi_imx_dma_init--->spi_imx->dma_chan_rx = %d\n",spi_imx->dma_chan_rx);
       
        spin_unlock_irqrestore(&spi_imx->lock, flag);


        //printk("spi_imx_dma_init--->alloc spi dma buf ok!\n");
        return ret;

}

/*从设备开始接受数据执行的准备工作*/
static int spidev_rxstreamon(struct spi_imx_data *spi_imx)
{
               int ret=0;
              struct dma_slave_config slave_config;
              struct dma_async_tx_descriptor *desc;
              int dir=DMA_TO_DEVICE;
              struct scatterlist * sg=NULL;
              struct dma_chan *chan;
        unsigned long flag;


              struct spi_imx_config config;
              int ret_err=0,buf_len=0,rc=0;

               

        ret=spi_imx_dma_init(spi_imx);
        if(ret== 0)
        {
             printk("spi_imx_dma_init  finish ok! \n");
        }
        else{
                return ret;
        }

        chan = spi_imx->dma_chan_rx;

        slave_config.direction=DMA_DEV_TO_MEM;
        slave_config.src_addr=spi_imx->mapbase + MXC_CSPIRXDATA;
        slave_config.src_addr_width =4;        //(bpw/8)       
        slave_config.src_maxburst =8;   //(rx_threshold +1) * src_addr_width   /*FIXME*/


             ret = dmaengine_slave_config(chan, &slave_config);
             if (ret) {
                printk("spi_imx_dma_setup: dmaengine_slave_config failed ret = %d \n",ret);
                return -EINVAL;
             }

        config.bpw = 32;
        config.speed_hz  = 15000000;
        config.mode = 0;
        config.cs = 0;
       
        spi_imx->bpw = 32;               
        spi_imx->rx_threshold = 1;
          
        spin_lock_irqsave(&spi_imx->lock, flag);
                                                               
        spi_imx->devtype_data.config(spi_imx, &config);

        spin_unlock_irqrestore(&spi_imx->lock, flag);

        sg=&spi_imx->rx_sg;  

        re_tstdata = kzalloc(1000, GFP_KERNEL | GFP_DMA);
        sg_init_one(sg,re_tstdata,20);

        spin_lock_irqsave(&spi_imx->lock, flag);

        //re_tstdata = kzalloc(20,  GFP_DMA);

        //if(!re_tstdata){
        //        printk("kzalloc buf failed!!!");                       
        //}

        //sg_init_one(sg,re_tstdata,20);

             ret=dma_map_sg(spi_imx->dev,sg,1,dir);
             if(ret==0){
                 printk("spi_imx_dma_setup: dma_map_sg  map failed ret = %d \n",ret);
                 return -EINVAL;       
              }

        //dma_sync_sg_for_cpu(spi_imx->dev, sg, 1, DMA_FROM_DEVICE);  //gxl 2016.6.27

        //dma_sync_sg_for_device(spi_imx->dev, sg, 1, DMA_FROM_DEVICE);

             desc=chan->device->device_prep_slave_sg(chan,sg,1,slave_config.direction,0);

        if(!desc){
                printk("device_prep_slave_sg---> Can not init dma descriptor \n");
        }
        spin_unlock_irqrestore(&spi_imx->lock, flag);
                  
             desc->callback=spi_imx_dma_rx_callback;

        desc->callback_param=spi_imx;

        spin_lock_irqsave(&spi_imx->lock, flag);

             dmaengine_submit(desc);

             dma_async_issue_pending(spi_imx->dma_chan_rx);

             /* enable rx/tx DMA transfer */
             spi_imx->devtype_data.trigger(spi_imx);

        spin_unlock_irqrestore(&spi_imx->lock, flag);

}


下面是对spi的相关寄存器的操作的函数
static void __maybe_unused spi_imx2_3_slave_intctrl(struct spi_imx_data *spi_imx, int enable)
{
        unsigned val = 0;

        printk("get into function spi_imx2_3_slave_intctrl !!!\n");
        if (enable & MXC_INT_TE)
                val |= SPI_IMX2_3_INT_TEEN;

        if (enable & MXC_INT_RR)
                val |= SPI_IMX2_3_INT_RREN;
       
        if(enable&MXC_INT_TDR)
                val|=SPI_IMX2_3_INT_TDREN;
        printk("spi_imx2_3_slave_intctrl:val = %d \n",val);

        writel(val, spi_imx->base + SPI_IMX2_3_INT);
}

static void __maybe_unused spi_imx2_3_slave_trigger(struct spi_imx_data *spi_imx)
{
        u32 dma=0;               

        dma=SPI_IMX2_3_DMA_RXDEN|
                        (1<<SPI_IMX2_3_DMA_RX_TH_OFFSET);       

        writel(dma, spi_imx->base + SPI_IMX2_3_DMA_REG);
        return;
}

static int __maybe_unused spi_imx2_3_slave_config(struct spi_imx_data *spi_imx,
                struct spi_imx_config *config)
{

        u32 ctrl = SPI_IMX2_3_CTRL_ENABLE, cfg = 0;

        writel(0, spi_imx->base + SPI_IMX2_3_CTRL);  //reset control register

        ctrl |=SPI_IMX2_3_CTRL_MODE_MASK^(1<<(config->cs+4));

        ctrl |= SPI_IMX2_3_CTRL_CS(config->cs);
       
        /* set clock speed */
                                                                                 
        ctrl |= spi_imx2_3_clkdiv(spi_imx->spi_clk, config->speed_hz);

        ctrl |= (config->bpw - 1) << SPI_IMX2_3_CTRL_BL_OFFSET;


        cfg &=~(0xf<<8);  /*SSB_CTL need clear*/

        if (config->mode & SPI_CPHA)
                cfg |= SPI_IMX2_3_CONFIG_SCLKPHA(config->cs);

        if (config->mode & SPI_CPOL)
                cfg |= SPI_IMX2_3_CONFIG_SCLKPOL(config->cs);

       //slave +dma
        cfg |= SPI_IMX2_3_CONFIG_SSBPOL(config->cs);

        writel(ctrl, spi_imx->base + SPI_IMX2_3_CTRL);
        writel(cfg, spi_imx->base + SPI_IMX2_3_CONFIG);
        return 0;
}

static int __maybe_unused spi_imx2_3_slave_rx_available(struct spi_imx_data *spi_imx)
{
        printk("get into function spi_imx2_3_slave_rx_available !!!\n");
        int rc=readl(spi_imx->base + SPI_IMX2_3_STAT) & SPI_IMX2_3_STAT_RR;
        return rc;
}

static void  __maybe_unused spi_imx2_3_slave_reset(struct spi_imx_data *spi_imx)
{
        printk("get into function spi_imx2_3_slave_reset !!!\n");
        /* drain receive buffer */
        while (spi_imx2_3_slave_rx_available(spi_imx))
                readl(spi_imx->base + MXC_CSPIRXDATA);
}


现在从接收的现象如下:


接收完了1000字节函数spi fifo溢出的现象,那位朋友知道什么原因
file:///d:\Documents\Tencent Files\18848715\Image\C2C\XXFPX0L]IIQ$29N7U(O{}C8.png

相关帖子

沙发
gxlsunday|  楼主 | 2016-6-30 11:39 | 只看该作者
FAE 看过来

使用特权

评论回复
板凳
gxlsunday|  楼主 | 2016-6-30 12:23 | 只看该作者
FAE 帮忙看一下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

44

主题

87

帖子

2

粉丝