IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> FreeRTOS串口接收一批数据后卡死bug的解决办法(HAL库发送函数和接收函数不能同时使用) -> 正文阅读

[嵌入式]FreeRTOS串口接收一批数据后卡死bug的解决办法(HAL库发送函数和接收函数不能同时使用)

项目背景: keil5+HAL库+FreeRTOS系统+STM32H743,存在两个同等优先级的任务,一个任务通过串口读取数据,一个任务通过串口发送数据,从而与其他设备进行信息的交互。

问题描述:网络调试助手以20HZ频率往单片机串口发数据,每次数据包共11字节。大概成功接收四百次之后,串口直接进不了接收中断。而串口对外发送任务正常进行,说明系统并未卡死。

不想看猜想过程的可以直接滑到最后一个猜想,就是问题的解决方案。

猜想1和波特率有关系

任务发送数据包一共11字节,即88bit20HZ的频率发送到单片机,1760bit/s。而串口通信波特率为115200bit/s。串口的速度还是足够的。

结论:与波特率无关

猜想2和任务栈空间大小有关系

将任务栈空间增加2倍,问题依然存在。

将任务栈空间增加3倍,问题依然存在。

结论:与任务栈空间无关

猜想3没有清除读取中断标志位

读取标志位RXNE/RXFNE的定义如下:

从数据手册可以看到,有两种方式可以消除中断标志位。通过对USART_RDR寄存器执行读取操作将该位清零或者向USART-RQR寄存区中的RXFRQ位写入“1”将RXNE标志清零。之前也成功了几百次的传输,说明中断基本流程是无误的。通过《中断分析》可知,USART从接收中断到处理中断,最后会进入到UART_RxISR_8BIT函数内部。

    /* Clear RXNE interrupt flag */
    __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);

在函数最后有这样一句代码,这是HAL库函数的内容,不需要用户编写。查看其原型,此函数的功能就是将UART特定的请求标志位置1。而 函数第二个参数UART_RXDATA_FLUSH_REQUEST这个宏定义就是上面提到的RXFRQ位。通过向RXFRQ位写入“1”将RXNE标志清零。探索到这里就发现了清除标志位是HAL函数帮忙完成的。

结论:与中断标志位无关。

猜想4:与任务优先级有关

这个猜想是看了《bug解决》博客想到的。先设置三种优先级方案验证:

接收任务优先级为6,发送任务任务为6,就是项目一开始的设置,问题存在;

接收任务优先级为7,发送任务优先级为6,问题依旧存在。

接收任务优先级为5,发送任务优先级为6,问题解决。

FreeRTOS的任务之间具备独立的任务栈空间,而串口通信是全双工通信,理论上是互不影响的。怎么会因为优先级的高低而出现bug?接下来探索一下这个HAL的源码。

在HAL_UART_Receive_IT函数和HAL_UART_Transmit函数的HAL源码都存在这两句代码:

_HAL_LOCK(huart)
.....
_HAL_UNLOCK(huart)

从函数名来看,这是一个锁住/解锁的函数。正是这个罪魁祸首导致了发送和接收两个任务之间的冲突,即发送和接收不能同时使用,硬生生把一个全双工通信变成了半双工通信。源码很好理解,如果没上锁那就上锁,如果上锁了那就返回HAL_BUSY。而Lock是UART串口结构体的成员之一。

?这个HAL锁资源结构目的就是让一个外设不要被两个地方同时引用。当一个函数在使用huart,此时Lock的状态是HAL_LOCKED,其他函数就不能使用huart,直到使用_HAL_UNLOCK解锁。

但是这个机制很是多余且容易产生bug。下面介绍bug是如何产生的。

正常读取中断的流程是这样的。中断发生会进入HAL_UART_RxCpltCallback回调函数,不管是在回调函数还是在任务,都必须再次调用HAL_UART_Receive_IT函数,目的是重新开启中断。因此在中断处理函数UART_RxISR_8BIT把读取中断关闭了,具体可见《中断分析》。

为什么串口可以正常读取发送几百次后才进入bug?因为bug的发生是需要一定条件的。

我的重新开启中断函数是放在任务的最开始,先开启中断,然后堵塞等待中断回调函数发来的通知。

?读取任务的优先级高于发送任务优先级的情况

当发送任务中的发送函数运行到上锁和解锁之间的时候,读取中断发生。在读取中断回调函数,会发送通知给读取任务,此时读取任务从堵塞态转为就绪态。

通过portYIELD_FROM_ISR函数,此时读取任务的优先级较高,那就会优先执行读取任务。执行HAL_UART_Receive_IT函数,并通过_HAL_LOCK(huart)上锁。但是因为HAL_UART_Transmit并未完成执行完,此时huart还是上锁状态。所以HAL_UART_Receive_IT函数会返回HAL_BUSY,后续的读取中断自然没有成功开启。而函数也并没有再次开启的机制。接收任务就会一直处于堵塞态等待通知,但是一直等不到。而发送任务重新获得CPU使用权,就可以继续完成解锁,发送数据的功能并没有受到影响。

读取中断发生在上锁前,解锁后都没关系,就是不能发生在中间。

?

输出HAL_Receive_IT的返回值验证一下,根据定义HAL_OK是0,HAL_BUSY是2.

?

?发送一次5,代表发送任务成功运行一次。发表一次0,代表接收任务成功运行一次。从串口助手输出数据能看到,返回2之后接收任务就卡死了。符合上述我们的猜想。

??

读取任务的优先级等于发送任务优先级的情况

前面分析了高于的情况,读取任务会抢占CPU,导致读取中断不能再次开启。那为什么等于的情况下还是会出现bug。portYIELD_FROM_ISR只会在被唤醒的任务高于现有执行的任务优先级,才会完成任务切换。

按照上面的分析,如果不强制切换,那发送任务就可以正常上锁解锁,就不会影响到读取任务的重新开启中断位操作。

这里涉及到FreeRTOS的时间片调度机制。根据FreeRTOS的说明,不同优先级之间,高优先级任务可以抢占低优先级任务的CPU使用权。而同样优先级之间,是使用时间片调度的。

FreeRTOS 与隔壁的 RT-Thread 和 μC/OS 一样,都支持时间片的功能。所谓时间片就是同一个优先级下可以有多个任务,每个任务轮流地享有相同的 CPU 时间,享有 CPU 的 时间我们叫时间片。在 RTOS 中,最小的时间单位为一个 tick,即 SysTick 的中断周期, RT-Thread 和 μC/OS 可以指定时间片的大小为多个 tick,但是 FreeRTOS 不一样,时间片只能是一个 tick。一个tick在本次工程设置就是1ms。

那假设一个tick的时间到了,某个任务没有完成呢?没有完成的话就保存环境变量,切换成下一个同等优先级任务。因为一个tick刚好完成n次任务的可能性不大。所以上述的问题又出现了,当读取回调函数发送通知到读取任务,此时读取任务不会立刻抢占CPU,但是已经是就绪状态,就等着下一个tick开始执行。

假如此时发送函数切换时刚好处于上锁和解锁的中间部分代码,那就回发生读取中断没办法再次开启的bug。

??发送一次5,代表发送任务成功运行一次。发表一次0,代表接收任务成功运行一次。从串口助手输出数据能看到,返回2之后接收任务就卡死了。符合上述我们的猜想。

解决方案

将读取任务的优先级调整至5,低于发送任务。所以读取任务只能乖乖等待发送任务完成一次,进入堵塞状态,才能开始。这样就不会造成上锁返回HAL_BUSY的情况。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-10 11:01:09  更:2021-09-10 11:01:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/30 1:25:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码