1.2. DMA简述

在开始分析代码之前,先简要介绍一下DMA的基础知识。

1.2.1. 什么是DMA

DMA,Direct Memory Access,直接内存访问。

既然叫 直接内存访问,那么相对应地,应该就有 “间接的内存访问”。

间接的内存访问,我的理解是,就是指最常见的,我们利用CPU的指令,去从一个内存地址中读出数据,然后写到另外一个内存地址中,完成对应的赋值操作。

此过程,完全都是CPU去操作的,如果是单个这样的数据读取和写入,还没啥,但是如果数据量很大,比如我们用memcpy(addr1,addr2,1024)去从地址addr1地址开始,拷贝1024个字节到内存addr2处,那么CPU这段时间,就不要干别的事情了,就一直这么的给你读取,写入数据吧,另外的还有,常见于驱动中的,尤其是涉及到和外设打交道,我们让CPU从内存一个地址,读取了一个数据,然后写入到某个设备的FIFO或者DATA寄存器中,咋写入之前,常常会等待FIFO不是满的,然后才能写入数据,要从FIFO中读取数据,要等到FIFO不是空,才能读取,这样来来回回,会比较消耗资源。

鉴于此,才出现了DMA这个硬件设备,专门设计用来处理这些相对用CPU去操作这样的事情,效率很低,换做专门的硬件的DMA来负责数据的读取和写入,释放了CPU这个苦力,可以让,在DMA忙着数据传输的过程中,CPU去忙其他更重要的事情。而专门的DMA硬件负责这样的数据传输,效率也会更高。

之所以这样,才叫做内存直接访问的。

1.2.2. DMA的一些基础概念

DMA传输,总的来说就是:

硬件上,会有对应的控制寄存器ctrl和配置寄存器config,

比如你想要从内存一个地址addr传输,N个字word(32bit)的数据到设备dev上,

那么你就要先去根据你的请求,去配置config寄存器,首先是传输方向,

是DMA_TO_DEVICE,然后是源地址source address是你的内存地址addr,

和目标destination address是你的dev的DATA寄存器地址,

然后要传输额transfer size是N个,每个位宽是32bit,

将源地址,目标地址,位宽,DMA传输方向设置好,

整理成一个结构,专有名称叫做LLI(Link List Item),把这个LLi设置到ctrl里面。

然后去enable DMA,DMA就可以按照你的要求,把数据传输过去了。

这样的DMA叫做single DMA传输,LLI中的next lli的域设置为空,表示就一个LLI要传输。

如果源地址或目标地址是多个分散的地址,叫做scatter/gather DMA,

就要将这些LLI组合一下,即将第一个LLI的next lli那个域,设置成下一个LLI的地址,

这样一个个链接起来,最后一个LLI的nex lli的域为空,这样设置好后,将第一个LLI的值写入到ctrl中,DMA就会自动地去执行第一个LLI的数据传输,传完后,发现next lli不为空,就找到next lli的位置,

找到对应的配置,开始这个lli的数据传送,直至传完所有的数据为止。

说完了DMA的由来和基本概念后,下面来分析一下,具体的ARM的PL08x驱动是如何实现的。