一起学linux总线驱动之DMA传输

原文来自
https://blog.csdn.net/eastmoon502136/article/details/8502087

DMA(Direct Memory Access,直接存储器访问) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用

在实现DMA传输时,是由DMA控制器直接掌管总线,因此,存在着一个总线控制权转移问题。即DMA传输前,CPU要把总线控制权交给DMA控制器,而在结束DMA传输后,DMA控制器应立即把总线控制权再交回给CPU。一个完整的DMA传输过程必须经过DMA请求、DMA响应、DMA传输、DMA结束4个步骤。

DMA工作过程

曾金鹏
对于嵌入式中的DMA,其实是在写数据寄存器的时候用dma的传输来代替。就像i2c设备,在发送和接收数据的时候都是要往数据寄存器中写数据的。比如那个寄存器是I2C_DATA,如果用cpu来传输的话就是writel(data, I2C_DATA);而用dma传输就是配置好要传输的buf长度,然后源地址就是buf的地址,目标地址就是I2C_DATA。

   这里还要注意经过cpu的是虚拟地址,而dma传输的是物理地址。

   其实dma传输就是dma控制在两个物理地址之间传输数据。

Linux下用dma传输主要调用下面这些函数就可以实现外部的dma了。
在这里插入图片描述
1、初始化DMA

  dma_cap_zero(mask);
   dma_cap_set(DMA_SLAVE,mask); /*1. Init rx channel */
   dws->rxchan= dma_request_channel(mask, dma_chan_filter, params);
   主要就是申请DMA通道。

   dma_chan_filter这个函数主要是查找你的dma传输的设备的请求信号线,其具体是在注册时填写的。

这里会根据这个函数返回的真假来判断已经注册在总线上的dma slave的。

buf =kmalloc(DMA_BUFFER_SIZE, GFP_KERNEL);
//申请一块地址,用来DMA传输的数据就放在这里
sg_init_one(&dma_dev->dmatx.sg, buf, DMA_BUFFER_SIZE);
//初始化,其主要为了发送时虚拟地址和物理地址的映射。

2、启动DMA

   struct dma_async_tx_descriptor *txdesc = NULL;
   struct dma_chan *txchan,;
   struct dma_slave_config txconf;
   txchan= dws->txchan;
   /*2. Prepare the TX dma transfer */
   txconf.direction= DMA_TO_DEVICE;              //表示dma传输方向为发送
   txconf.dst_addr= dws->dma_addr;                   //目标地址,物理地址
   txconf.dst_maxburst= LNW_DMA_MSIZE_16; //最大传输的字节数
   txconf.dst_addr_width= DMA_SLAVE_BUSWIDTH_2_BYTES;  //数据的位宽

   txchan->device->device_control(txchan,DMA_SLAVE_CONFIG,
                               (unsigned long) &txconf);
  
   dws->tx_sgl.length= dws->len;    //要传输的数据的长度

dma_map_sg(dma_dev->dev,&dmatx->sg, 1, DMA_TO_DEVICE);
//通过这个函数来实现虚拟地址和物理地址的映射。

   txdesc= txchan->device->device_prep_slave_sg(txchan,
                        &dws->tx_sgl,
                        1,
                        DMA_TO_DEVICE,
                        DMA_PREP_INTERRUPT| DMA_COMPL_SKIP_DEST_UNMAP);
   txdesc->callback= dw_spi_dma_done;   //传输完成后的回调函数
   txdesc->callback_param= params;      //回调函数中的参数

   dmaengine_submit(txdesc);

dma_dev->device_issue_pending(txchan); // 启动dma传输了

配置好后,这样DMA就会开始传输了,然后传输完了以后就会有调用callback函数

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值