FreeRTOS学习 --- 任务调度

news2025/2/1 23:24:51

开启任务调度器

        作用:用于启动任务调度器,任务调度器启动后, FreeRTOS 便会开始进行任务调度  

该函数内部实现,如下:

        1、创建空闲任务(优先级最低)

        2、如果使能软件定时器,则创建定时器任务(优先级最高)

        3、关闭中断,防止调度器开启之前或过程中,受中断干扰,会在运行第一个任务时打开中断(在SVC中断中,通过设置basepri 为 0 来开启中断)

        4、初始化全局变量,并将任务调度器的运行标志设置为已运行

        5、初始化任务运行时间统计功能的时基定时器

        6、调用函数 xPortStartScheduler()完成启动任务调度器中与硬件架构相关的配置部分,以及启动第一个任务

      xPortStartScheduler()

        作用:该函数用于完成启动任务调度器中与硬件架构相关的配置部分,以及启动第一个任务

该函数内部实现,如下:

        1、检测用户在 FreeRTOSConfig.h 文件中对中断的相关配置是否有误

        2、配置 PendSV SysTick 的中断优先级为最低优先级

        3、调用函数 vPortSetupTimerInterrupt()配置 SysTick

        4、初始化临界区嵌套计数器为 0

        5、调用函数 prvEnableVFP()使能 FPU(M3中不支持FPU浮点单元)

        6、调用函数 prvStartFirstTask()启动第一个任务

        prvStartFirstTask()

        函数 prvStartFirstTask()用于初始化启动第一个任务前的环境,主要是重新设置 MSP 指针,并使能全局中断。

       1. 首先是使用了 PRESERVE8,进行 8 字节对齐,这是因为,栈在任何时候都是需要 4 字节对齐的,而在调用入口得 8 字节对齐,在进行 C 编程的时候,编译器会自动完成的对齐的操作,而对于汇编,就需要开发者手动进行对齐。

        2.获得 MSP 指针的初始值

ldr r0, =0xE000ED08    /* 0xE000ED08 为 VTOR 地址 */
ldr r0, [ r0 ]         /* 获取 VTOR 的值 */
ldr r0, [ r0 ]         /* 获取 MSP 的初始值 */

(1) 什么是 MSP 指针?

        程序在运行过程中需要一定的栈空间来保存局部变量等一些信息。当有信息保存到栈中时, MCU 会自动更新 SP 指针,使 SP 指针指向最后一个入栈的元素,那么程序就可以根据 SP 指针来从栈中存取信息。对于正点原子的 STM32F1、 STM32F4、 STM32F7 和 STM32H7 开发板上使用的 ARM Cortex-M 的 MCU 内核来说, ARM Cortex-M 提供了两个栈空间, 这两个栈空间的堆栈指针分别是 MSP(主堆栈指针) 和 PSP(进程堆栈指针)在 FreeRTOS 中 MSP 是给系统栈空间使用的,而 PSP 是给任务栈使用的,也就是说, FreeRTOS 任务的栈空间是通过 PSP 指向的,而在进入中断服务函数时,则是使用 MSP 指针。当使用不同的堆栈指针时, SP 会等于当前使用的堆栈指针。

        (2) 为什么是 0xE000ED08?

        0xE000ED08 是 VTOR(向量表偏移寄存器)的地址, VTOR 中保存了向量表的偏移地址。一般来说向量表是从其实地址 0x00000000 开始的,但是在有情况下,可能需要修改或重定向向量表的首地址,因此 ARM Corten-M 提供了 VTOR 对向量表进行从定向。而向量表是用来保存中断异常的入口函数地址,即栈顶地址的,并且向量表中的第一个字保存的就是栈底的地址,在 start_stm32xxxxxx.s 文件中有如下定义:

__Vectors DCD __initial_sp ; 栈底指针
          DCD Reset_Handler ; Reset Handler
          DCD NMI_Handler ; NMI Handler
          DCD HardFault_Handler ; Hard Fault Handler
          DCD MemManage_Handler ; MPU Fault Handler

        以上就是向量表(只列出前几个)的部分内容,可以看到向量表的第一个元素就是栈指针的初始值,也就是栈底指针。

        在了解了这两个问题之后,接下来再来看看代码。首先是获取 VTOR 的地址,接着获取VTOR 的值,也就是获取向量表的首地址,最后获取向量表中第一个字的数据,也就是栈底指针了。

        3. 在获取了栈顶指针后,将 MSP 指针重新赋值为栈底指针。这个操作相当于丢弃了程序之前保存在栈中的数据,因为FreeRTOS从开启任务调度器到启动第一个任务都是不会返回的,是一条不归路,因此将栈中的数据丢弃,也不会有影响。

        4. 重新赋值 MSP 后,接下来就重新使能全局中断,因为之前在函数 vTaskStartScheduler()中关闭了受 FreeRTOS 的中断
        5. 最后使用 SVC 指令,并传入系统调用号 0,触发 SVC 中断。

        SVC中断处理函数vPortSVCHandler()

        当使能了全局中断,并且手动触发 SVC 中断后,就会进入到 SVC 的中断服务函数中。 SVC的中断服务函数为 vPortSVCHandler(),该函数在 port.c 文件中有定义,具体的代码如下所示(这里以正点原子的 STM32F1 系列开发板为例,其他类型的开发板类似):

_asm void vPortSVCHandler( void )
{
    /* 8 字节对齐 */
    PRESERVE8
    /* 获取任务栈地址 */
    ldr r3, = pxCurrentTCB /* r3 指向优先级最高的就绪态任务的任务控制块 */
    ldr r1, [ r3 ] /* r1 为任务控制块地址 */
    ldr r0, [ r1 ] /* r0 为任务控制块的第一个元素(栈顶) */
    /* 模拟出栈,并设置 PSP */
    ldmia r0 !, { r4 - r11 } /* 任务栈弹出到 CPU 寄存器 */
    msr psp, r0 /* 设置 PSP 为任务栈指针 */
    isb
    /* 使能所有中断 */
    mov r0, # 0
    msr basepri,
    /* 使用 PSP 指针,并跳转到任务函数 */
    orr r14, # 0xd
    bx r14
}

        从上面代码中可以看出,函数 vPortSVCHandler()就是用来跳转到第一个任务函数中去的,该函数的具体解析如下:

        1. 首先通过 pxCurrentTCB 获取优先级最高的就绪态任务的任务栈地址,优先级最高的就绪态任务就是系统将要运行的任务。 pxCurrentTCB 是一个全局变量,用于指向系统中优先级最高的就绪态任务的任务控制块
        举个例子:

        定时器处理任务的任务优先级为 31,是系统中优先级最高的任务,因此当进入 SVC 中断时, pxCurrentTCB 就是指向了定时器处理任务的任务控制块。
        接着通过获取任务控制块中的第一个元素,得到该任务的栈顶指针,任务控制块的相关内容

        2. 接下来通过任务的栈顶指针,将任务栈中的内容出栈到 CPU 寄存器中,任务栈中的内容在调用任务创建函数的时候,已经初始化了。然后再设置 PSP 指针,那么,这么一来,任务的运行环境就准备好了。(这里的任务栈顶指针就是最下图里的pxTopOfStack)

        3. 通过往 BASEPRI 寄存器中写 0,允许中断。

        4. 最后通过两条汇编指令,使 CPU 跳转到任务的函数中去执行,代码如下所示:

orr r14, # 0xd
bx r14

        要弄清楚这两条汇编代码,首先要清楚 r14 寄存器是干什么用的。 通常情况下, r14 为链接寄存器(LR),用于保存函数的返回地址。但是在异常或中断处理函数中, r14 为 EXC_RETURN (关于 r14 寄存器的相关内容,感兴趣的读者请自行查阅相关资料), EXC_RETURN 各比特位的描述如下表所示:

        XC_RETURN 只有 6 个合法的值,如下表所示:

        为此时是在 SVC 的中断服务函数中,因此此时的 r14 应为 EXC_RETURN,将 r14 与 0xd作或操作,然后将值写入 r14,那么就是将 r14 的值设置为了 0xFFFFFFFD 或 0xFFFFFFED(具体看是否使用了浮点单元),即返回后进入线程模式,并使用 PSP。这里要注意的是, SVC 中断服务函数的前面,将 PSP 指向了任务栈。
         说了这么多, FreeRTOS 对于进入中断后 r14 为 EXC_RETURN 的具体应用就是,通过判断EXC_RETURN 的 bit4 是否为 0,来判断任务是否使用了浮点单元。

        最后通过 bx r14 指令,跳转到任务的任务函数中执行,执行此指令, CPU 会自动从 PSP 指向的栈中出栈 R0、 R1、 R2、 R3、 R12、 LR、 PC、 xPSR 寄存器, 并且如果 EXC_RETURN 的bit4 为 0(使用了浮点单元),那么 CPU 还会自动恢复浮点寄存器。

出栈/压栈汇编指令详解

任务栈图解:

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

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

相关文章

2025年人工智能技术:Prompt与Agent的发展趋势与机遇

文章目录 一、Prompt与Agent的定义与区别(一)定义(二)区别二、2025年Prompt与Agent的应用场景(一)Prompt的应用场景(二)Agent的应用场景三、2025年Prompt与Agent的适合群体(一)Prompt适合的群体(二)Agent适合的群体四、2025年Prompt与Agent的发展机遇(一)Prompt的…

区块链 智能合约安全 | 回滚攻击

视频教程在我主页简介和专栏里 目录: 智能合约安全 回滚攻击 总结 智能合约安全 回滚攻击 回滚攻击的本质是”耍赖” 举一个简单的例子,两个人玩石头剪刀布,输了的给对方10块钱,现在A输了,A说这把不算,重来 放在Solidity中,require()函数会检测其中的条件是否满…

【JavaEE进阶】图书管理系统 - 壹

目录 🌲序言 🌴前端代码的引入 🎋约定前后端交互接口 🚩接口定义 🍃后端服务器代码实现 🚩登录接口 🚩图书列表接口 🎄前端代码实现 🚩登录页面 🚩…

TensorFlow 简单的二分类神经网络的训练和应用流程

展示了一个简单的二分类神经网络的训练和应用流程。主要步骤包括: 1. 数据准备与预处理 2. 构建模型 3. 编译模型 4. 训练模型 5. 评估模型 6. 模型应用与部署 加载和应用已训练的模型 1. 数据准备与预处理 在本例中,数据准备是通过两个 Numpy 数…

docker安装Redis:docker离线安装Redis、docker在线安装Redis、Redis镜像下载、Redis配置、Redis命令

一、镜像下载 1、在线下载 在一台能连外网的linux上执行docker镜像拉取命令 docker pull redis:7.4.0 2、离线包下载 两种方式: 方式一: -)在一台能连外网的linux上安装docker执行第一步的命令下载镜像 -)导出 # 导出镜像…

Retrieval-Augmented Generation for Large Language Models: A Survey——(1)Overview

Retrieval-Augmented Generation for Large Language Models: A Survey——(1)Overview 文章目录 Retrieval-Augmented Generation for Large Language Models: A Survey——(1)Overview1. Introduction&Abstract1. LLM面临的问题2. RAG核心三要素3. RAG taxonomy 2. Overv…

LabVIEW透镜多参数自动检测系统

在现代制造业中,提升产品质量检测的自动化水平是提高生产效率和准确性的关键。本文介绍了一个基于LabVIEW的透镜多参数自动检测系统,该系统能够在单一工位上完成透镜的多项质量参数检测,并实现透镜的自动搬运与分选,极大地提升了检…

什么是Maxscript?为什么要学习Maxscript?

MAXScript是Autodesk 3ds Max的内置脚本语言,它是一种与3dsMax对话并使3dsMax执行某些操作的编程语言。它是一种脚本语言,这意味着您不需要编译代码即可运行。通过使用一系列基于文本的命令而不是使用UI操作,您可以完成许多使用UI操作无法完成的任务。 Maxscript是一种专有…

Redis|前言

文章目录 什么是 Redis?Redis 主流功能与应用 什么是 Redis? Redis,Remote Dictionary Server(远程字典服务器)。Redis 是完全开源的,使用 ANSIC 语言编写,遵守 BSD 协议,是一个高性…

LeetCode:63. 不同路径 II

跟着carl学算法,本系列博客仅做个人记录,建议大家都去看carl本人的博客,写的真的很好的! 代码随想录 LeetCode:63. 不同路径 II 给定一个 m x n 的整数数组 grid。一个机器人初始位于 左上角(即 grid[0][0]…

Redis-布隆过滤器

文章目录 布隆过滤器的特点:实践布隆过滤器应用 布隆过滤器的特点: 就可以把布隆过滤器理解为一个set集合,我们可以通过add往里面添加元素,通过contains来判断是否包含某个元素。 布隆过滤器是一个很长的二进制向量和一系列随机映射函数。 可以用来检索…

【视频+图文详解】HTML基础3-html常用标签

图文教程 html常用标签 常用标签 1. 文档结构 <!DOCTYPE html>&#xff1a;声明HTML文档类型。<html>&#xff1a;定义HTML文档的根元素。<head>&#xff1a;定义文档头部&#xff0c;包含元数据。<title>&#xff1a;设置网页标题&#xff0c;浏览…

【B站保姆级视频教程:Jetson配置YOLOv11环境(五)Miniconda安装与配置】

Jetson配置YOLOv11环境&#xff08;5&#xff09;Miniconda安装与配置 文章目录 0. Anaconda vs Miniconda in Jetson1. 下载Miniconda32. 安装Miniconda33. 换源3.1 conda 换源3.2 pip 换源 4. 创建环境5. 设置默认启动环境 0. Anaconda vs Miniconda in Jetson Jetson 设备资…

【PLL】杂散生成和调制

时钟生成 --》 数字系统 --》峰值抖动频率生成 --》无线系统 --》 频谱纯度、 周期信号的相位不确定性 随机抖动&#xff08;random jitter, RJ&#xff09;确定性抖动&#xff08;deterministic jitter,DJ&#xff09; 时域频域随机抖动积分相位噪声确定性抖动边带 杂散生成和…

游戏引擎 Unity - Unity 启动(下载 Unity Editor、生成 Unity Personal Edition 许可证)

Unity Unity 首次发布于 2005 年&#xff0c;属于 Unity Technologies Unity 使用的开发技术有&#xff1a;C# Unity 的适用平台&#xff1a;PC、主机、移动设备、VR / AR、Web 等 Unity 的适用领域&#xff1a;开发中等画质中小型项目 Unity 适合初学者或需要快速上手的开…

【C++动态规划 离散化】1626. 无矛盾的最佳球队|2027

本文涉及知识点 C动态规划 离散化 LeetCode1626. 无矛盾的最佳球队 假设你是球队的经理。对于即将到来的锦标赛&#xff0c;你想组合一支总体得分最高的球队。球队的得分是球队中所有球员的分数 总和 。 然而&#xff0c;球队中的矛盾会限制球员的发挥&#xff0c;所以必须选…

python-leetcode-从中序与后序遍历序列构造二叉树

106. 从中序与后序遍历序列构造二叉树 - 力扣&#xff08;LeetCode&#xff09; # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right r…

Java实战:图像浏览器

文章目录 1. 实战概述2. 知识准备3. 实现步骤3.1 创建Java项目3.2 创建图像浏览器类3.2.1 声明变量与常量3.2.2 创建构造方法3.2.3 创建初始化界面方法3.2.4 创建处理事件方法3.2.5 创建主方法3.2.6 查看完整代码 3.3 运行程序&#xff0c;查看结果 4. 实战小结5. 扩展练习 1. …

I.MX6ULL 中断介绍上

i.MX6ULL是NXP&#xff08;原Freescale&#xff09;推出的一款基于ARM Cortex-A7内核的微处理器&#xff0c;广泛应用于嵌入式系统。在i.MX6ULL中&#xff0c;中断&#xff08;Interrupt&#xff09;是一种重要的机制&#xff0c;用于处理外部或内部事件&#xff0c;允许微处理…

(即插即用模块-特征处理部分) 十九、(NeurIPS 2023) Prompt Block 提示生成 / 交互模块

文章目录 1、Prompt Block2、代码实现 paper&#xff1a;PromptIR: Prompting for All-in-One Blind Image Restoration Code&#xff1a;https://github.com/va1shn9v/PromptIR 1、Prompt Block 在解决现有图像恢复模型时&#xff0c;现有研究存在一些局限性&#xff1a; 现有…