• 和菜鸟一起学linux总线驱动之DMA传输


        最早接触DMA的时候是大三的微机原理,当时不是很理解,什么DMA模式啊,只知道是传输速度快,不经过CPU,但是到底是怎么样的不经过CPU呢?还是不理解。这次I2C控制器里面带了DMA的模式,所以有机会去接触下了。

           而具体的DMA的意思是什么http://baike.baidu.com/view/32471.htm,百度百科里还是不错的。

     

    DMA的工作过程:

     

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

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

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

     

    Linux下用dma传输主要调用下面这些函数就可以实现外部的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函数。

     

     

  • 相关阅读:
    毕昇编译器优化:Lazy Code Motion
    JavaScript 里三个点 ...,可不是省略号啊···
    Python图像处理丨如何调用OpenCV绘制直方图
    华为云全流程护航《流浪方舟》破竹首发,打造口碑爆款
    游戏开发常遇到数据一致性BUG,怎么解?
    看到这个应用上下线方式,不禁感叹:优雅,太优雅了!
    不止跑路,拯救误操作rm rf /*的小伙儿
    索引设计 《数据库高效优化》 p300
    科学学习法
    读运维MySQL计划有感1 mysql默认索引,mysql执行计划,mysql索引分类
  • 原文地址:https://www.cnblogs.com/wuyida/p/6300030.html
Copyright © 2020-2023  润新知