当前位置: 首页 > article >正文

嵌入式学习笔记-freeRTOS taskENTER_CRITICAL(_FROM_ISR)跟taskEXIT_CRITICAL(_FROM_ISR)函数解析

一 函数taskENTER_CRITICAL,taskEXIT_CRITICAL

函数taskENTER_CRITICAL最终实现如下:

第①处按照系统设定的configMAX_SYSCALL_INTERRUPT_PRIORITY值对中断进行屏蔽

第②处调用一次自增一次

第③处检查中断状态寄存器位,如果有任何中断位置1,说明是在中断中,那么报错,因为此函数不允许中断中使用。

taskEXIT_CRITICAL函数最终实现如下:

第①处如果前面有过一次以上调用taskENTER_CRITICAL,那么仍然禁止中断configMAX_SYSCALL_INTERRUPT_PRIORITY值以上的中断都不能开启,直到最后一次退出才真正退出,这个意思就是从第一次调用taskENTER_CRITICAL的范围内的代码都不能被中断打扰。

第② 处直接将basepri寄存器写0开启所有中断,taskEXIT_CRITICAL函数没有参数带入,只要调用它就是开启所有中断。

二 taskENTER_CRITICAL_FROM_ISR,taskEXIT_CRITICAL_FROM_ISR

1)taskENTER_CRITICAL_FROM_ISR函数最终实现:

第①②处,将BASEPRI赋值之前先将其值取出来,之后返回

第③处,向BASEPRI寄存器赋新值,

注:BASEPRI是arm的一个寄存器,可以设置一个数值,向寄存器BASEPRI写入某数值时大于等于此数值的中断都会被屏蔽。

2) taskEXIT_CRITICAL_FROM_ISR(xReturn)实现

此函数是带参数的,并不是像taskEXIT_CRITICAL一样直接将0赋值给BASEPRI,而这个参数就是

taskENTER_CRITICAL_FROM_ISR的返回值。

3)这样做有什么作用呢?

直接用实例解释比较容易理解:

// 嵌套中断示例
void Nested_ISR(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    BaseType_t xSavedInterruptStatus1, xSavedInterruptStatus2;
    
    // 第一层临界区保护
    xSavedInterruptStatus1 = taskENTER_CRITICAL_FROM_ISR();
    
    /* 执行第一层临界区代码 */
    

   // 第二层临界区保护(嵌套)
    xSavedInterruptStatus2 = taskENTER_CRITICAL_FROM_ISR();
    
    /* 执行第二层临界区代码 */
    
    // 按相反顺序退出临界区
    taskEXIT_CRITICAL_FROM_ISR(xSavedInterruptStatus2);
   

   taskEXIT_CRITICAL_FROM_ISR(xSavedInterruptStatus1);
    
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

假设系统设置configMAX_SYSCALL_INTERRUPT_PRIORITY为11

第一次调用前basepri寄存器应该为0,所以xSavedInterruptStatus1=0,调用之后basepri寄存器为11,(如果当前中断优先级为11以上,那么11~15的中断都不能响应,如果当前中断优先级位11以下比如9,那么9以上都不能响应)。

第二次调用前basepri寄存器应该为11,所以xSavedInterruptStatus2=11,调用之后basepri寄存器为11,(如果当前中断优先级为11以上,那么11~15的中断都不能响应,如果当前中断优先级位11以下比如9,那么9以上都不能响应)。

第一次返回时因为xSavedInterruptStatus2=11,basepri寄存器应该为11,0~11都能执行,12~15都不能执行,此时如果使用不带ISR的临界屏蔽taskEXIT_CRITICAL()返回   ,那么0~15都能执行,违背初衷。

第二次返回时因为xSavedInterruptStatus2=0,basepri寄存器应该为0,优先级0~15都能执行。

题外话:

也许中断使用带ISR的屏蔽也许还有一个作用,就是跟任务分开,

因为任务中使用临界段仅仅可能只是想能够屏蔽其他任务的干扰,因为其他任务切换依靠最低优先级pendSV切换, 设定一个屏蔽值,可能不想屏蔽高优先级的中断。

而中断使用临界段的意图是屏蔽更高优先级的中断,起码要比当前中断的优先级要高一级(自然比任务的优先级也要高),如果同样使用 taskEXIT_CRITICAL(),一是起不到作用起不到想要的效果(屏蔽更高优先级的中断),二是起不到嵌套分层的作用,所以两者不能使用相同的屏蔽方式?

总之freeRTOS的任务跟中断是分离的两套系统,一个是任务级临界段代码保护,通过嵌套计数实现,一个是中断级代码临界段保护,通过保存和恢复寄存器BASEPRI的数值实现嵌套使用,最好是互不干扰。

可以这样理解:把任务级taskENTER_CRITICAL当成屏蔽所有中断理解,那么中断中不想屏蔽所有中断,中断中中断,那么就必须设置成可嵌套的,可嵌套的就必须带返回。所以taskENTER_CRITICAL_FROM_ISR就是为了可嵌套。

以下来自deepseek的回答有点乱感觉不对稍微参考:

FreeRTOS中断中不能使用taskENTER_CRITICAL()的主要原因如下:

  1. 嵌套机制冲突
    taskENTER_CRITICAL()通过递归计数管理临界区嵌套,但中断服务程序(ISR)可能被更高优先级中断打断,导致嵌套计数不一致,从而引发中断状态恢复错误。

  2. 中断上下文特殊性
    中断中直接关闭所有中断(如taskENTER_CRITICAL()的操作)会破坏实时性,可能导致高优先级中断无法及时响应。FreeRTOS为此专门提供taskENTER_CRITICAL_FROM_ISR(),仅屏蔽特定优先级的中断而非全部。

  3. 优先级管理差异
    taskENTER_CRITICAL()通过操作BASEPRI寄存器屏蔽低于某优先级的中断,而中断服务程序本身可能已处于高优先级上下文,直接调用会导致不可预测的行为。

  4. 任务调度限制
    中断中若使用任务级临界区保护,可能因调度器状态不一致引发任务切换异常,甚至

    死锁。

http://www.lryc.cn/news/2403088.html

相关文章:

  • Unity基础-数学向量
  • 【华为云Astro-服务编排】服务编排中图元的使用与配置
  • 1panel面板中部署SpringBoot和Vue前后端分离系统 【图文教程】
  • C++.OpenGL (7/64)摄像机(Camera)
  • 使用xdocreport导出word
  • 青少年编程与数学 01-011 系统软件简介 05 macOS操作系统
  • Python打卡训练营学习记录Day43
  • 【Android基础回顾】二:handler消息机制
  • 每日Prompt:每天上班的状态
  • .net ORM框架dapper批量插入
  • C++11 右值引用:从入门到精通
  • .net 使用MQTT订阅消息
  • Python实现快速排序的三种经典写法及算法解析
  • 【递归、搜索与回溯】综合练习(四)
  • 强化学习入门:Gym实现CartPole随机智能体
  • STM32:CAN总线精髓:特性、电路、帧格式与波形分析详解
  • 贝叶斯深度学习!华科大《Nat. Commun.》发表BNN重大突破!
  • 【大模型LLM学习】Flash-Attention的学习记录
  • 三、元器件的选型
  • 精益数据分析(95/126):Socialight的定价转型启示——B2B商业模式的价格策略与利润优化
  • stm32_DMA
  • 物联网数据归档之数据存储方案选择分析
  • 【自动驾驶避障开发】如何让障碍物在 RViz 中‘显形’?呈现感知数据转 Polygon 全流程
  • 【C语言】C语言经典小游戏:贪吃蛇(上)
  • usbutils工具的使用帮助
  • vue2中使用jspdf插件实现页面自定义块pdf下载
  • 如何防止服务器被用于僵尸网络(Botnet)攻击 ?
  • 基于cornerstone3D的dicom影像浏览器 第二十九章 自定义菜单组件
  • 【Block总结】DBlock,结合膨胀空间注意模块(Di-SpAM)和频域模块Gated-FFN|即插即用|CVPR2025
  • 【学习笔记】单例类模板