一、DMA发送
1、配置问题
使用DMA发送时需要将DMA配置成内存到寄存器搬运,关闭寄存器的地址增长,如果要搬运的多个字节就需要开启内存的地址增长
/* 串口 */
hdma_usart2_tx.Instance = DMA1_Channel3;
hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
//!!! 设置成9数据位需要使用半字对齐 即每次增长2字节
hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_usart2_tx.Init.Mode = DMA_NORMAL;
hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
HAL_DMA_Init(&hdma_usart2_tx);
需要将DMA的通道连接到串口寄存器,一般来说所有DMA通道都可以连接串口寄存器,但部分芯片的DMA的部分通道可能不支持连接,需要查看用户手册。如果是HAL库,连接后还需要使用__HAL_LINKDMA将串口句柄和DMA句柄进行链接。
HAL_DMA_ChannelMap(&hdma_usart2_tx, DMA_CHANNEL_MAP_USART2_WR);
__HAL_LINKDMA(&huart2, hdmatx, hdma_usart2_tx);
串口和DMA的时钟都不要忘记开启
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
2、发送问题
如果使用 HAL_UART_Transmit_DMA(&huart2,(uint8_t *)data,43); 进行发送需要确保发送完毕前data的内存没有被释放,DMA发送调用完后不会阻塞,如果函数结束后data的数据还没搬运完就会出错,最方便的办法就是将data设置为全局变量。
uint16_t data[43];
如果上一次的数据没有发送完却再次开启DMA发送会导致发送失败,即进入HAL_BUSY,建议开启DMA中断,在中断中调用会自动清除发送完毕标志位允许下一次传输
void DMA1_Channel3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_usart2_tx);
}
二、DMA接收
1、配置问题
需要配置成寄存器到内存,同样关闭寄存器增长开启内存增长
//需要先开启DMA再开启串口
hdma_usart1_rx.Instance = DMA1_Channel2;
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_rx.Init.Mode = DMA_NORMAL;
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
HAL_DMA_Init(&hdma_usart1_rx);
2、接收问题
进行DMA接收时最好不要到接收的内存中读取数据,如果需要读取数据要先关闭DMA接收
//读取DMA
HAL_UART_DMAStop(huart);
//读取数据...
//再次开启DMA
HAL_UART_Receive_DMA(&huart1,rx_buf.buf,RX_BUF_MAX);
开启DMA接收时如果串口数据寄存器DR里有数据DMA就会立即搬运一次,如果不想接收该数据可以开启DMA前先清空DR
标签:DMA,HAL,tx,hdma,Init,笔记,串口,usart2 From: https://blog.csdn.net/weixin_63723467/article/details/144781596