记一次FreeRTOS错误配置导致无法进入临界区
最近项目用到FreeRTOS,在实际调试中发现我自己的一段代码本来好用的(在无RTOS的情况下),但是当我在带RTOS的情况下把代码放到一个单独的任务中运行时我发现本来好用的代码莫名其妙的出现问题,有一定的概率会失败,考虑到应该是内核发生了调度导致代码中时序比较严格的地方被打断因此会出现时好时不好的现象,因此我对时序严格的地方调用了taskENTER_CRITICAL();和taskEXIT_CRITICAL();进行任务切换保护和中断但是结果还是一样,由此一来这个问题困扰了好久,我就开始怀疑freeRTOS源码的问题,仔细看了源码中关于进入临界和退出临界的函数。
进入临界区的宏函数是:taskENTER_CRITICAL();而又一层宏是portENTER_CRITICAL()最后才是函数vPortEnterCritical()。
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
uxCriticalNesting++; /* This is not the interrupt safe version of the enter critical function so
assert() if it is being called from an interrupt context. Only API
functions that end in "FromISR" can be used in an interrupt. Only assert if
the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section. */
if( uxCriticalNesting == 1 )
{
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
}
}
注意函数中不仅仅将临界区深度加1同时还调用了宏函数:portDISABLE_INTERRUPTS();这个宏的实体函数是vPortRaiseBASEPRI()
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY; __asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
section. */
msr basepri, ulNewBASEPRI
dsb
isb
}
}
这里参考M3权威指南中关于异常掩蔽寄存器,PRIMASK, FAULTMASK 以及 BASEPRI的功能描述。
PRIMASK 用于除能在 NMI 和硬 fault 之外的所有异常,它有效地把当前优先级改为 0(可
编程优先级中的最高优先级)。该寄存器可以通过 MRS 和 MSR 以下例方式访问:
关中断
MOV R0, #1
MSR PRIMASK, R0 开中断
MOV R0, #0
MSR PRIMASK, R0
FAULTMASK则更加绝对他可以关闭除NMI以外的所有中断,使用其专用的指令访问方式及功能如下:
FAULTMASK=1,关异常
CPSID F ; FAULTMASK=0,开异常
CPSIE F ;
最后也就是本次将说明关于FreeRTOS系统中临界区用到的BASEPRI特殊功能寄存器,这个寄存器在内核指南中用了一个“细腻”的描述,意思这个寄存器可以更加细分的控制中断屏蔽的问题。这个寄存器的作用就是如果你向其中写入 A则中断优先级数大于等于A的所有中断将被除能。同时如果你给其中写0则表示不屏蔽任何优先级的中断。回到上面说的FreeRTOS的临界区问题,在进入临界区函数内调用了portFORCE_INLINE 函数这个函数内部是用汇编写的但是内容比较浅显易懂其实就是将configMAX_SYSCALL_INTERRUPT_PRIORITY 写入BASEPRI因此这将屏蔽优先级不高于configMAX_SYSCALL_INTERRUPT_PRIORITY (中断优先级数大于等于configMAX_SYSCALL_INTERRUPT_PRIORITY )的中断,本次我遇到的问题比较LOW啊,我在配置文件中如下配置
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 5
在实际工程中我将中断配置为中断优先级分组“组4”也就是全部用于抢占优先级共可以分16(0~~~15)级优先级,配置文件中我配置为5,但是在使用时发现,调用进入临界函数后调度器虽然不会再进行调度,但是中断还是会执行,这我就奇怪了。
继续看内核指南,M3内核可以支持256级中断,且BASEPRI寄存器最多可以到9位,具体几位和芯片设计的优先级表示位数相关,这就是此次问题的原因了,STM32F1只使用了8位优先级中的高四位,低位未使用,因此实际效果如下(灰色表示未使用写会被忽略,读回永远是0)
当我给BASEPRI寄存器中写入configMAX_SYSCALL_INTERRUPT_PRIORITY = 5 时实际写入的效果是 0000 0101因此此时对于STM32芯片来说,实际写入完成后的寄存器实际值是0x00,因为对于低四位功能未实现当写入时会被忽略,读取会一直是0,所以会导致出现FreeRTOS临界区无法屏蔽中断的问题。同样对于如果不使用优先级组4时,同理将抢占优先级和子优先级合并后和BASEPRI寄存器中的之比较如果大于则会被屏蔽。这里注意不管使用多少位都是MSB对齐的,查阅内核指南的一段话:通过让优先级以 MSB 对齐,可以简化程序的跨器件移植。比如,如果一个程序早先在支持 4 位优先级的器件上运行,在移植到只支持 3 位优先级的器件后,其功能不受影响。但若是对齐到 LSB,则会使 MSB 丢失,导致数值大于 7 的低优先级一下子升高了,甚至会反转小于等于 7 的高优先级。如,8 号优先级因为损失了 MSB,现在反而变成 0 号了!这一点实际点也就是如图所示的意义:
完事了。。。细节真的很重要啊!!!
记一次FreeRTOS错误配置导致无法进入临界区的更多相关文章
- jenkins用户权限配置错误,导致登录时提示:没有Overall/read权限
jenkins用户权限配置错误,导致登录时提示:没有Overall/read权限 由于初次接触jenkins,于是在搭建好jenkins以后,想要对用户进行管理,于是乎开始在系统管理->conf ...
- node name配置错误,导致grid日志在报警
[root@aipdb ContentsXML]# cat inventory.xml <?xml version="1.0" standalone="yes&qu ...
- ubuntu18.04错误配置变量环境导致无法进入系统
1.问题描述 错误配置环境变量(直接在/etc/profile文件末尾添加了export xxx),关机后一直在登录界面循环无法进入系统. ###环境变量的添加是在原有变量之后以冒号(:)分隔加入,并 ...
- 记pytorch版faster rcnn配置运行中的一些坑
记pytorch版faster rcnn配置运行中的一些坑 项目地址 https://github.com/jwyang/faster-rcnn.pytorch 一般安装配置参考README.md文件 ...
- 记一次因证书问题导致请求失败问题SSLHandshakeException
记一次因证书问题导致请求失败问题SSLHandshakeException 转载请注明出处:https://www.cnblogs.com/funnyzpc/p/10989813.html 最近接一外 ...
- Nginx常见的错误配置
Blog:博客园 个人 翻译自Common Nginx misconfigurations that leave your web server open to attack Nginx是当前主流的W ...
- Oracle登录时提示错误,导致用户无法登录
Oracle登录时提示错误,导致用户无法登录,错误如下 ------------------------------------------------------------------------ ...
- 【初级坑跳跳跳】[NULLException] findViewById() id 引用错误,导致空指针
在学习Intent页面切换,几个页面切换,导致view id 写错,写成另一个xml里的id去了,导致空指针异常 setContentView(R.layout.activity_second); B ...
- FreeRTOS中断优先级配置(重要)
FreeRTOS中断优先级配置(重要) 本章节为大家讲解FreeRTOS中断优先级配置,此章节非常重要,初学者经常在这里犯迷糊.对于初学者来说,本章节务必要整明白.12.1 NVIC基础知识12.2 ...
随机推荐
- MVC和MTV框架模式
1. MVC: MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controller ...
- uni-app开发经验分享四: 实现文字复制到选择器中
这里分享一个我经常用到的一个方法,主要是用来复制文字内容,具体代码如下: var that=this; if(!document){ uni.setClipboardData({ data:复制的值, ...
- 夯实基础系列一:Java 基础总结
前言 大学期间接触 Java 的时间也不短了,不论学习还是实习,都让我发觉基础的重要性.互联网发展太快了,各种框架各种技术更新迭代的速度非常快,可能你刚好掌握了一门技术的应用,它却已经走在淘汰的边缘了 ...
- 3、剑指offer-数组——数组中重复的数字
*题目描述* **在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输 ...
- Fixing SQL Injection: ORM is not enough
Fixing SQL Injection: ORM is not enough | Snyk https://snyk.io/blog/sql-injection-orm-vulnerabilitie ...
- 阿里云 Redis 开发规范
阿里云Redis开发规范-阿里云开发者社区 https://developer.aliyun.com/article/531067 https://mp.weixin.qq.com/s/UWE1Kx6 ...
- Linux 中的文件属性
文件属性 d 开头是: 目录文件.l 开头是: 符号链接(指向另一个文件,类似于瘟下的快捷方式).s 开头是: 套接字文件(sock).b 开头是: 块设备文件,二进制文件.c 开头是: 字符设备文 ...
- sentry 错误监控 报警
错误监控 报警 Sentry | Error Tracking Software - JavaScript, Python, PHP, Ruby, more https://sentry.io/wel ...
- 深入TLS/SSL协议
总体 TLS/SSL协议是为了解决网络通讯中的信息安全问题而诞生的. 它的设计目的主要有三个: 身份验证--搞清楚与我通讯的人是不是我所想的那个. 保密性--就算第三方拿到了通讯内容,也搞不清楚其中所 ...
- 用tqdm和rich为固定路径和目标的python算法代码实现进度条
适用场景 在存在固定长度的算法中可以可视化算法执行的过程,比如对一个固定长度的数组的遍历,就是一种适合使用进度条来进行可视化的场景.而一些条件循环,比如while循环,不一定适合使用进度条来对算法执行 ...