DMA
参考野火《STM32库开发实战》 P195-P215 “DMA—直接存储区访问 ”章节讲解。
DMA FIFO
每个数据流都独立拥有四级32位FIFO。DMA传输具有FIFO模式和直接传输模式。
FIFO用于源数据传输到目标地址之间临时存储这些数据。
DMA传输模式
DMA2 支持全部三种传输模式,而 DMA1 只有外设到存储器和存储器到外设两种模式。
DMA1 的存储区端口相比 DMA2 的要减少 AHB2 外设的访问权,同时 DMA1 外设端口是没有连接至总线矩阵的,只有连接到 APB1 外设,所以 DMA1 不能实现存储器到存储器传输。
DMA 流控制器
流控制器主要涉及到一个控制 DMA 传输停止问题。 DMA 传输在 DMA_SxCR 寄存器的 EN 位被置 1 后就进入准备传输状态,如果有外设请求 DMA 传输就可以进行数据传输。
很多情况下,我们明确知道传输数据的数目,比如要传 1000 个或者 2000 个数据,这样我们就可以在传输之前设置 DMA_SxNDTR 寄存器为要传输数目值, DMA 控制器在传输完 这么多数目数据后就可以控制 DMA 停止传输。
DMA 数据流 x 数据项数 DMA_SxNDTR(x 为 0~7)寄存器用来记录当前仍需要传输数目,它是一个 16 位数据有效寄存器,即最大值为 65535,这个值在程序设计是非常有用也是需要注意的地方。我们在编程时一般都会明确指定一个传输数量,在完成一次数目传输
后 DMA_SxNDTR 计数值就会自减,当达到零时就说明传输完成。
如果某些情况下在传输之前我们无法确定数据的数目,那 DMA 就无法自动控制传输停止了,此时需要外设通过硬件通信向 DMA 控制器发送停止传输信号。这里有一个大前提就是外设必须是可以发出这个停止传输信号,只有 SDIO 才有这个功能,其他外设不具备此功能。
理解1
看库函数中
DMAy_Channelx->CNDTR = DMA_InitStruct->DMA_BufferSize;
而CNDTR即数据传输数量 (Number of data to transfer)
数据传输数量为0至65535。这个寄存器只能在通道不工作(DMA_CCRx的EN=0)时写入。通道开启后该寄存器变为只读,指示剩余的待传输字节数目。寄存器内容在每次DMA传输后递减。
数据传输结束后,寄存器的内容或者变为0;或者当该通道配置为自动重加载模式时,寄存器的内容将被自动重新加载为之前配置时的数值。
当寄存器的内容为0时,无论通道是否开启,都不会发生任何数据传输。
理解2
这个DMA_BufferSize 就是要传输的次数。
这个并不是指buf的字节大小,而是指DMA的传输次数,一次传输可以是:1字节,2字节,4字节。
理解3
那为啥取名叫buffer 呢,我猜是为了和DMA_MemoryInc_Enable配合。虽然传输计数是减少的,但是内存地址是增长的。在声明DMA_MemoryBaseAddr时候,其实DMA的就指向(是指向,不是开辟!)一个大小为DMA_BufferSize的数组,数组的开始地址为DMA_MemoryBaseAddr。这个数组就是缓冲区。
每次ADC采样后,就通过DMA把数据放在内存中, 从DMA_MemoryBaseAddr+0地址开始放, 直到DMA_MemoryBaseAddr+DMA_BufferSize-1,此时CNDTR变成0,传输结束。
理解4
如果你有32字节数据:
datasize=1 ==> buffersize = 32
datasize=2 ==> buffersize = 16
datasize=4 ==> buffersize = 8
这个理解,说明了buffer_size设置时需要注意的事项,
1. 外设数据宽度、内存数据宽度
2. 我们设置了外部存储区的大小
**外设:DCMI_DR_ADDRESS
内存:FSMC_LCD_ADDRESS #液晶屏地址或数组首地址**
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; #外设数据宽度为32位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; #内存数据宽度为16位
上述此情况下,假设传输2个字节,则buffer_size = 16/32 = 0.5 假设传输32个字节,则buffer_size = 32/2*0.5=8
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; #外设数据宽度为16位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; #内存数据宽度为32位
上述此情况下,假设传输4个字节,则buffer_size = 32/16= 2
假设传输32个字节,则buffer_size = 32/4*2=16
DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_HalfWord; #外设数据宽度为16
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; #内存数据宽度为16位
上述此情况下,假设传输2个字节,则buffer_size = 16/16= 1
假设传输32个字节,则buffer_size = 32/2*1=16
传输类型
DMA传输类型有单次(single)传输和突发(Burst)传输。
burst:
dma实际上是一次一次的申请总线,把要传的数据总量分成一个一个小的数据块。比如要传64个字节,那么dma内部可能分为2次,一次传 64/2=32个字节,这个2(a)次呢,就叫做burst。这个burst是可以设置的。这32个字节又可以分为32位 * 8或者16位*16来传输。
突发传输与 FIFO 密切相关,突发传输需要结合 FIFO 使用,具体要求 FIFO 阈值一定要是内存突发传输数据量的整数倍。 FIFO 阈值选择和存储器突发大小必须配合使用,
直接模式
默认情况下, DMA 工作在直接模式,不使能 FIFO 阈值级别。
直接模式在每个外设请求都立即启动对存储器传输的单次传输。直接模式要求源地址和目标地址的数据宽度必须一致,所以只有 PSIZE 控制,而 MSIZE 值被忽略。突发传输是基于 FIFO 的所以直接模式不被支持。另外直接模式不能用于存储器到存储器传输。
在直接模式下,如果 DMA 配置为存储器到外设传输那 DMA 会见一个数据存放在FIFO 内,如果外设启动 DMA 传输请求就可以马上将数据传输过去
上一篇:stm32 DMA初始化选项研究
下一篇:STM32F4 UART DMA初始化
推荐阅读最新更新时间:2024-03-16 16:21