stm32串口HAL库的DMA发送问题
2019-08-30 来源:eefocus
本文使用stm32f411ret的串口1的DMA方式发送数据,刚开始调试的时候发现串口只能发送一次数据,之后就把系统hang住了。通过网上搜资料和不断尝试,发现问题是中断回调函数没有写的原因。
使用HAL库的DMA,需要同时实现DMA中断回调函数和串口中断回调函数。
void DMA2_Stream7_IRQHandler(void)
{
HAL_DMA_IRQHandler(Uart1Handle.hdmatx);
}
void USART1_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(USART1_IRQn);
HAL_UART_IRQHandler(&Uart1Handle);
}
下面附上我的dma配置和串口配置函数
dma配置
void HAL_UART1_dma_Init(void)
{
static DMA_HandleTypeDef hdma_tx;
__HAL_RCC_DMA2_CLK_ENABLE(); //打开DMA2时钟
/*##-3- Configure the DMA streams ##########################################*/
/* Configure the DMA handler for Transmission process */
hdma_tx.Instance = DMA2_Stream7;
hdma_tx.Init.Channel = DMA_CHANNEL_4; //串口1发送属于stream7、channel4,可在参考手册的DMA章节查到
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; //数据发送方向:内存->外设
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE; //外设为串口,地址不需要增加
hdma_tx.Init.MemInc = DMA_MINC_ENABLE; //存储需要增加
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //串口为字节
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; //与串口设置要一致
hdma_tx.Init.Mode = DMA_NORMAL; //一次发送,如果设置为循环模式,会一直不停的发
hdma_tx.Init.Priority = DMA_PRIORITY_LOW; //低优先级
hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_tx.Init.MemBurst = DMA_MBURST_INC4;
hdma_tx.Init.PeriphBurst = DMA_PBURST_INC4;
HAL_DMA_Init(&hdma_tx);
/* Associate the initialized DMA handle to the the UART handle */
__HAL_LINKDMA(&Uart1Handle, hdmatx, hdma_tx); //将dma的发送handle赋值给串口1的hdmatx成员
/*##-4- Configure the NVIC for DMA #########################################*/
/* NVIC configuration for DMA transfer complete interrupt (USARTx_TX) */
HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 0, 1); //设置dma中断优先级
HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn); //使能dma中断
}
串口引脚配置
void Init_Usart1(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable GPIO TX/RX clock */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* Enable USARTx clock */
__HAL_RCC_USART1_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* UART TX GPIO pin configuration */
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* UART RX GPIO pin configuration */
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_SetPriority(USART1_IRQn,0,0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
串口配置
void Usart1_Configuration(uint32_t BaudRate)
{
Uart1Handle.Instance = USART1;
Uart1Handle.Init.BaudRate = BaudRate;
Uart1Handle.Init.WordLength = UART_WORDLENGTH_8B;
Uart1Handle.Init.StopBits = UART_STOPBITS_1;
Uart1Handle.Init.Parity = UART_PARITY_NONE;
Uart1Handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
Uart1Handle.Init.Mode = UART_MODE_TX_RX;
Uart1Handle.Init.OverSampling = UART_OVERSAMPLING_16;
if(HAL_UART_Init(&Uart1Handle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
}
发送数据调用下面的函数即可
HAL_UART_Transmit_DMA(&Uart1Handle, (uint8_t*)aTxBuffer, 32)
实际操作时可以在串口中断中设置一个标志位,用来标记串口发送完成,在主程序中用标志位控制对发送函数的调用。