【5】STM32·FreeRTOS·临界段保护与调度器挂起

目录

一、临界段代码保护简介

二、临界段代码保护函数介绍

2.1、调用示例

2.2、内部实现

三、任务调度器的挂起和恢复

3.1、调用示例

3.2、内部实现


一、临界段代码保护简介

什么是临界段:临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段

适用场合如:

1、外设需严格按照时序初始化的外设:IIC、SPI等等
2、系统系统自身需求
3、用户用户需求

中断任务调度可以打断当前程序的运行

二、临界段代码保护函数介绍

FreeRTOS 在进入临界段代码的时候需要关闭中断,当处理完临界段以后再开中断

函数描述

taskENTER_CRITICAL()

任务级进入临界段

taskEXIT_CRITICAL()

任务级退出临界段

taskENTER_CRITICAL_FROM_ISR()

中断级进入临界段

taskEXIT_CRITICAL_FROM_ISR()

中断级退出临界段

2.1、调用示例

任务级临界区调用格式示例:

taskENTER_CRITICAL();
{...    /* 临界区 */
}
taskEXIT_CRITICAL();

中断级临界区调用格式示例:

uint32_t save_status;
save_status = taskENTER_CRITICAL_FROM_ISR();
{...    /* 临界区 */
}
taskEXIT_CRITICAL_FROM_ISR(save_status);

特点

1、成对使用

2、支持嵌套

3、尽量保持临界段耗时短

2.2、内部实现

任务级进入临界段:taskENTER_CRITICAL()

#define taskENTER_CRITICAL()               portENTER_CRITICAL()
#define 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 );}
}#define 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. */
/* *INDENT-OFF* */msr basepri, ulNewBASEPRIdsbisb
/* *INDENT-ON* */}}

任务级退出临界段:taskEXIT_CRITICAL()

#define taskEXIT_CRITICAL()                portEXIT_CRITICAL()
#define portEXIT_CRITICAL()                vPortExitCritical()void vPortExitCritical( void )
{configASSERT( uxCriticalNesting );uxCriticalNesting--;if( uxCriticalNesting == 0 ){portENABLE_INTERRUPTS();}
}#define portENABLE_INTERRUPTS()            vPortSetBASEPRI( 0 )static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI ){__asm{/* Barrier instructions are not used as this function is only used to* lower the BASEPRI value. */
/* *INDENT-OFF* */msr basepri, ulBASEPRI
/* *INDENT-ON* */}}

中断级进入临界段:taskENTER_CRITICAL_FROM_ISR()

#define taskENTER_CRITICAL_FROM_ISR()      portSET_INTERRUPT_MASK_FROM_ISR()
#define portSET_INTERRUPT_MASK_FROM_ISR()  ulPortRaiseBASEPRI()static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void ){uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;__asm{/* Set BASEPRI to the max syscall priority to effect a critical* section. */
/* *INDENT-OFF* */mrs ulReturn, baseprimsr basepri, ulNewBASEPRIdsbisb
/* *INDENT-ON* */}return ulReturn;}

中断级退出临界段:taskEXIT_CRITICAL_FROM_ISR()

#define taskEXIT_CRITICAL_FROM_ISR( x )           portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x )    vPortSetBASEPRI( x )static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI ){__asm{/* Barrier instructions are not used as this function is only used to* lower the BASEPRI value. */
/* *INDENT-OFF* */msr basepri, ulBASEPRI
/* *INDENT-ON* */}}

三、任务调度器的挂起和恢复

挂起任务调度器,调用此函数不需要关闭中断

函数描述

vTaskSuspendAll()

挂起任务调度器

xTaskResumeAll()

恢复任务调度器

3.1、调用示例

vTaskSuspendAll();
{···    /* 内容 */
}
xTaskResumeAll();

1、与临界区不一样的是,挂起任务调度器,未关闭中断

2、它仅仅是防止了任务之间的资源争夺,中断照样可以直接响应

3、挂起调度器的方式,适用于临界区位于任务与任务之间

4、既不用去延时中断,又可以做到临界区的安全

3.2、内部实现

挂起任务调度器:vTaskSuspendAll()

void vTaskSuspendAll( void )
{/* A critical section is not required as the variable is of type* BaseType_t.  Please read Richard Barry's reply in the following link to a* post in the FreeRTOS support forum before reporting this as a bug! -* https://goo.gl/wu4acr *//* portSOFTWARE_BARRIER() is only implemented for emulated/simulated ports that* do not otherwise exhibit real time behaviour. */portSOFTWARE_BARRIER();/* The scheduler is suspended if uxSchedulerSuspended is non-zero.  An increment* is used to allow calls to vTaskSuspendAll() to nest. */++uxSchedulerSuspended;/* Enforces ordering for ports and optimised compilers that may otherwise place* the above increment elsewhere. */portMEMORY_BARRIER();
}

当变量 uxSchedulerSuspended 的值不为 0,将会导致 Systick 无法触发 PendSV 中断,即挂起任务调度器

恢复任务调度器:xTaskResumeAll()

BaseType_t xTaskResumeAll( void )
{TCB_t * pxTCB = NULL;BaseType_t xAlreadyYielded = pdFALSE;/* If uxSchedulerSuspended is zero then this function does not match a* previous call to vTaskSuspendAll(). */configASSERT( uxSchedulerSuspended );/* It is possible that an ISR caused a task to be removed from an event* list while the scheduler was suspended.  If this was the case then the* removed task will have been added to the xPendingReadyList.  Once the* scheduler has been resumed it is safe to move all the pending ready* tasks from this list into their appropriate ready list. */taskENTER_CRITICAL();{--uxSchedulerSuspended;if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ){if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U ){/* Move any readied tasks from the pending list into the* appropriate ready list. */while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ){pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too.  Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */listREMOVE_ITEM( &( pxTCB->xEventListItem ) );portMEMORY_BARRIER();listREMOVE_ITEM( &( pxTCB->xStateListItem ) );prvAddTaskToReadyList( pxTCB );/* If the moved task has a priority higher than or equal to* the current task then a yield must be performed. */if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ){xYieldPending = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}if( pxTCB != NULL ){/* A task was unblocked while the scheduler was suspended,* which may have prevented the next unblock time from being* re-calculated, in which case re-calculate it now.  Mainly* important for low power tickless implementations, where* this can prevent an unnecessary exit from low power* state. */prvResetNextTaskUnblockTime();}/* If any ticks occurred while the scheduler was suspended then* they should be processed now.  This ensures the tick count does* not  slip, and that any delayed tasks are resumed at the correct* time. */{TickType_t xPendedCounts = xPendedTicks; /* Non-volatile copy. */if( xPendedCounts > ( TickType_t ) 0U ){do{if( xTaskIncrementTick() != pdFALSE ){xYieldPending = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}--xPendedCounts;} while( xPendedCounts > ( TickType_t ) 0U );xPendedTicks = 0;}else{mtCOVERAGE_TEST_MARKER();}}if( xYieldPending != pdFALSE ){#if ( configUSE_PREEMPTION != 0 ){xAlreadyYielded = pdTRUE;}#endiftaskYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}}else{mtCOVERAGE_TEST_MARKER();}}taskEXIT_CRITICAL();return xAlreadyYielded;
}

当变量 uxSchedulerSuspended 的值等于 0,则允许调度

1、当任务数量大于 0 时,恢复调度器才有意义,如果没有一个已创建的任务就无意义

2、移除等待就绪列表中的列表项,恢复至就绪列表,直到 xPendingReadyList 列表为空

3、如果恢复的任务优先级比当前正在执行任务优先级更高,则将 xYieldPending 赋值为 pdTRUE,表示需要进行一次任务切换

4、在调度器被挂起的期间内,是否有丢失未处理的滴答数。xPendedTicks 是丢失的滴答数,有则调用 xTaskIncrementTick() 补齐丢失的滴答数

5、判断是否允许任务切换

6、返回任务是否已经切换,已经切换返回 pdTRUE,反之返回 pdFALSE

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/479905.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode 二叉树的最大深度

104. 二叉树的最大深度 已解答 简单 相关标签 相关企业 给定一个二叉树 root ,返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1: 输入:root [3,9,20,null,null,15,7] 输出:3…

VMware ubuntu创建共享文件夹与Windows互传文件

1.如图1所示,点击虚拟机,点击设置; 图1 2.如图2所示,点击选项,点击共享文件夹,如图3所示,点击总是启用,点击添加; 图2 图3 3.如图4所示,出现命名共享文件夹…

matlab 实现混沌麻雀搜索算法的光伏MPPT控制仿真

1、内容简介 略 103-可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略

Unity3D 截图

使用 Unity3D 自带的截图接口,制作截图工具。 截图 有时候我们想对 Unity 的窗口进行截图,如果直接使用一些截图工具,很难截取到一张完整分辨率的图片(例如,我们想要截取一张 1920 * 1080 的图片)。 其实…

STM32F10x 定时器

使用定时器实现:B5 E5的开关 添加相关的.h路径文件 添加相关的.c配置文件 led.h文件 用于声明LED函数 #ifndef __LED_H //没有定义__LED_H #define __LED_H //就定义__LED_H #define LED1_ON GPIO_ResetBits(GPIOB,GPIO_Pin_5) #defi…

PMP好考吗,有多大的价值?

非常好考!PMP目前大陆地区的笔试是只有选择题的,运气好的话 蒙一个都能对,所以PMP的通过率高,这也是很多人考了吐槽PMP没用,是“水证”,但是每年考PMP 的人不减反增,大家可以想一下,…

css:项目

这是一个完整的网站制作的流程 美工会先制作一个原型图: 原型图写的不详细,就是体现一个网页大致的布局 然后美工再做一个psd样例图片 然后再交给程序员 项目 模块化开发:把代码的不同的样式封装起来,需要用到相同样式的标签就…

VsCode 插件推荐(个人常用)

VsCode 插件推荐(个人常用)

黑马程序员Java项目实战《苍穹外卖》Day01

苍穹外卖-day01 课程内容 软件开发整体介绍苍穹外卖项目介绍开发环境搭建导入接口文档Swagger 项目整体效果展示: ​ 管理端-外卖商家使用 ​ 用户端-点餐用户使用 当我们完成该项目的学习,可以培养以下能力: 1. 软件开发整体介绍 作为一…

Python双向链表、循环链表、栈

一、双向链表 1.作用 双向链表也叫双面链表。 对于单向链表而言。只能通过头节点或者第一个节点出发,单向的访问后继节点,每个节点只能记录其后继节点的信息(位置),不能向前遍历。 所以引入双向链表,双…

k8s网络服务

k8s 中向外界提供服务的几种方法port-forward、NodePort,以及 更加常用的提供服务的资源ingress。 1 kubectl port-forward service/redis 6379:6379 现在k8s中有一个pod运行在6379,本机访问映射到6379上,它可以针对部署,服务&…

eduSRC挖洞思路

声明 学习视频来自 B 站UP主泷羽sec,如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负。 ✍🏻作者简介:致…

Leetcode - 周赛424

目录 一,3354. 使数组元素等于零 二, 3355. 零数组变换 I 三,3356. 零数组变换 II 四,3357. 最小化相邻元素的最大差值 一,3354. 使数组元素等于零 本题实际上是一个前/后缀和的问题,就是判断前缀和与后…

Vue2中 vuex 的使用

1.安装 vuex 安装vuex与vue-router类似,vuex是一个独立存在的插件,如果脚手架初始化没有选 vuex,就需要额外安装。 yarn add vuex3 或者 npm i vuex3 233 Vue2 Vue-Router3 Vuex3 344 Vue3 Vue-Router4 Vuex4 2. 新建 store/index.j…

数据结构C语言描述5(图文结合)--队列,数组、链式、优先队列的实现

前言 这个专栏将会用纯C实现常用的数据结构和简单的算法;有C基础即可跟着学习,代码均可运行;准备考研的也可跟着写,个人感觉,如果时间充裕,手写一遍比看书、刷题管用很多,这也是本人采用纯C语言…

Windows修复SSL/TLS协议信息泄露漏洞(CVE-2016-2183) --亲测

漏洞说明: 打开链接:https://docs.microsoft.com/zh-cn/troubleshoot/windows-server/windows-security/restrict-cryptographic-algorithms-protocols-schannel 可以看到: 找到:应通过配置密码套件顺序来控制 TLS/SSL 密码 我们…

深度学习图像视觉 RKNN Toolkit2 部署 RK3588S边缘端 过程全记录

深度学习图像视觉 RKNN Toolkit2 部署 RK3588S边缘端 过程全记录 认识RKNN Toolkit2 工程文件学习路线: Anaconda Miniconda安装.condarc 文件配置镜像源自定义conda虚拟环境路径创建Conda虚拟环境 本地训练环境本地转换环境安装 RKNN-Toolkit2:添加 lin…

controller中的参数注解@Param @RequestParam和@RequestBody的不同

现在controller中有个方法:(LoginUserRequest是一个用户类对象) PostMapping("/test/phone")public Result validPhone(LoginUserRequest loginUserRequest) {return Result.success(loginUserRequest);}现在讨论Param("login…

Android按键点击事件三种实现方法

1. 在xml文件中为 Button 添加android:onclick属性 由于没有onclick这个函数,onclick下面会提示红色波浪线错误,然后单击一下"onclick"按住键盘上AltEnter键,选择在activity中生成函数 public void onclick(View view) {Toast.makeText(this,&…

全景图像(Panorama Image)向透视图像(Perspective Image)的跨视图转化(Cross-view)

一、概念讲解 全景图像到透视图像的转化是一个复杂的图像处理过程,它涉及到将一个360度的全景图像转换为一个具有透视效果的图像,这种图像更接近于人眼观察世界的方式。全景图像通常是一个矩形图像,它通过将球面图像映射到平面上得到&#xf…