STM32F4 HAL库串口死锁问题调试记录

2024-03-03 08:36

本文主要是介绍STM32F4 HAL库串口死锁问题调试记录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • STM32F4 HAL库串口死锁问题调试记录
      • 调试方法
      • 结果
      • 分析
      • 解决
        • 方法一:
        • 方法二:

STM32F4 HAL库串口死锁问题调试记录

使用方法:通过串口DMA固定周期向外发送数据,同时开启串口DMA接收用于接收其它板卡发来的数据。
问题:在程序运行一段时间后会出现程序不再接收数据的情况,但向外发送数据正常。
分析:一开始认为是触发了串口ORE错误导致的这个问题呢,但奇怪的是并没有触发串口错误中断的回调函数,通过进一步分析排查发现是由__HAL_LOCK()引起的,而串口ORE错误是在触发这个问题之后出现的。

调试方法

  1. 通过如下函数开启串口DMA接收
HAL_UARTEx_ReceiveToIdle_DMA(&JOYSTICK_HUART, joystick_uart_buffer, JOYSTICK_UART_BUFFER_SIZE);
  1. 通过如下函数以10ms周期定时向外发送数据
HAL_UART_Transmit_DMA(&JOYSTICK_HUART,(uint8_t*)&joystick_display_frame,sizeof(JoystickDisplayFrame_t));
  1. 实现串口DMA+IDLE中断接收回调函数
uint32_t huart2_err_cnt = 0;
uint32_t aaa[10] = {0};
HAL_StatusTypeDef huart2_status1;
HAL_StatusTypeDef huart2_status2;uint32_t tx_lock_cnt = 0;
uint32_t tx_unlock_cnt = 0;
uint8_t rx_irq_flag = 0;void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {uart_rx_event_cnt++;huart2_status1 = HAL_UARTEx_ReceiveToIdle_DMA(&JOYSTICK_HUART, joystick_uart_buffer, JOYSTICK_UART_BUFFER_SIZE);if(huart2_status1 != HAL_OK) {huart2_err_cnt++;rx_irq_flag = 1;/* 根据相应的错误类型清除相应的错误标志 */if(__HAL_UART_GET_FLAG(&JOYSTICK_HUART, UART_FLAG_ORE) != RESET) {__HAL_UART_CLEAR_OREFLAG(&JOYSTICK_HUART); //清除ORE溢出错误标志,(读SR然后读DR,这里用于清除串口错误标志)aaa[0]++;} else if(__HAL_UART_GET_FLAG(&JOYSTICK_HUART, UART_FLAG_FE) != RESET) {__HAL_UART_CLEAR_FEFLAG(&JOYSTICK_HUART); //清除FE帧错误标志aaa[1]++;} else if(__HAL_UART_GET_FLAG(&JOYSTICK_HUART, UART_FLAG_PE) != RESET) {__HAL_UART_CLEAR_PEFLAG(&JOYSTICK_HUART); //清除PE奇偶校验错误标志aaa[2]++;} else if(__HAL_UART_GET_FLAG(&JOYSTICK_HUART, UART_FLAG_NE) != RESET) {__HAL_UART_CLEAR_NEFLAG(&JOYSTICK_HUART); //清除NE噪声错误标志aaa[3]++;}huart2_status2 = HAL_UARTEx_ReceiveToIdle_DMA(&JOYSTICK_HUART, joystick_uart_buffer, JOYSTICK_UART_BUFFER_SIZE);}
}
  1. 实现串口错误中断回调函数
uint32_t uart_error_cnt = 0; //记录是否进入串口错误中断
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {uart_error_cnt++;// 其它处理
}
  1. 改造HAL库串口DMA发送函数来验证问题
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{uint32_t *tmp;/* Check that a Tx process is not already ongoing */if (huart->gState == HAL_UART_STATE_READY){if ((pData == NULL) || (Size == 0U)){return HAL_ERROR;}/* Process Locked */__HAL_LOCK(huart);if(rx_irq_flag == 0) {tx_lock_cnt++;}// 省略中间的处理/* Process Unlocked */__HAL_UNLOCK(huart);if(rx_irq_flag == 0) {tx_unlock_cnt++;}/* Enable the DMA transfer for transmit request by setting the DMAT bitin the UART CR3 register */ATOMIC_SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);return HAL_OK;}else{return HAL_BUSY;}
}

结果

下图为出错时对应的变量值
第一次测试结果:
在这里插入图片描述
第二次测试结果:
在这里插入图片描述

分析

  1. 根据上面的结果可以看出:程序在执行发送函数中的__HAL_LOCK(huart)串口加锁函数后,__HAL_UNLOCK(huart)串口解锁函数前触发了串口IDLE中断,此时由于串口处于锁定状态,执行HAL_UARTEx_ReceiveToIdle_DMA()函数会直接返回HAL_BUSY(即2)的状态,导致出现了错误。
  2. 根据aaa[0]的值可以判定此时尚未出现串口ORE的报错,而usart2_sr串口状态寄存器的值显示当前出现了串口ORE错误,这个错误是由于后续又继续收到数据导致的。
  3. 根据usart2_cr串口控制寄存器1的值可以看出IDLEIE中断使能标志位现在为0,因而不会继续触发串口IDLE接收中断了,自然就不会继续执行回调函数的内容了

解决

STM32串口是支持全双工工作的,按理说收发可以做到完全互不干扰,但是串口锁定处理的这段时间确实会影响全双工的性能。程序同时高频接收和高频发送时可能会有比较高的概率出现该问题。

方法一:

屏蔽掉HAL库中关于串口锁的函数(不推荐)

方法二:

触发这种情况时添加串口解锁处理

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {uart_rx_event_cnt++;huart2_status1 = HAL_UARTEx_ReceiveToIdle_DMA(&JOYSTICK_HUART, joystick_uart_buffer, JOYSTICK_UART_BUFFER_SIZE);if(huart2_status1 != HAL_OK) {huart2_err_cnt++;JOYSTICK_HUART.RxState = HAL_UART_STATE_READY;JOYSTICK_HUART.Lock = HAL_UNLOCKED; //或者调用 __HAL_UNLOCK(&JOYSTICK_HUART);huart2_status2 = HAL_UARTEx_ReceiveToIdle_DMA(&JOYSTICK_HUART, joystick_uart_buffer, JOYSTICK_UART_BUFFER_SIZE);}
}

这篇关于STM32F4 HAL库串口死锁问题调试记录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/769075

相关文章

SQL Server数据库死锁处理超详细攻略

《SQLServer数据库死锁处理超详细攻略》SQLServer作为主流数据库管理系统,在高并发场景下可能面临死锁问题,影响系统性能和稳定性,这篇文章主要给大家介绍了关于SQLServer数据库死... 目录一、引言二、查询 Sqlserver 中造成死锁的 SPID三、用内置函数查询执行信息1. sp_w

Python UV安装、升级、卸载详细步骤记录

《PythonUV安装、升级、卸载详细步骤记录》:本文主要介绍PythonUV安装、升级、卸载的详细步骤,uv是Astral推出的下一代Python包与项目管理器,主打单一可执行文件、极致性能... 目录安装检查升级设置自动补全卸载UV 命令总结 官方文档详见:https://docs.astral.sh/

MySQL 设置AUTO_INCREMENT 无效的问题解决

《MySQL设置AUTO_INCREMENT无效的问题解决》本文主要介绍了MySQL设置AUTO_INCREMENT无效的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录快速设置mysql的auto_increment参数一、修改 AUTO_INCREMENT 的值。

关于跨域无效的问题及解决(java后端方案)

《关于跨域无效的问题及解决(java后端方案)》:本文主要介绍关于跨域无效的问题及解决(java后端方案),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录通用后端跨域方法1、@CrossOrigin 注解2、springboot2.0 实现WebMvcConfig

统一返回JsonResult踩坑的记录

《统一返回JsonResult踩坑的记录》:本文主要介绍统一返回JsonResult踩坑的记录,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录统一返回jsonResult踩坑定义了一个统一返回类在使用时,JsonResult没有get/set方法时响应总结统一返回

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Go语言中泄漏缓冲区的问题解决

《Go语言中泄漏缓冲区的问题解决》缓冲区是一种常见的数据结构,常被用于在不同的并发单元之间传递数据,然而,若缓冲区使用不当,就可能引发泄漏缓冲区问题,本文就来介绍一下问题的解决,感兴趣的可以了解一下... 目录引言泄漏缓冲区的基本概念代码示例:泄漏缓冲区的产生项目场景:Web 服务器中的请求缓冲场景描述代码

Java死锁问题解决方案及示例详解

《Java死锁问题解决方案及示例详解》死锁是指两个或多个线程因争夺资源而相互等待,导致所有线程都无法继续执行的一种状态,本文给大家详细介绍了Java死锁问题解决方案详解及实践样例,需要的朋友可以参考下... 目录1、简述死锁的四个必要条件:2、死锁示例代码3、如何检测死锁?3.1 使用 jstack3.2

解决JSONField、JsonProperty不生效的问题

《解决JSONField、JsonProperty不生效的问题》:本文主要介绍解决JSONField、JsonProperty不生效的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录jsONField、JsonProperty不生效javascript问题排查总结JSONField

github打不开的问题分析及解决

《github打不开的问题分析及解决》:本文主要介绍github打不开的问题分析及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、找到github.com域名解析的ip地址二、找到github.global.ssl.fastly.net网址解析的ip地址三