DMA
Directional Memory Access,直接内存访问。是计算机系统中用于快速、大量数据交换的重要技术。
DMA的基本概念
DMA是一种完全由硬件执行数据交换的工作方式。它由DMA控制器控制在存储器和存储器,存储器和外设之间的批量数据传输。
一般:一个DMA有若干条通道,每条通道连接多个外设。这些连接在同一条DMA通道上的多个外设可以分时共享这条DMA通道。
但是在同一时刻,一条DMA通道上只能由一个外设进行DMA数据传输。
传输要素
- 传输源:DMA数据传输的来源。
- 传输目标:DMA数据传输的目标。
- 传输单位数量:DMA传输数据的大小。
- 触发信号:用于触发一次数据传输的动作,可以用来控制数据传输的时机。
传输过程
- DMA请求:CPU初始化DMA控制器,外设(I/O接口)发出DMA请求。
- DMA响应:DMA控制器判断DMA请求的优先级及屏蔽,向总线仲裁器提出总线请求。
- DMA传输:数据以**规定的传输单位(usually byte)**传输,每个单位的数据传输完后,DMA控制器修改地址,并对传送单位的个数进行计数,继而开始下一单位数据的传输。
- DMA结束:当规定数量的DMA数据传输完成后,DMA控制器通知外设(I/O接口)停止传输,并向CPU发送一个信号(产生中断或是事情)报告DMA数据传输操作结束,同时释放总线控制权。
特点
DMA一般用于高速传送成组数据的应用场合。
好处:
-
减轻CPU的负担:
For DMA:控制传输数据的整个过程,既不通过CPU,也不需要CPU干预,都在DMA控制器的控制下完成。
For CPU:在数据传输开始前配置,在数据传输结束后处理外,在整个数据传输的过程进行其他工作。
-
提高数据传输的效率:不需要通过中间变量,而直接将源地址上的数据送到目标地址。
-
减少用户开发的代码量:在DMA传输过程中,没有保护现场、恢复现场之类的工作。硬件实现存储器地址修改,传送单位个数的计数等。
弊端:
- 由于DMA允许外设直接访问内存,从而形成在一段时间内对总线的独占。
- 如果DMA传输的数据量过大,会造成中断延时过长,不适于在硬实时嵌入式系统中使用。
STM32F103のDMA
STM32F103微控制器有2个DMA,每个DMA都有若干的触发通道,每个通道可以管理来自多个外设对存储器的访问请求。
每个外设的DMA请求,可以使用相应的库函数,被独立地开启或关闭。
优先级
在每个DMA中,DMA的仲裁器根据通道请求的优先级来启动外设/存储器的访问;同一时刻,一个DMA只能有一个请求有效。
软件优先级:
DMA每个通道的软件优先级可以在DMA_CCRx
寄存器中设置,有4个等级:
- 最高优先级
- 高优先级
- 中等优先级
- 低优先级
硬件优先级:
在软件优先级相同的情况下使用,较低编号的通道的优先级更高。
传输模式
- 普通模式:DMA传输结束时,DMA通道被自动关闭,进一步DMA请求不被响应。
- 循环模式:用于处理一个环形的缓冲区,每轮传输结束时数据传输的配置会自动地更新为初始状态,DMA传输会不断地进行。
主要特点
- DMA可实现存储器与存储器、外设与存储器、存储器与外设之间的传输;闪存、SRAM、外设的SRAM、APB1、APB2和AHB上的外设均可作为访问的源和目标。
- 具有12个独立的可配置的通道/请求:DMA1有7个通道,DMA2有5个通道。当在存储器之间使用DMA进行数据传输时,可以使用任意的DMA通道。
- 每个通道既有直接连接专用的硬件DMA请求,同时也支持软件触发,这些功能可以通过软件来配置。
- 在同一个DMA上,多个通道请求的优先级可以通过软件编程设置,当软件优先级设置相等时由硬件决定优先级高低。(
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
) - 每个通道都有3个时间标志:DMA半传输、DMA传输完成和DMA传输出错,这3个事件标志逻辑或成为一个单独的中断请求。
- DMA数据传输数量(max=65535)可编程。
- 支持循环的DMA缓冲区管理,避免DMA传输到达缓冲区结尾时所产生的中断。
相关库函数
void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx)
:将DMAy的通道x的寄存器恢复为复位启动时的default值。
- 输入参数
DMAy_Channelx
:DMAy的通道x- y:用来指定某个DMA,是DMA1或DMA2。
- x:用于指定DMA的某个通道。
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx,DMA_InitTypeDef* DMA_InitStruct)
:根据DMA_InitStruct中指定的参数初始化指定DMA通道的寄存器。
-
输入参数
DMA_InitTypeDef* DMA_InitStruct
:指向结构体DMA_InitTypeDef
的指针,包含了DMAy通道x的配置信息。typedef struct{ uint32_t DMA_PeripheralBaseAddr;//为通道设置外设基地址。 uint32_t DMA_MemoryBaseAddr;//设置内存基地址。 uint32_t DMA_DIR;//指定外设是作为DMA数据传输的目的地还是来源。DMA_DIR_PeripheralDST/SRC uint32_t DMA_BufferSize;//指定通道DMA缓存的大小,单位是数据单位。 uint32_t DMA_PeripheralInc;//设定外设地址寄存器是否递增。Enable/Disable uint32_t DMA_MemoryInc;//设定内存地址寄存器是否递增。Enable/Disable uint32_t DMA_PeripheralDataSize;//设定外设数据宽度。Byte/HalfWord/Word uint32_t DMA_MemoryDataSize;//设定内存数据宽度。Byte/HalfWord/Word uint32_t DMA_Mode;//工作模式是正常缓存还是循环缓存。Normal/Circular uint32_t DMA_Priority;//VeryHigh/High/Medium/Low uint32_t DMA_M2M;//是否将DMAy的通道x设置为内存到内存传输。Enable/Disable }DMA_InitTypeDef;
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx)
:返回当前指定DMA通道剩余的待传输数据数目。
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx,FunctionalStateNewState)
:使能or禁止指定DMA通道。
FunctionalStateNewState:Enable/Disable
通道新状态。
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG)
:查询指定DMA通道的标志位状态(是否置位),但不检查该中断是否被屏蔽。因此当该位置位时,通道的指定中断并不一定得到响应。
- 返回值:
- SET
- RESET
void DMA_ClearFlag(uint32_t DMAy_FLAG)
:清除指定DMA通道的待处理标志位。
void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx,uint32_t DMAy_IT,FunctionalStateNewState)
:使能or禁止指定DMA通道中断。
- 输入参数
DMA_IT
:DMA_IT_TC
:传输完成中断。DMA_IT_HT
:传输过半中断。DMA_IT_TE
:传输错误中断。
ITStatus DMA_GetITConfig(uint32_t DMAy_IT)
:查询指定DMAy的通道x的中断的状态,中断是否发生,指定标志位的状态并检测该中断是否被屏蔽。
void DMA_ClearITPendingBit(uint32_t DMAy_IT)
:清除指定DMAy的通道x的中断的挂起位。
_GetITConfig(uint32_t DMAy_IT)`:查询指定DMAy的通道x的中断的状态,中断是否发生,指定标志位的状态并检测该中断是否被屏蔽。
void DMA_ClearITPendingBit(uint32_t DMAy_IT)
:清除指定DMAy的通道x的中断的挂起位。