使用过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
|