1 DMA介绍
DMA(Direct Memory Accesse,直接内存访问)是一种数据通信技术
允许数据无需借助CPU,直接开辟内存和外设通道进行数据传输
提高数据传输效率,减负CPU
外设发送请求,DMA收到请求给外设返回ack应答信号
外设收到ack后释放请求,启动DMA数据传输,直至传输结束
每个外设有一个特定的通道供数据传输
同时多个外设使用同一个通道时由仲裁器决定优先级
多个请求进入DMA只有一个请求有效
2 DMA相关HAL库驱动介绍
2.0 DMA_HandleTypeDef
typedef struct __DMA_HandleTypeDef
{
DMA_Channel_TypeDef *Instance; //DMA通道
DMA_InitTypeDef Init; /*!< DMA communication parameters */
HAL_LockTypeDef Lock; /*!< DMA locking object */
HAL_DMA_StateTypeDef State; /*!< DMA transfer state */
void *Parent; /*!< Parent object state */
void (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA transfer complete callback */
void (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA Half transfer complete callback */
void (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA transfer error callback */
void (* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA transfer abort callback */
__IO uint32_t ErrorCode; /*!< DMA Error code */
DMA_TypeDef *DmaBaseAddress; /*!< DMA Channel Base Address */
uint32_t ChannelIndex; /*!< DMA Channel Index */
} DMA_HandleTypeDef;
2.1 __HAL_RCC_DMAx_CLK_ENABLE()
用于使能DMA1控制器的时钟,其中 x
代表想要使能的DMA控制器的编号
__HAL_RCC_DMA1_CLK_ENABLE();
2.2 HAL_DMA_Init()
函数定义 HAL_StatusTypeDef HAL_DMA_Init (DMA_HandleTypeDef * hdma)
函数描述 根据DMA_InitTypeDef中指定的参数初始化DMA,并创建关联的句柄。
参数 hdma:指向包含指定DMA通道的配置信息的指针。
返回值 HAL status
DMA_HandleTypeDef g_dma_handle; //创建DMA句柄
g_dma_handle.Instance = DMA1_Channel4 ; //DMA传输使用的通道
g_dma_handle.Init.Direction = DMA_MEMORY_TO_PERIPH; //模式,内存到外设
g_dma_handle.Init.PeriphInc = DMA_PINC_DISABLE; //外设非增量模式
//递增模式会使得DMA在传输数据时会自动递增寄存器地址,用于处理连续数据块
g_dma_handle.Init.MemInc = DMA_MINC_ENABLE; //存储器增量模式
//与外设增量模式差不多,只不过这个应用于内存
g_dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //数据对齐方式:一字节
//类似于缓存,收集到一字节的数据后DMA才进行数据传输
g_dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; //存储器数据长度:一字节
g_dma_handle.Init.Mode = DMA_NORMAL; //DMA模式:正常模式
//循环模式会在完成一次传输后,自动重新开始一次新的传输,继续传输之前设置的数据
//这种循环的过程可以持续进行,直到手动停止DMA或者中止传输
g_dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM; //中等优先级
HAL_DMA_Init(&g_dma_handle);
2.3 __HAL_LINKDMA()
宏描述 用于将外设和 DMA 通道关联起来,以便在使用 DMA 进行数据传输时,DMA 控制器知道要使用哪个 DMA 通道来管理传输
__HAL_LINKDMA(&g_uart1_handle, hdmatx, g_dma_handle);
//hdmatx是UART句柄中一个成员,是UART1的DMA发送通道
2.4 HAL_UART_Transmit_DMA()
函数定义 HAL_StatusTypeDef HAL_UART_Transmit_DMA (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)
函数描述 以非阻塞模式发送数据
参数 huart:指向UART_HandleTypeDef结构体的指针,该结构体包含指定UART
模块的配置信息。
pData: 指向数据缓冲区指针
Size: 要发送的数据量
返回值 HAL status
HAL_UART_Transmit_DMA(&g_uart1_handle, g_sendbuf, SEND_BUF_SIZE);
2.6 __HAL_DMA_GET_FLAG()
宏定义 __HAL_DMA_GET_FLAG(&hdma, DMA_FLAG_XYZ)
宏描述 用于检查特定DMA通道的标志位是否被置位,以确定是否发生了某个特定的事件,比如传输完成
宏参数 &hdma:DMA_HandleTypeDef
结构体变量,DMA句柄
DMA_FLAG_XYZ:要检查的标志位
if ( __HAL_DMA_GET_FLAG(&g_dma_handle, DMA_FLAG_TC4)) /* 等待 DMA1_Channel4 传输完成 */
{
__HAL_DMA_CLEAR_FLAG(&g_dma_handle, DMA_FLAG_TC4); /* 清除 DMA1_Channel4 传输完成标志 */
HAL_UART_DMAStop(&g_uart1_handle); /* 传输完成以后关闭串口DMA */
break;
}
2.7 __HAL_DMA_GET_COUNTER()
宏定义 __HAL_DMA_GET_COUNTER(&hdma);
宏描述 获取特定DMA通道的剩余传输字节数
宏参数 &hdma:DMA_HandleTypeDef
结构体变量,DMA句柄
pro = __HAL_DMA_GET_COUNTER(&g_dma_handle);
3 DMA配置步骤
使能DMA时钟 __HAL_RCC_DMA1_CLK_ENABLE
初始化DMA HAL_DMA_Init; __HAL_LINKDMA
使能串口的DMA发送,启动传输 HAL_UART_Transmit_DMA
查询DMA传输状态 __HAL_DMA_GET_FLAG; __HAL_DMA_GET_COUNTER
DMA中断使用 HAL_NVIC_EnableIRQ; HAL_NVIC_SetPriority
4 参考资料
1. Description of STM32F1xx HAL drivers.pdf
2.【【正点原子】手把手教你学STM32 HAL库开发全集【真人出镜】STM32入门教学视频教程 单片机 嵌入式】 https://www.bilibili.com/video/BV1bv4y1R7dp