STM32F407 DMA配置分析

这几天调试代码,认真看了F407的DMA设置。
一些细节记录在此。

常用配置

一个DMA的通常配置如下:

DMA_InitStructure.DMA_Channel = DMA_Channel_0;  
    DMA_InitStructure.DMA_PeripheralBaseAddr = MemoryAddr;   
    DMA_InitStructure.DMA_Memory0BaseAddr = FSMC_LCD_ADDRESS;
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;
    DMA_InitStructure.DMA_BufferSize = len*2;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    /* DMA2 IRQ channel Configuration */
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);

DMA_Channel

DMA通道,407有两个DMA,每个DMA的通道和stream在参考手册中都有。上面我们配置为通道0。
DMA1
DMA2

DMA_PeripheralBaseAddr

外设地址,不一定是真正的外设地址。
如果你是外设到内存,或者内存到外设,这里就是一个外设的地址。
这里的外设就是前面表格中说的片上设备,SPI、串口、SDIO等等。
如果你是memory到memory,那这个就是RAM地址或者FLASH地址,或外部RAM SRAM等地址。

DMA_Memory0BaseAddr

memory地址,为什么带个0呢?因为某种情况下,可以用双缓冲。在做I2S播放音乐的时候我们就用双缓冲。
其他情况通常都是单缓冲。

DMA_DIR

DMA方向,有3种:

DMA_DIR_PeripheralToMemory
DMA_DIR_MemoryToPeripheral
DMA_DIR_MemoryToMemory

好了,到这里就有点疑问了,配合前面设置的两个地址来看,
如果是P-M,也就是perpheral to memory,那肯定就是DMA_PeripheralBaseAddr取数据,发到DMA_Memory0BaseAddr。
如果是M-P,那就是反着来。
那M-M呢?我没找到文档哪里写,实测,是从DMA_PeripheralBaseAddr取数据,发到DMA_Memory0BaseAddr。
上面的配置就是我将内存RAM中的数据发送到FSMC上,FSMC上接的是彩屏。

只有 DMA2 控制器能够执行存储器到存储器的传输。

DMA_BufferSize

准确的说应该是传输长度。
如果配置不准确,传输数据就或出错,或者是移植在DMA传输,不结束。
这个长度,跟后面配置字长有关:
如果DMA_PeripheralDataSize跟DMA_MemoryDataSize相等,那就没话说了,该是多长就是多长。
如果两者不相等,DMA_BufferSize是指DMA_PeripheralDataSize数据宽度的数据数。
假如DMA_PeripheralDataSize是半字,DMA_MemoryDataSize是BYTE,
DMA_BufferSize=10,就表示DMA要传输10个半字,20个BYTE。
具体看《STM32F4xx中文参考手册.pdf》

9.3.10 可编程数据宽度、封装/解封、字节序

DMA_PeripheralInc

DMA_MemoryInc

地址是否自加,外设地址通常不自加。
上面例子是将RAM数据发送到彩屏,DMA_PeripheralBaseAddr地址是内存地址,自加。DMA_Memory0BaseAddr 是彩屏地址,不自加。

DMA_PeripheralDataSize

DMA_MemoryDataSize

字长设置,当我把两者都设置为halfword时,发现如果传输奇数个半字,会一直处于发送,DMA不会停止。
因此把DMA_PeripheralDataSize设置为byte,那么传输的字节数就是2*实际要传输的半字,
那么肯定是2的倍数,就能正常。关于这个在文档中也有提及,只是还看不太明白。

DMA_Mode

是否循环。
摄像头就用循环,只要配置一次,启动DMA后,一直持续不断的更新数据到屏幕上。
需要注意的是:
使用存储器到存储器模式时,不允许循环模式和直接模式。

DMA_Priority

优先级

DMA_FIFOMode

是否使用FIFO,也就是是否使用直接模式。
但是,我们的配置是disable,那么就是直接模式?存储器到存储器不是不允许直接模式吗?

DMA_MemoryBurst

DMA_PeripheralBurst

9.3.11 单次传输和突发传输
“为确保数据一致性,形成突发的每一组传输都不可分割:在突发传输序列期间, AHB 传输会
锁定,并且 AHB 总线矩阵的仲裁器不解除对 DMA 主总线的授权。”
从文档看来,是保证数据完整性的,也就是说不要传到一半被别的设备打断造成数据错误?

DMA_Init(DMA2_Stream0, &DMA_InitStructure);

执行配置,第一个参数要选对Stream0,用哪个stream,根据表格选。

对DMAD的认识如上,请指教。

留下评论