DMA
一、F28379D的DMA简介
- 具有六个DMA通道,每个通道都有各自独立的PIE中断
- 每个DMA通道都能够被各种外设触发源触发
- 16-bit模式和32-bit模式(SPI为16-bit)
- 吞吐量:传输一个word需要三个周期
- 每个CPU都有各自的DMA控制器
二、DMA Data Path
三、DMA触发源的选择(寄存器手册P625)
触发的逻辑图:
Table5-1由于太长,未列完全,可翻阅寄存器手册。
四、DMA的传输方式和传输模式
在DMA传输时,一共有两个嵌套的循环,在一次DMA传输结束后,DMA传输的数据量为:(BURST_SIZE+1)*(TRANSFER_SIZE+1)
-
Burst Loop(内循环)
BURST_SIZE寄存器可以设置每次Burst传输words的数量,一次Burst传输最大可以传输32个16-bit words,而MODE.DATASIZE能够改变DMA通道传输的是16-bit还是32bit。每次Burst传输完成后,其地址变换为:
SRC_ADDR_ACTIVE = SRC_ADDR_ACTIVE + SRC_BURST_STEP
DST_ADDR_ACTIVE = DST_ADDR_ACTIVE + DST_BURST_STEP -
Transfer Loop(外循环)
TRANSFER_SIZE寄存器可以配置Transfer传输的burst数,TRANSFER_SIZE寄存器是16-bit的寄存器,因此可以传输大量数据。每次Transfer传输完成后,其地址变化为(前提是SRC_WRAP_SIZE要大于TRANSFER_SIZE):
SRC_ADDR_ACTIVE = SRC_ADDR_ACTIVE + SRC_TRANSFER_STEP
DST_ADDR_ACTIVE = DST_ADDR_ACTIVE + DST_TRANSFER_STEP
OneShot Mode(默认关闭)
当OneShot Mode关闭时,每次触发后只传输一次burst,在此次burst传输完成后,DMA控制器状态机直接切换到下一个优先级正在等待的DMA通道,即使本通道传输完成后又一次被触发。该模式能够防止任何通道独自占用DMA总线。
当OneShot Mode打开时,每次触发后会将一个通道的所有bursts传输完成,在该模式下,很容易造成一个通道占用DMA的大部分带宽。
Continuos Mode(默认关闭)
当Continuos Mode关闭时, 当DMA完成所有通道的所有bursts之后,DMA会自动关闭,如果需要再次传输,需要重新使能。
当该模式打开时,会循环传输数据,不需要再次重新使能。
五、DMA的配置
在该示例中,是将在RAMGS0处的数据DMA传送至在RAMGS1处。即Mem-To-Mem的传送方式。使用的是软件触发。
-
首先是配置DMA中断:
EALLOW; PieVectTable.DMA_CH1_INT = &dma_finish_isr; EDIS; IER |= M_INT7; PieCtrlRegs.PIECTRL.bit.ENPIE = 1; // Enable the PIE block PieCtrlRegs.PIEIER7.bit.INTx1 = 1; //查找PIE Map映射即可知道PIE组7,第一个中断就是DMAch1中断 EINT; ERTM;
-
配置DMA
#pragma DATA_SECTION(g_ulSrcBuf0, "ramgs0"); #pragma DATA_SECTION(g_ulDstBuf1, "ramgs1"); #define MEM_BUFFER_SIZE 1024 Uint32 g_ulSrcBuf0[MEM_BUFFER_SIZE]; Uint32 g_ulDstBuf1[MEM_BUFFER_SIZE]; volatile Uint32 *DMADest; volatile Uint32 *DMASource; void DMA_Init() { // Initialize DMA DMAInitialize(); // Configure DMA Channel 1 (16-bit datasize) DMADest = g_ulDstBuf1; DMASource = (volatile Uint32 *)g_ulSrcBuf0; DMACH1AddrConfig32bit(DMADest,DMASource);//配置目标地址和源地址 /***************************16-bit word 传输配置**********************************/ //Will set up to use 16-bit datasize, pointers are based on 16-bit words //每次burst配置成传输32个16bit word,每个word传输完成后,源地址和目标地址都递增1 DMACH1BurstConfig(31,1,1); //每次Teransfer传输MEM_BUFFER_SIZE*2/32个burst,每次burst传输完成后源地址和目标地址递增1 DMACH1TransferConfig((MEM_BUFFER_SIZE*2/32-1),1,1); DMACH1WrapConfig(0xFFFF,0,0xFFFF,0); //第一个参数是外部触发源,由于该示例是软件触发,因此为0x0,其他的选择可参考寄存器手册P625 //其他参数定义,可参考库函数里面的介绍 DMACH1ModeConfig(0x0,PERINT_ENABLE,ONESHOT_ENABLE, CONT_DISABLE,SYNC_DISABLE,SYNC_SRC, OVRFLOW_DISABLE,SIXTEEN_BIT,CHINT_END,CHINT_ENABLE); /***************************32-bit word 传输配置**********************************/ DMACH1BurstConfig(31,2,2); //每次Teransfer传输MEM_BUFFER_SIZE*2/32个burst,每次burst传输完成后源地址和目标地址递增2 DMACH1TransferConfig((MEM_BUFFER_SIZE*2/32-1),2,2); DMACH1WrapConfig(0xFFFF,0,0xFFFF,0); //第一个参数是外部触发源,由于该示例是软件触发,因此为0x0,其他的选择可参考寄存器手册P625 //其他参数定义,可参考库函数里面的介绍 DMACH1ModeConfig(0x0,PERINT_ENABLE,ONESHOT_ENABLE, CONT_DISABLE,SYNC_DISABLE,SYNC_SRC, OVRFLOW_DISABLE,THIRTYTWO_BIT,CHINT_END,CHINT_ENABLE); }
-
在CMD文件中添加相关定义
//在CMD的section中添加如下定义 ramgs0 : > RAMGS0, PAGE = 1 ramgs1 : > RAMGS1, PAGE = 1
-
启动DMA
//打开DMA通道1传输 StartDMACH1(); //进行软件触发 EALLOW; DmaRegs.CH1.CONTROL.bit.PERINTFRC = 1; EDIS;
-
DMA传输完成中断函数
__interrupt void dma_finish_isr(void) { PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; //User Code }
注意:
在定义数组时,必须要添加下面这两行
#pragma DATA_SECTION(g_ulSrcBuf0, “ramgs0”);
#pragma DATA_SECTION(g_ulDstBuf1, “ramgs1”);这是为了将g_ulSrcBuf0和g_ulDstBuf1分别定义在ramgs0和ramgs1处,不然的话,可能会将数组自动定义在其他区域,而由上面的第一张图的DMA数据传输路径可知,只有GS0-GS15RAMs和DMA总线相连,定义在其他区域,无法进行DMA传输
在软件触发传输完成时,若要再次进行传输,必须再次打开DMA通道,同时再次软件触发,不然无法完成传输。
在该示例中,是定义了两个uint32_t的数组,容量为1024,在传输数据为16-bit word时,如果每次burst传输的数量设置为32,则每次Transfer传输的burst次数应该设置为1024*2/32次,且地址指针都因该递增1,这样才能全部正常传输完成。但在32-bit 传输下,若想要全部传输完成,每次burst传输的数量和传输burst的次数与16-bit一样,只是地址变成递增2而已。有点迷惑,个人猜想,在手册里介绍每次burst传输的最大数据量为32*16-bit word,可能在32-bit模式下,每次burst传输的时16个32bit的数据。