STR32H743 uart DMA收发一段时间后收不到数据的问题记录
平台 STR32H743
配置
Rx DMA2_Stream6 没开启DMA中断
Tx DMA2_Stream7 开启DMA 中断
用了 hal 库
测试一段时间后或者 上位机断电、重启后,下位机无法再接收数据,
原因:
用keil debug 发现,收不到数据时 DMAR 位 被置0,也就是 接收DMA 被禁用,
当然收不到数据,这不纯纯要人命吗。。。
查手册发现,接收出错后会禁用 DMA, 接下来很关键
相应的错误标志位 以及 RXNE会被置1,
错误标志位包括 奇偶校验错误, 帧错误 或 噪声错误
所以,DMAR 被 置0 ,应该是 上面的情况发生了,
对应解决方案如下:
在uart 中断处理函数中判断上述任一flag 置1 了 ,我们就重新使能接收DMA(即DMAR 置1)
同时清理错误标志位
if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_PE) != RESET || __HAL_UART_GET_FLAG(&huart2, UART_FLAG_FE) != RESET || __HAL_UART_GET_FLAG(&huart2, UART_FLAG_NE) != RESET || __HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) != RESET)
{
SET_BIT(huart2.Instance->CR3, USART_CR3_DMAR);
}
/* 帧错误 */
__HAL_UART_CLEAR_FEFLAG(&huart2);
/* 奇偶校验错误 */
__HAL_UART_CLEAR_PEFLAG(&huart2);
/* 噪声错误 */
__HAL_UART_CLEAR_NEFLAG(&huart2);
/* RXNE RXNE 在 H743上会自动清除可以这句可以省略 */
__HAL_UART_CLEAR_FLAG(&huart2,UART_FLAG_RXNE);
完整代码放在最后:
(代码不规范的地方还请指出)
额外注意事项:
发送DMA初始化放在uart之前,接收DMA 初始化要放在 uart初始化之后,否则会出发送 busy 的问题,
static void drv_uart2_rxdma_config(void) {
/*开启DMA时钟*/
__HAL_RCC_DMA2_CLK_ENABLE();
drv_uart2_rxdma.Instance = DMA2_Stream6;
drv_uart2_rxdma.Init.Request = DMA_REQUEST_USART2_RX;
drv_uart2_rxdma.Init.Direction= DMA_PERIPH_TO_MEMORY;
/*外设地址不增*/
drv_uart2_rxdma.Init.PeriphInc = DMA_PINC_DISABLE;
/*内存地址自增*/
drv_uart2_rxdma.Init.MemInc = DMA_MINC_ENABLE;
/*外设数据单位*/
drv_uart2_rxdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
/*内存数据单位 8bit*/
drv_uart2_rxdma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
/*DMA模式:不断循环*/
drv_uart2_rxdma.Init.Mode = DMA_CIRCULAR;
/*优先级:中*/
drv_uart2_rxdma.Init.Priority = DMA_PRIORITY_MEDIUM;
/*禁用FIFO*/
drv_uart2_rxdma.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
drv_uart2_rxdma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
/*存储器突发传输 1个节拍*/
drv_uart2_rxdma.Init.MemBurst = DMA_MBURST_SINGLE;
/*外设突发传输 1个节拍*/
drv_uart2_rxdma.Init.PeriphBurst = DMA_PBURST_SINGLE;
/*配置DMA2的数据流7*/
/* Deinitialize the stream for new transfer */
HAL_DMA_DeInit(&drv_uart2_rxdma);
/* Configure the DMA stream */
HAL_DMA_Init(&drv_uart2_rxdma);
/* Associate the DMA handle */
__HAL_LINKDMA(&huart2, hdmarx, drv_uart2_rxdma);
}
static void drv_uart2_txdma_config(void) {
/*开启DMA时钟*/
__HAL_RCC_DMA2_CLK_ENABLE();
drv_uart2_txdma.Instance = DMA2_Stream7;
drv_uart2_txdma.Init.Request = DMA_REQUEST_USART2_TX;
drv_uart2_txdma.Init.Direction= DMA_MEMORY_TO_PERIPH;
/*外设地址不增*/
drv_uart2_txdma.Init.PeriphInc = DMA_PINC_DISABLE;
/*内存地址自增*/
drv_uart2_txdma.Init.MemInc = DMA_MINC_ENABLE;
/*外设数据单位*/
drv_uart2_txdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
/*内存数据单位 8bit*/
drv_uart2_txdma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
/*DMA模式:不断循环*/
drv_uart2_txdma.Init.Mode = DMA_NORMAL;
/*优先级:中*/
drv_uart2_txdma.Init.Priority = DMA_PRIORITY_MEDIUM;
/*禁用FIFO*/
drv_uart2_txdma.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
drv_uart2_txdma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
/*存储器突发传输 1个节拍*/
drv_uart2_txdma.Init.MemBurst = DMA_MBURST_SINGLE;
/*外设突发传输 1个节拍*/
drv_uart2_txdma.Init.PeriphBurst = DMA_PBURST_SINGLE;
/*配置DMA2的数据流7*/
/* Deinitialize the stream for new transfer */
HAL_DMA_DeInit(&drv_uart2_txdma);
/* Configure the DMA stream */
HAL_DMA_Init(&drv_uart2_txdma);
/* Associate the DMA handle */
__HAL_LINKDMA(&huart2, hdmatx, drv_uart2_txdma);
}
uint32_t tlfs_impella_drv_uart_upper_init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;
if (TLFS_IMPELLA_DRV_UART_UPPER_OK_INIT == drv_uart_upper_init_status) return 0;
uart2_sem = osSemaphoreNew (UART2_SEM_MAX, 0, NULL);
if(uart2_sem == NULL) return 1;
drv_uart2_txdma_config();
RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
RCC_PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1;
HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);
/* Peripheral clock enable */
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/**USART2 GPIO Configuration
PA3 ------> USART2_RX
PA2 ------> USART2_TX
*/
GPIO_InitStruct.Pin = DRV_UART_2_TX_GPIO | DRV_UART_2_RX_GPIO;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
HAL_GPIO_Init(DRV_UART_2_RX_TX_PORT, &GPIO_InitStruct);
huart2.Instance = USART2;
huart2.Init.BaudRate = DRV_UART_2_BAUDRATE;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_OK != HAL_UART_Init(&huart2)) {
drv_uart_upper_init_status = TLFS_IMPELLA_DRV_UART_UPPER_FAIL_INIT;
return 1;
}
HAL_NVIC_SetPriority(USART2_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(USART2_IRQn);
HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);
drv_uart2_rxdma_config();
HAL_UART_Receive_DMA(&huart2, elem2.data, QUEUE_NODE_DATA_LEN);
drv_uart_upper_init_status = TLFS_IMPELLA_DRV_UART_UPPER_OK_INIT;
return 0;
}
void USART2_IRQHandler(void) {
unsigned int len = 0;
if (__HAL_UART_GET_IT(&huart2, UART_IT_IDLE) != RESET) {
//__HAL_UART_CLEAR_OREFLAG(&huart2);
// 关闭DMA ,防止干扰
__HAL_DMA_DISABLE(&drv_uart2_rxdma);
// 清DMA标志位
__HAL_DMA_CLEAR_FLAG(&drv_uart2_rxdma,DMA_FLAG_TCIF2_6);
/ * 获取接收数据长度 * /
len = QUEUE_NODE_DATA_LEN - ((DMA_Stream_TypeDef*)drv_uart2_rxdma.Instance)->NDTR;
// 重新赋值计数值,必须大于等于最大可能接收到的数据帧数目
WRITE_REG(((DMA_Stream_TypeDef*)drv_uart2_rxdma.Instance)->NDTR, QUEUE_NODE_DATA_LEN);
if (len != 0) {
elem2.len = len % QUEUE_NODE_DATA_LEN;
cbWrite(&uart2_cb, &elem2);
osSemaphoreRelease(uart2_sem);
}
__HAL_DMA_ENABLE(&drv_uart2_rxdma);
if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_PE) != RESET || __HAL_UART_GET_FLAG(&huart2, UART_FLAG_FE) != RESET || __HAL_UART_GET_FLAG(&huart2, UART_FLAG_NE) != RESET || __HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) != RESET)
{
SET_BIT(huart2.Instance->CR3, USART_CR3_DMAR);
}
__HAL_UART_CLEAR_IDLEFLAG(&huart2);
}
HAL_UART_IRQHandler(&huart2);
__HAL_UART_CLEAR_OREFLAG(&huart2);
__HAL_UART_CLEAR_FEFLAG(&huart2);
__HAL_UART_CLEAR_PEFLAG(&huart2);
__HAL_UART_CLEAR_NEFLAG(&huart2);
__HAL_UART_CLEAR_FLAG(&huart2,UART_FLAG_RXNE);
}