直接内存访问控制器DMA
简介
-
直接存储器访问(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输
-
无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作
-
两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道)
-
每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权
DMA主要特性
-
12个独立的可配置的通道(请求):DMA1有7个通道,DMA2有5个通道
-
每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置
-
在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推)
-
独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐
-
支持循环的缓冲器管理
-
每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求
-
存储器和存储器间的传输
-
外设和存储器、存储器和外设之间的传输
-
闪存、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和目标
-
可编程的数据传输数目:最大为65535
DMA框图
![](https://img-blog.csdnimg.cn/6eedb6a610324820a5e9a719830bf7ce.png)
DMA处理
在发生一个事件后,外设向DMA控制器发送一个请求信号,DMA控制器根据通道的优先权处理请求。当DMA控制器开始访问发出请求的外设时,DMA控制器立即发送给它一个应答信号。
当从DMA控制器得到应答信号时,外设立即释放它的请求。一旦外设释放了这个请求,DMA控制器同时撤销应答信号。如果有更多的请求时,外设可以启动下一个周期。
每执行一次DMA传输,DMA_CNDTRx寄存器执行递减操作,该寄存器包含未完成的传输数目
仲裁器
仲裁器根据通道请求的优先级来启动外设/存储器的访问
优先权管理分2个阶段:
● 软件:每个通道的优先权可以在DMA_CCRx寄存器中设置,有4个等级:
─ 最高优先级
─ 高优先级
─ 中等优先级
─ 低优先级
● 硬件:如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优先权
举个例子,通道2优先于通道4
注意: DMA1控制器拥有高于DMA2控制器的优先级
DMA 通道
DMA传输的数据量是可编程的,最大达到65535,在每次传输后递减
当通道配置为非循环模式时,传输结束后(即传输计数变为0)将不再产生DMA操作。要开始新的DMA传输,需要在关闭DMA通道的情况下,在DMA_CNDTRx寄存器中重新写入传输数目。
在循环模式下,最后一次传输结束时,DMA_CNDTRx寄存器的内容会自动地被重新加载为其初始数值,内部的当前外设/存储器地址寄存器也被重新加载为DMA_CPARx/DMA_CMARx寄存器设定的初始基地址
指针增量
外设和存储器的指针在每次传输后可以有选择地完成自动增量。
当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值,增量值取决与所选的数据宽度为1、2或4
循环模式
循环模式用于处理循环缓冲区和连续的数据传输(如ADC的扫描模式),在DMA_CCRx寄存器中的CIRC位用于开启这一功能
当启动了循环模式,数据传输的数目变为0时,将会自动地被恢复成配置通道时设置的初值,DMA操作将会继续进行
存储器到存储器模式
DMA通道的操作可以在没有外设请求的情况下进行,这种操作就是存储器到存储器模式
当设置了DMA_CCRx寄存器中的MEM2MEM位之后,在软件设置了DMA_CCRx寄存器中的EN位启动DMA通道时,DMA传输将马上开始
当DMA_CNDTRx寄存器变为0时,DMA传输结束,存储器到存储器模式不能与循环模式同时使用
DMA1请求映像
![](https://img-blog.csdnimg.cn/acbefaca1c864077973a7789b5e7269a.png)
各个通道的DMA1请求一览
![](https://img-blog.csdnimg.cn/ba3dc4da816442ff9e23ab1318c2f173.png)
DMA2控制器
![](https://img-blog.csdnimg.cn/db651ec5dea742eab1adbed67f8fa69a.png)
各个通道的DMA2请求一览
![](https://img-blog.csdnimg.cn/29e5ad144cd34662902070601163147d.png)
DMA HAL库函数介绍
stm32f1xx_hal_dma.c
//DMA初始化和去初始化函数
HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma);
HAL_StatusTypeDef HAL_DMA_DeInit (DMA_HandleTypeDef *hdma);
//DMA启动
HAL_StatusTypeDef HAL_DMA_Start (DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);
//DMA启动并开启DMA中断
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);
//停止DMA及关闭中断
HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma);
HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *hdma);
//DMA传输状态轮询阻塞查询
HAL_StatusTypeDef HAL_DMA_PollForTransfer(DMA_HandleTypeDef *hdma, uint32_t CompleteLevel, uint32_t Timeout);
//DMA中断服务函数
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma);
//DMA回调函数注册
HAL_StatusTypeDef HAL_DMA_RegisterCallback(DMA_HandleTypeDef *hdma,HAL_DMA_CallbackIDTypeDef CallbackID, void (* pCallback)( DMA_HandleTypeDef * _hdma));
//DMA回调函数注销
HAL_StatusTypeDef HAL_DMA_UnRegisterCallback(DMA_HandleTypeDef *hdma, HAL_DMA_CallbackIDTypeDef CallbackID);
stm32f1xx_hal_dma.h
typedef struct
{
uint32_t Direction; /*!< DMA传输模式
这个参数可查 @ref DMA_Data_transfer_direction */
uint32_t PeriphInc; /*!< 外设地址增量
这个参数可查 @ref DMA_Peripheral_incremented_mode */
uint32_t MemInc; /*!< 内存地址增量
这个参数可查 @ref DMA_Memory_incremented_mode */
uint32_t PeriphDataAlignment; /*!< 外设数据对齐
这个参数可查 @ref DMA_Peripheral_data_size */
uint32_t MemDataAlignment; /*!< 内存数据对齐
这个参数可查 @ref DMA_Memory_data_size */
uint32_t Mode; /*!< DMA工作模式
这个参数可查 @ref DMA_mode
内存 TO 内存时禁止使用循环模式 */
uint32_t Priority; /*!< 设置通道优先级
这个参数可查 @ref DMA_Priority_level */
} DMA_InitTypeDef;//DMA初始化结构体
typedef struct __DMA_HandleTypeDef
{
DMA_Channel_TypeDef *Instance; /*!< 外设基地址 */
DMA_InitTypeDef Init; /*!< DMA 初始化结构体 */
HAL_LockTypeDef Lock; /*!< DMA 锁定对象 */
HAL_DMA_StateTypeDef State; /*!< DMA 传输状态 */
void *Parent; /*!< 父对象状态 */
void (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA 传输完成回调 */
void (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA 传输过半回调 */
void (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA 传输错误回调 */
void (* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA 传输中止回调 */
__IO uint32_t ErrorCode; /*!< DMA Error code */
DMA_TypeDef *DmaBaseAddress; /*!< DMA Channel Base Address */
uint32_t ChannelIndex; /*!< DMA Channel Index */
} DMA_HandleTypeDef;//DMA句柄结构体
stm32f1xx_hal_dma_ex.h
此文件包含一些标志位查询及清除宏定义
DMA通道配置完成后,通过下列宏链接至外设通道
//DMA通道链接至外设句柄
#define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD__, __DMA_HANDLE__);
Author :HU&DA