最近项目用到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错误配置导致无法进入临界区的更多相关文章

  1. jenkins用户权限配置错误,导致登录时提示:没有Overall/read权限

    jenkins用户权限配置错误,导致登录时提示:没有Overall/read权限 由于初次接触jenkins,于是在搭建好jenkins以后,想要对用户进行管理,于是乎开始在系统管理->conf ...

  2. node name配置错误,导致grid日志在报警

    [root@aipdb ContentsXML]# cat inventory.xml <?xml version="1.0" standalone="yes&qu ...

  3. ubuntu18.04错误配置变量环境导致无法进入系统

    1.问题描述 错误配置环境变量(直接在/etc/profile文件末尾添加了export xxx),关机后一直在登录界面循环无法进入系统. ###环境变量的添加是在原有变量之后以冒号(:)分隔加入,并 ...

  4. 记pytorch版faster rcnn配置运行中的一些坑

    记pytorch版faster rcnn配置运行中的一些坑 项目地址 https://github.com/jwyang/faster-rcnn.pytorch 一般安装配置参考README.md文件 ...

  5. 记一次因证书问题导致请求失败问题SSLHandshakeException

    记一次因证书问题导致请求失败问题SSLHandshakeException 转载请注明出处:https://www.cnblogs.com/funnyzpc/p/10989813.html 最近接一外 ...

  6. Nginx常见的错误配置

    Blog:博客园 个人 翻译自Common Nginx misconfigurations that leave your web server open to attack Nginx是当前主流的W ...

  7. Oracle登录时提示错误,导致用户无法登录

    Oracle登录时提示错误,导致用户无法登录,错误如下 ------------------------------------------------------------------------ ...

  8. 【初级坑跳跳跳】[NULLException] findViewById() id 引用错误,导致空指针

    在学习Intent页面切换,几个页面切换,导致view id 写错,写成另一个xml里的id去了,导致空指针异常 setContentView(R.layout.activity_second); B ...

  9. FreeRTOS中断优先级配置(重要)

    FreeRTOS中断优先级配置(重要) 本章节为大家讲解FreeRTOS中断优先级配置,此章节非常重要,初学者经常在这里犯迷糊.对于初学者来说,本章节务必要整明白.12.1 NVIC基础知识12.2  ...

随机推荐

  1. gRPC Load Balancing

    gRPC Load Balancing 翻译自:https://grpc.io/blog/grpc-load-balancing/ 这是gRPC负载均衡的第一篇,后续会给出基于golang XDS服务 ...

  2. 盼望着,盼望着。它终于来了!!!剪辑Windows PC测试版!

    盼望着,盼望着.它终于来了!!!剪辑Windows PC测试版! 喜欢短视频抖音的小伙伴们,是不是都对手机抖音剪映操作不是很满意.期待WINDOWS电脑版剪映的来临.在此之前只有MAC版本,不能满足广 ...

  3. Bitter.Core系列八:Bitter ORM NETCORE ORM 全网最粗暴简单易用高性能的 NETCore 之 事务

    Bitter.Core 编写事务相当简单,Bitter.Core 尽可能的将代码编写量降为最低,例外一方方面保证客户主观能控制代码.Bitter.Core 事务提交,支持Builkcopy事务,原生事 ...

  4. LOJ10019生日蛋糕

    Mr.W 要制作一个体积为 N*π 的 M 层生日蛋糕,每层都是一个圆柱体. 设从下往上数第 i 蛋糕是半径为 R_i,高度为 H_i 的圆柱.当 i<M 时,要求 R_i>R_{i+1} ...

  5. LOJ10075 农场派对

    USACO 2007 Feb. Silver N(1≤N≤1000) 头牛要去参加一场在编号为 x(1≤x≤N) 的牛的农场举行的派对.有 M(1≤M≤100000) 条有向道路,每条路长Ti​(1≤ ...

  6. Spring Cloud系列之Commons - 1. 背景与基础知识准备

    本文基于 Spring Cloud 2020.0 发布版的依赖 本系列会深入分析 Spring Cloud 的每一个组件,从Spring Cloud Commons这个 Spring Cloud 所有 ...

  7. Docker容器内中文乱码

    Docker容器内中文乱码 一.通过Dockerfile解决中文乱码问题 方式二: 二.临时解决 方式二: 三.修改jre/lib/fonts下的字体 CSDN:黑猫_:Dockerfile 创建容器 ...

  8. python模块----os模块 (操作系统接口模块)

    os模块提供一种使用与操作系统相关的功能的便捷式途径. 一定要使用 import os 而不是 from os import * .这将避免内建的 open() 函数被 os.open() 隐式替换掉 ...

  9. JVM调优之垃圾定位、垃圾回收算法、垃圾处理器对比

    谈垃圾回收器之前,要先讲讲垃圾回收算法,以及JVM对垃圾的认定策略,JVM垃圾回收器是垃圾回收算法的具体实现,了解了前面的前置知识,有利于对垃圾回收器的理解. 什么是垃圾? 垃圾,主要是指堆上的对象, ...

  10. Maven多模块的2种依赖管理策略

    在Maven多模块的时候,管理依赖关系是非常重要的,各种依赖包冲突,查询问题起来非常复杂,于是就用到了<dependencyManagement>, 示例说明, 在父模块中: <de ...