1.6. PL08X _cctl_data _cctl

/*
 * PL08X private data structures  ==== START
 */
struct _cctl_data{
	unsigned int tsize:12;1
	unsigned int sbsize:3;
	unsigned int dbsize:3;2
	unsigned int swidth:3;
	unsigned int dwidth:3;3
	unsigned int smaster:1;
	unsigned int dmaster:1;4
	unsigned int si:1;
	unsigned int di:1;5
	unsigned int prot:3;6
	unsigned int intr:1;7
};
union8 _cctl{
	struct _cctl_data bits;
	unsigned int val;
};
        

1

即TransferSize,传输大小,bit0-bit11,共12位。

表示,如果当前传输是DMA控制的情况下,当前此次DMA传输要传输的个数,其中每个具体大小是几个字节,由下面的位宽决定。

在配置完dma,开始传输后,此传输大小从你设置的值,即要传输的数,一点点减少直至0.如果读取此域,得到的值,表示当前还剩下多少个要传输。

不过特殊一点是,如果当前正在进行DMA传输,由于正在传输,所以你读取到的值,并不一定是真正的还剩多少个要传输的。一般用法是,在启用DMA传输,后来又由于传输完成后或者出错等特殊情况又禁用了DMA,此时再去读此域的值,就能真正有效地表示还多少没有传输的。

如果不是DMA控制数据流的传输,(之后会提到,关于DMA数据传输方向,除了DMA_TO_DEVICE,DMA_FROM_DEVICE之外,还有MEM_TO_MEM之类的,非DMA控制数据传输的情况)那么就应该在开始配置的时候,将此域值设置成0.

2

即source burst size和destination burst size,即前面提到的,当设备发送给DMA控制器一个突发传输信号之后,DMA要传输多少个数据,就由此处设置的值决定。

支持的burst size有1,4,8,。。。,128,256。

前面已经解释过了,具体此处需要设置成多少,要根据你的硬件的datasheet中描述的你的硬件的能力去决定。

Datasheet中写的DMACxBREQ信号线,就是设备的控制器,如果支持DMA,都会有此信号线接出来的,这样,接到DMA的对应的DMACxBREQ引脚上,这样,如果设备控制器,发现当前的条件,满足DMA burst传输,比如FIFO一共36个word,发现FIFO中数据&=32个word了,快满了,就会向DMA控制器PL080,通过这个信号线发送burst read请求,然后PL080就会根据你DMA传输前此处设置的值,比如是32,去你的设备的FIFO中,一次性地读取你之前设置的32个word。

其中具体满足什么条件,才会触发DMA burst读取或写入的请求信号,都是对应你的设备的控制器的datasheet中描述的,也就是你的硬件本身的能力决定的。.

3

即source width和destination width。

具体支持的位宽类型有,byte(8bit),half word(16bit),word(32bit)等。

关于source和destination,解释一下,

比如,你要从你的设备读取数据,即从你设备的FIFO中读取数据到内存某个位置,那么你的设备就是source,此时你的设备的FIFO的位宽,就是source width,比如你FIFO位宽是32bit的,那么此处,根据datasheet,就应该设置为word(32bit)。

4

即source master和destination master,当你的传输由DMA控制时,

比如上面说的DMA_FROM_DEVICE,DMA从设备的FIFO中读取数据到内存中,此时,你要设置一下,你的DMA是用哪一个,即source master是谁。因为,此处的DMA的控制者有2个,可以简单理解为,有两个dma控制器,master1和master2,你具体选哪个master来控制你的DMA传输。关于master的选择,后面的代码分析中,会再次提及。

5

即source increment和destination increment,此处可翻译为,源地址递增和目标地址递增,

关于什么叫递增,为何要递增,可以从最开始提到的,DMA的常见应用情况中来解释,

因为常见的DMA传输,是从某个设备读取数据到某块内存区域,即DMA_FROM_DEVICE,以DMA模式,将数据“From从”你的设备中,读取到某块内存里面;或者将某块内存区域内数据,写入到设备里面,即DMA_TO_DEVICE。

而设备往往都是只有一个DATA寄存器(或是FIFO),此地址是固定不变的,

因此:

对于DMA_FROM_DEVICE,你传输完一个数据了,再传下一个数据的时候,此时你的Source源,还是你的设备的那个寄存器的地址,没有变化,而目标地址,往往要增加一个你的destination width,比如是一个word,32bit,4个字节,即地址要加4了,对应的就要将destination increment设置成1,表示,你的dma每次传输完,目标地址要增加的。

当然具体增加的大小,由你的设置的destination width的值决定。

相应地,如果是DMA_TO_DEVICE,那么就是DMA将数据从内存中写入到你的设备里面,每次传输完后,就是源source地址要增加,source increment要设置为1.

同理,如果是MEM_TO_MEM类型的,内存到内存,就是两者都要设置成1了,因为DMA传输完单个数据后,源地址和目标地址都要改变,要增加相应位宽的大小的。

6

即Protection,保护位,共3bit。

一般很少用到此域,我也没有完全理解,故不多解释,仅简述其义:

  1. Bit0

    0是普通用户模式,1是特权模式

  2. Bit1

    0是non-bufferable,1是bufferable

  3. Bit2

    0是non-cacheable,1是cacheable

7

是否启用计数终止中断(Terminal count interrupt)。

关于此位,之前一直很迷惑,后面终于看懂了。

就是说,对于DMA的传输中的单个LLI来说,当前传输完成了,对应的寄存器中的transfer size域的值,也就是从设置的值,递减到0,也就是此计数递减到0,即结束了,即terminal count,而Terminal Count Interrupt,即传输完了,达到了terminal count时候,发送一个中断,告诉设备此次传输完成了。

如果此位被设置为0,那么传输完当前的LLI,就不会发送这个中断了,设置为1,就发送此中断。

8

此处之所以定义成union类型,就是方便,在设置好了之后,将此32位的值,直接写入对应的32位的寄存器中。