STR32H743 uart DMA收发一段时间后收不到数据的问题记录

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);
}
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32H743是一款高性能的微控制器芯片,内置多种外设,其中包括UARTDMAUART是一种串行通信接口,可以实现单向或双向数据传输。DMA是一种直接内存访问技术,可以在不使用CPU的情况下,实现高速数据传输。 在STM32H743芯片中,可以使用DMA来控制UART数据传输。这可以提高系统的性能,减轻CPU的负担,同时提高数据传输的稳定性和可靠性。具体实现方式如下: 1.配置UART:设置UART参数,如波特率、数据位、校验位等。 2.配置DMA:设置DMA参数,包括通道、存储器地址和外设地址等。 3.开启DMA传输:使用DMA控制器开启传输,此时DMA会自动从存储器读取数据,然后写入到UART的发送寄存器中。 4.数据传输完成中断:传输完成后,DMA会触发中断信号,通知CPU处理相关的中断程序。 使用DMA控制UART数据传输可以大大提高系统的性能和稳定性,特别适合数据量大、传输速度快的场景。同时,由于DMA可以独立运行,不需要CPU的干预,因此可以减少CPU的负担,释放CPU资源,提高系统的响应速度。 ### 回答2: STM32H743是一款高性能的ARM Cortex-M7微控制器,其中UART是其通信接口之一。而DMA(直接存储器访问)是一项能够帮助微控制器实现高效数据传输的技术。 在STM32H743中,使用UART DMA可以实现数据的高速传输,从而提高系统的效率和可靠性。使用UART DMA时,数据的传输不需要CPU的干预,DMA控制器会自动将数据UART端口接收并存储到内存中,或将内存中的数据发送至UART端口。 在配置UART DMA时,需要设置数据传输的方向、缓冲区地址、数据长度、传输完成中断等参数。通过设置这些参数,可以使DMA实现UART数据的高速传输,同时还能够提高CPU资源的利用率。 总之,STM32H743 UART DMA技术是一项十分优秀的高效数据传输方案,可应用于各种需要快速数据传输的应用场合,如智能家居、医疗设备、智能电表等等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值