20、DMA----释放CPU压力,加快传输
1、DMA介绍
DMA,全称为:Direct Memory Access,即直接存储器访问。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,能使CPU的效率大为提高。
STM32F103内部有2个DMA控制器(DMA2仅存大容量产品中),DMA1有7个通道,DMA2有5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求,一个仲裁器来协调各个DMA请求的优先权。
DMA有以下特性
- 每个通道都直接连接专用的硬件DMA请求,每个通道都支持软件触发。通过软件来配置。
- 优先权可以通过软件编程设置,有四个等级:很高、高、中、低,优先权相同时由硬件决定。
- 独立源和目标数据区的传输宽度,可以根据字节、半字、全字,模拟打包和拆包过程。源和目标地址必须按照数据传输宽度对齐。
- 支持循环的缓冲器管理。
- 每个通道有3个事件标志:DMA半传输、DMA传输完成、DMA传输出错,3个事件标志逻辑或成为一个独立中断请求。
- 存储器和存储器间的传输。
- 外设和存储器,存储器和外设的传输。
- 闪存、SRAM、外设SRAM、APB1、APB2、AHB外设都可以作为访问的源和目标。
- 最大传输数目:65536
1.1、DMA框图
STM32F103ZET6有两个DMA控制器,DMA1和DMA2。
- ①DMA请求: 外设想要通过DMA来传输数据,必须先给DMA控制器发送DMA请求,DMA收到请求信号后,控制器会给外设一个应答信号,当外设应答后且DMA控制器收到应答信号后,就会启动DMA传输,直到传输完毕。
- ②通道:DMA具有12个独立可编程的通道,其中DMA1有7个通道,DMA2有5个通道,每个通道对应不同的外设的DMA请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。
- ③仲裁器:当发生多个DMA通道请求时,就会由仲裁器管理,仲裁器管理DMA通道请求分为两个阶段。第一阶段属于软件阶段,可以在DMA_CCRx寄存器中设置,有4个等级:非常高,高,中和低四个优先级。第二阶段属于硬件阶段,两个或以上的DMA通道请求设置的优先级一样,则他们优先级取决于通道编号,编号越低优先权越高,比如通道0高于通道1。DMA1控制器拥有高于DMA2控制器的优先级。
1.2、DMA请求映射表
2、DMA函数
DMA_HandleTypeDef结构体类型指针变量:
typedef struct __DMA_HandleTypeDef {void *Instance; /* 寄存器基地址 */DMA_InitTypeDef Init; /* DAM 通信参数 */HAL_LockTypeDef Lock; /* DMA 锁对象 */ __IO HAL_DMA_StateTypeDef State; /* DMA 传输状态 */ void *Parent; /* 父对象状态,HAL库处理的中间变量 */ void(*XferCpltCallback)( struct __DMA_HandleTypeDef *hdma); /*DMA传输完成回调*/ void(* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma);/* DMA一半传输完成回调 */void(* XferM1CpltCallback)( struct __DMA_HandleTypeDef * hdma); /* DMA传输完整的Memory1回调 */void(* XferM1HalfCpltCallback)( struct __DMA_HandleTypeDef * hdma);/* DMA传输半完全内存回调 */void(* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma);/*DMA传输错误回调*/void(* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma);/* DMA传输中止回调 */__IO uint32_t ErrorCode; /* DMA存取错误代码 */DMA_TypeDef *DmaBaseAddress; /* DMA通道基地址 */uint32_t ChannelIndex; /* DMA通道索引 */ }DMA_HandleTypeDef;
- Instance:是用来设置寄存器基地址,如果设置的对象是串口1的发送,串口1的DMA传输需要用到的是DMA1的通道4,即DMA1_Channel4。
- Parent:是HAL库处理中间变量,用来指向DMA通道外设句柄。
- XferCpltCallback:传输完成回调函数入口地址
- XferHalfCpltCallback:半传输完成回调函数入口地址
- XferM1CpltCallback:Memory1传输完成回调函数入口地址
- XferErrorCallback:传输错误回调函数入口地址
- Init:它是DMA_InitTypeDef结构体类型变量
typedef struct { uint32_t Direction; /* 传输方向,例如存储器到外设DMA_MEMORY_TO_PERIPH */ uint32_t PeriphInc; /* 外设(非)增量模式,非增量模式DMA_PINC_DISABLE */ uint32_t MemInc; /* 存储器(非)增量模式,增量模式DMA_MINC_ENABLE */ uint32_t PeriphDataAlignment; /* 外设数据大小:8/16/32位 */ uint32_t MemDataAlignment; /* 存储器数据大小:8/16/32位 */ uint32_t Mode; /* 模式:循环模式/普通模式 */ uint32_t Priority; /* DMA优先级:低/中/高/非常高 */ }DMA_InitTypeDef;
- HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma);DMA的初始化函数
- __HAL_RCC_DMA1_CLK_ENABLE(); /* DMA1时钟使能 */ __HAL_RCC_DMA2_CLK_ENABLE(); /* DMA2时钟使能 */
- __HAL_LINKDMA(&g_uart1_handler, hdmatx, g_dma_handle);连接DMA和外设句柄。
- 外设的DMA发送、启动传输函数。
- __HAL_DMA_GET_FLAG(&g_dma_handle, DMA_FLAG_TC4);查询DMA传输通道的状态
- __HAL_DMA_GET_COUNTER(&g_dma_handle);获取当前传输剩余数据量
- __HAL_DMA_SET_COUNTER (&g_dma_handle, 1000);设置对应的DMA数据流传输的数据量大小
- DMA中断函数
- DMA中断对于每个通道都有一个中断服务函数
- HAL库提供了通用DMA中断处理函数HAL_DMA_IRQHandler, 在该函数内部,会对DMA传输状态进行分析,然后调用相应的中断处理回调函数:
- 发送完成回调函数
- 发送一般回调函数
- 接收完成回调函数
- 接收一半回调函数
- 传输错误回调函数