记一次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 ...
随机推荐
- Java中的深浅拷贝问题,你清楚吗?
一.前言 拷贝这个词想必大家都很熟悉,在工作中经常需要拷贝一份文件作为副本.拷贝的好处也很明显,相较于新建来说,可以节省很大的工作量.在Java中,同样存在拷贝这个概念,拷贝的意义也是可以节省创建对象 ...
- JVM学习-运行时数据区域
目录 前言 运行时数据区 程序计数器 Java虚拟机栈 局部变量表 基础数据类型 对象引用 returnAddress 操作数栈 动态链接 方法返回地址 Java堆 方法区 类型信息 字段描述符 方法 ...
- MySQL高可用HA——keepalived配置
0. Keepalived介绍 Keepalived是基于VRRP(Virtual Router Redundancy Protocol,虚拟路由器冗余协议)协议的一款高可用软件.Keepaili ...
- 深度漫谈数据系统架构——Lambda architecture
https://mp.weixin.qq.com/s/whmhm2yzug2WVdH3dTq8hg
- https://twistedmatrix.com/documents/current/core/howto/defer.html
https://twistedmatrix.com/documents/current/core/howto/defer.html
- 【PC Basic】CPU、核、多线程的那些事儿
一.CPU与核的概念 1.半导体中名词[Wafer][Chip][Die]中文名字和用途 Wafer--晶圆 wafer 即为图片所示的晶圆,由纯硅(Si)构成.一般分为6英寸.8英寸.12英寸规格不 ...
- 【转载】【Python模块】datetime
原文地址 一.datetime模块介绍 (一).datetime模块中包含如下类: 类名 功能说明 date 日期对象,常用的属性有year, month, day time 时间对象 datetim ...
- windows10 中 svn 代码统计工具 StatSVN 使用详解
1.下载TortoiseSVN 下载地址 ps:安装时务必选上命令行的svn命令. 2.下载StatSVN 官网地址 官网上目前时0.7.0版本,我的svn是1.12.0版本,运行时会报错: 所以建议 ...
- SpringMVC听课笔记(二:SpringMVC的 HelloWorld)
1.如何建Maven web项目,请看http://how2j.cn/k/maven/maven-eclipse-web-project/1334.html 2.Maven项目,pom文件中的jar包 ...
- Grafana Prometheus系统监控Redis服务
Grafana Prometheus系统监控Redis服务 一.Grafana Prometheus系统监控Redis服务 1.1流程 1.2安装redis_exporter 1.3配置prometh ...