FreeRTOS任务切换

目录

一、PendSV异常

二、任务切换场合

1、执行系统调用

2、滴答定时器(SysTick)中断

三、PendSV中断服务函数

1、分析xPortPendSVHandler中断服务函数

四、查找下一个要运行的任务的两种方法

1、获取下一个要运行的任务

2、查找下一个要运行的任务的两种方法

2.1、通用方法:所有处理器都可以使用的方法

2.2、硬件方法:需要硬件支持的方法


一、PendSV异常

        PendSV(可挂起的系统调用)其优先级可以通过编程设置。可以通过将中断控制和壮态寄存器 ICSR 的 bit28,也就是 PendSV 的挂起位置 1 来触发 PendSV 中断。

        与SVC异常不同,它是不精确的,因此它的挂起壮态可在更高优先级异常处理内设置,且会在高优先级处理完成后执行。利用该特性,若将PendSV设置为最低的异常优先级,可以让PendSV异常处理在所有其他中断处理完成后执行,这对于上下文切换非常有用,也是各种OS设计中的关键。

        在具有嵌入式OS的典型系统中,处理时间被划分为了多个时间片。若系统中只有两个任务,这两个任务会交替执行,如下图所示:

二、任务切换场合

1、执行系统调用

        执行系统调用就是执行FreeRTOS系统提供的相关API函数,比如任务切换函数taskYIELD(), FreeRTOS有些API函数也会调用函数taskYIELD(),这些API函数都会导致任务切换,这些API函数和任务切换函数taskYIELD()都统称为系统调用。函数taskYIELD()其 实就是个宏,在文件task.h中有如下定义:

在文件portmacro.h中有如下定义:

        通过向中断控制和壮态寄存器 ICSR 的 bit28 写入 1 挂起 PendSV 来启动 PendSV 中断;这样就可以在PendSV中断服务函数中进行任务切换了。

2、滴答定时器(SysTick)中断

FreeRTOS中滴答定时器(SysTick)中断服务函数中也会进行任务切换,滴答定时器中断服务函数如下:

(1) 关闭中断。

(2) 通过向中断控制和壮态寄存器ICSR的bit28写入1挂起PendSV来启动PendSV中断;这 样就可以在PendSV中断服务函数中进行任务切换了。

(3) 打开中断。

三、PendSV中断服务函数

1、分析xPortPendSVHandler中断服务函数

(1)、读取进程栈指针,保存在寄存器RO里面。

(2)和(3),获取当前任务的任务控制块,并将任务控制块的地址保存在寄存器R2里面。

(4)和(5)、判断任务是否使用了FPU,如果任务使用了FPU的话在进行任务切换的时候就需要将FPU寄存器s16-s31手动保存到任务堆栈中,其中s0-s15和FPSCR是自动保存的。

(6)、保存s16-s31这16个FPU寄存器。

(7)、保存r4-r11和R14这几个寄存器的值。

(8)、将寄存器RO的值写入到寄存器R2所保存的地址中去,也就是将新的栈顶保存在任务控制块的第一个字段中。此时的寄存器RO保存着最新的堆栈栈顶指针值,所以要将这个最新的栈顶指针写入到当前任务的任务控制块第一个字段,而经过(2)和(3)已经获取到了任务控制块,并将任务控制块的首地址写如到了寄存器R2中。

(9)、将寄存器 R3 的值临时压栈,寄存器 R3 中保存了当前任务的任务控制块,而接下来要调用函数vTaskSwitchContext(),为了防止R3的值被改写,所以这里临时将R3的值先压栈。

(10)和(11)、关闭中断,进入临界区。

(12)、调用函数vTaskSwitchContext(),此函数用来获取下一个要运行的任务,并将pxCurrentTCB更新为这个要运行的任务。

(13)和(14)、打开中断,退出临界区。

(15)、刚保存的寄存器R3的值出栈,恢复寄存器R3的值。注意,经过(12)步,此时pxCurrentTCB的值已经改变了,所以读取R3所保存的地址处的数据就会发现其值改变了,成为了下一个要运行的任务的任务控制块。

(16)和(17)、获取新的要运行的任务的任务堆栈栈顶,并将栈顶保存在寄存器R0中。

(18)、R4-R11,R14出栈,也就是即将运行的任务的现场。

(19)、 (20)和(21)、判断即将运行的任务是否有使用到FPU,如果有的话还需要手工恢复FPU的 s16~s31 寄存器。

(22)、更新进程栈指针PSP的值。

(23)、执行此行代码以后硬件自动恢复寄存器RO-R3、 R12、LR、PC和xPSR的值,确定异常返回以后应该进入处理器模式?还是进程模式?,使用主栈指针(MSP)?还是进程栈指针(PSP)?。很明显这里会进入进程模式,并且使用进程栈指针(PSP),寄存器PC值会被恢复为即将运行的任务的任务函数,新的任务开始运行!至此,任务切换成功。

总结:将当前运行的任务的寄存器保存到栈中,再将就绪任务的数据从栈中保存到寄存器,然后运行。

四、查找下一个要运行的任务的两种方法

1、获取下一个要运行的任务

        在PendSV中断服务程序中有调用函数vTaskSwitchContext()来获取下一个要运行的任务,也就是查找已经就绪了的优先级最高的任务:

(1)、如果调度器挂起那就不能进行任务切换。

(2)、调用函数taskSELECT_HIGHEST_PRIORITY_TASK()获取下一个要运行的任务。

2、查找下一个要运行的任务的两种方法

2.1、通用方法:所有处理器都可以使用的方法

(1) 从就绪任务列表找到优先级最高的就绪任务。

(2) 使用函数listGET_OWNER_OF_NEXT_ENTRY()来获取列表中的下一个列表项,然后将获取到的列表项所对应的任务控制块赋值给pxCurrentTCB,这样我们就确定了下 一个要运行的任务了。

2.2、硬件方法:需要硬件支持的方法

        硬件方法就是使用处理器自带的硬件指令来实现的,比如Cortex-M处理器就带有的计算前导0个数指令: CLZ,函数如下:

(1)、通过函数 portGET_HIGHEST_PRIORITY() 获取处于就绪态的最高优先级。

(2)、使用函数listGET_OWNER_OF_NEXT_ENTRY()来获取列表中的下一个列表项,然后将获取到的列表项所对应的任务控制块赋值给pxCurrentTCB,这样我们就确定了下一个要运行的任务了。

        可以看出硬件方法借助一个指令就可以快速的获取处于就绪态的最高优先级,但是会限制任务的优先级数,比如STM32只能有 32 个优先级,不过 32 个优先级已经完全够用了。要知道FreeRTOS是支持时间片的,每个优先级可以支持无限多个任务。

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

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

相关文章

Windows系统安装TortoiseSVN并结合内网穿透实现远程访问本地服务器——“cpolar内网穿透”

文章目录 前言1. TortoiseSVN 客户端下载安装2. 创建检出文件夹3. 创建与提交文件4. 公网访问测试 前言 TortoiseSVN是一个开源的版本控制系统,它与Apache Subversion(SVN)集成在一起,提供了一个用户友好的界面,方便用…

ThreeDWorld(TDW)学习(待更新)

目录 前言 1.TDW 2.transport challenge 总结 前言 因为挑战赛了解到tdw仿真平台。 想了解的请点击: GitHub - threedworld-mit/tdw: ThreeDWorld simulation environment GitHub - chuangg/tdw-transport-challenge-starter-code 1.TDW ThreeDWorld (TDW)是一…

数据卷dockerfile

目录 一、数据卷 1. 简介 2. 数据卷和数据卷容器 1. 数据卷: 2. 数据卷容器: 二、自定义镜像 1. 作用 2. 自定义centos 3. 自定义tomcat8 一、数据卷 1. 简介 数据卷是一个可供一个或多个容器使用的特殊目录,它将主机操作系统目录直…

mysql修改字段的长度锁表问题

mysql修改字段的长度锁表问题 背景 MySQL(这里指5.6及其后续版本)修改字段的长度锁表会锁表吗?答案是可能会但不一定会 具体原理 MySQL 5.6 及以后版本扩大字段长度 支持 online ddl in-place 模式,而这将不会锁表。varchar 表示…

string字符串进行分割

c标准库中&#xff0c;对string字符串并没有提供分割操作&#xff0c;需要自己手动实现此功能。 方式1&#xff1a; 采用 std::stringstream 输入字符串&#xff0c;通过getline()函数&#xff0c;来对字符串进行分割。 #include <sstream>void getSplit(std::string s…

Unity—MVC分层开发思想

每日一句&#xff1a;当你不努力的时候&#xff0c;天赋就会一点一点被收回 目录 MVC分层开发思想 MVC是什么 MVC的开发步骤 案例&#xff1a;点击按钮实现金币进行添加&#xff0c;并且把金币记录到JSON里 MVC模式实现 背包系统基础代码 背包项目实现步骤 MVC分层开发思…

【vue+element ui】大屏自适应中el-select下拉内容在低分辨率下显示不全问题解决

目录 背景 现象 解决方案 背景 最近要把一个1920px*1080px的大屏改成自适应的&#xff1b;最低适配到1028px*720px&#xff1b; 现象 自适应适配改完之后 将电脑屏幕改成1028px*720px分辨率后&#xff0c;下拉显示正常 通过谷歌浏览器设置Toggle device toolbar为1028px*…

Fastjson2 <== 2.0.26反序列漏洞

根据Y4TACKER师傅在2023-03-20发布了一篇关于Fastjson原生反序列化的文章&#xff0c;文章中引入注目的是利用条件限制条件&#xff0c;不常常关注漏洞预警或者内容的几乎都是未发觉Fastjson2 到Fastjson2 2.0.26版本都有问题&#xff0c;其实如果单独去使用一些关键词去搜索&a…

Aws Ec2服务器设置密码登录

通过密钥&#xff0c;ssh登录到服务器 切换到root sudo -i开始设置root的新密码 passwd root输入并确认新密码即可 5.修改ssh配置文件 vim /etc/ssh/sshd_config6.重启sshd配置 systemctl restart sshd

QML中动态增加表格数据

1.QML中的表格实现 import QtQuick 2.15 import QtQuick.Window 2.15import QtQuick.Controls 2.0 import Qt.labs.qmlmodels 1.0 import QtQuick.Layouts 1.15Window {width: 640height: 480visible: truetitle: qsTr("Hello World")TableModel{id:table_modelTabl…

接口测试-幂等测试

我们知道一个网站的访问中会有很多各种各样的接口请求 比如说拿一个购物网站来说&#xff0c;有注册&#xff0c;有登录&#xff0c;有浏览商品&#xff0c;有添加购物车&#xff0c;查询购物车商品这些接口&#xff0c;还有一类特殊的接口&#xff0c;比如&#xff1a;支付。…

【JavaEE进阶】 Spring AOP详解

文章目录 &#x1f38b;前言&#x1f38d;Spring AOP核心概念&#x1f6a9;切点(Pointcut)&#x1f6a9;连接点(Join Point)&#x1f6a9;通知(Advice)&#x1f6a9;切面(Aspect) &#x1f340;通知类型&#x1f6a9;注意事项 &#x1f332;PointCut&#x1f384;切面优先级Ord…

深入理解Linux线程(LWP):概念、结构与实现机制(1)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;会いたい—Naomile 1:12━━━━━━️&#x1f49f;──────── 4:59 &#x1f504; ◀️ ⏸ ▶️ ☰ &a…

vue 解决:点击左侧相同菜单,右侧页面不重新加载的问题

1、问题描述&#xff1a; 其一、需求为&#xff1a; 无论是通过路由组件形成的平台管理系统&#xff0c;还是通过文件配置形成的平台管理系统&#xff0c;都存在通过切换左侧的导航栏而使右侧的页面切换的业务需求&#xff1b; 其二、问题描述为&#xff1a; A、步骤一&#…

基于RISC-V架构的通信DSP的设计以及在5G RedCap基带中的应用(五)-基于RISC-V的RedCap DSP在5G基带中的应用

4 基于RISC-V的RedCap DSP在5G基带中的应用 4.1 基带处理器的关键任务和性能需求 基带处理器是移动通信设备中的关键部件&#xff0c;负责处理无线信号&#xff0c;包括信号的接收、发送和处理。在5G通信系统中&#xff0c;基带处理器的关键任务和性能需求包括以下几个方面&a…

【Linux C | 网络编程】gethostbyname 函数详解及C语言例子

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

就业班 2401--2.29 Linux Day8--存储管理2(LVM)+swap+磁盘阵列raid

&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;小伙伴们一定要看到最后&#xff0c;有彩蛋呢^--^ 一、存储管理Ⅱ 逻辑卷LVM &#xff08;Logical Volume Manager&#xff08;逻辑卷管理&#xff09;的简写&#xff09; LVM管理 lvm概念&#xf…

代理IP如何帮助领英账号预防封号限制?

LinkedIn是跨境外贸必备的拓客工具&#xff0c;世界各地的许多专业人士都使用领英来作为发布和共享内容的主要工具&#xff0c;这使得它成为跨境出海必备的渠道工具。 但是不少做外贸的朋友都知道&#xff0c;领英账号很容易遭遇限制封禁&#xff0c;但如果善用工具&#xff0…

单点登录的三种方式

前言 在B/S系统中&#xff0c;登录功能通常都是基于Cookie 来实现的。当用户登录成功后&#xff0c;一般会将登录状态记录到Session中&#xff0c;或者是给用户签发一个 Token&#xff0c;无论哪一种方式&#xff0c;都需要在客户端保存一些信息(Session ID或Token)&#xff0…

redis-RedisTemplate.opsForGeo 的geo地理位置及实现附近的人的功能

redis内部使用的是 zset 数据结构存储&#xff0c;如下 import cn.huawei.VideoApplication; import cn.huawei.domain.Jingqu; import cn.huawei.service.JingquService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired…