FreeRTOS的学习(十四)——PendSV异常

2023-05-16

FreeRTOS的学习系列文章目录

FreeRTOS的学习(一)——STM32上的移植问题
FreeRTOS的学习(二)——任务优先级问题
FreeRTOS的学习(三)——中断机制
FreeRTOS的学习(四)——列表
FreeRTOS的学习(五)——系统延时
FreeRTOS的学习(六)——系统时钟
FreeRTOS的学习(七)——1.队列概念
FreeRTOS的学习(七)——2.队列入队源码分析
FreeRTOS的学习(七)——3.队列出队源码分析
FreeRTOS的学习(八)——1.二值信号量
FreeRTOS的学习(八)——2.计数型信号量
FreeRTOS的学习(八)——3.优先级翻转问题
FreeRTOS的学习(八)——4.互斥信号量
FreeRTOS的学习(九)——软件定时器
FreeRTOS的学习(十)——事件标志组
FreeRTOS的学习(十一)——任务通知


目录

  • FreeRTOS的学习系列文章目录
  • 前言
  • 1 PendSV异常
  • 2 FreeRTOS 任务切换场合
    • 2.1 执行系统调用
    • 2.2 系统滴答定时器(SysTick)中断
  • 3 PendSV中断函数
  • 4 时间片调度


前言

本文将从任务切换的角度出发,学习PendSV异常的相关概念。


1 PendSV异常

正常情况下,任务的切换需要具有实时性的作用,并且不能影响到其他优先级更高的任务。因此不难想象,可以使用一个优先级最低的中断来完成任务的切换操作。
PendSV称为可悬起的系统调用,这与SVC不同,SVC异常是必须被立即响应的,如若不然,就会产生硬件错误。而PendSV异常是可以像普通中断一样根据优先级从而判断是否执行。此外,PendSV的异常实现也很简单,只要像地址为0xe000ed04的中断控制和状态寄存器(ICSR)的bit28位置1悬起PendSV,从而引起PendSV异常。


2 FreeRTOS 任务切换场合

2.1 执行系统调用

执行系统调用就是执行FreeRTOS系统提供的相关API函数,比如任务切换函数taskYIELD(),FreeRTOS 有些 API 函数也会调用函数 taskYIELD(),这些 API 函数都会导致任务切换,这些 API 函数和任务切换函数 taskYIELD()都统称为系统调用。

PendSV异常的代码最终都会调用portYIELD,其中主要的操作就是将ICSR的bit28置1,并且对数据和指令进行隔离,保证PendSV的悬起。

#define portYIELD()                                 \
    {                                                   \
        portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
        /*数据和指令隔离指令,确保之前指令确实执行*/ \
        __dsb( portSY_FULL_READ_WRITE );                           \
        __isb( portSY_FULL_READ_WRITE );                           \
    }

当然 上述的情况属于任务级的任务切换,如果是中断级的任务切换,首先会根据中断函数中是否存在更高优先级的任务产生,从而有一个返回值,该返回值如果为真,则需要进行任务切换,同样是调用portYILED。

2.2 系统滴答定时器(SysTick)中断

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

void xPortSysTickHandler( void )
{
    //执行SysTick_Handler中断函数时,为了保证在freertos中属于最低优先级的此中断能顺利执行,
    //故要关闭FreeRTOS的所有可管理中断,保证系统计数时不被打断。
    vPortRaiseBASEPRI();  //关中断
    {
        /* Increment the RTOS tick. */
        if( xTaskIncrementTick() != pdFALSE )  //判断返回值,如果为pdTURE就要进行一次上下文切换
        {
            portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
        }
    }
    vPortClearBASEPRIFromISR();  //开中断
}

xTaskIncrementTick函数:当有阻塞的任务计时时间到了的时候,如果任务优先级更高的话就会需要进行任务切换,其返回值为pdTURE。
此外还有一种情况:抢占功能以及时间片调度功能都开启的话,也会根据情况对xTaskIncrementTick函数的返回值进行操作。
具体关于时间片调度的说明将在下面给出。


3 PendSV中断函数

通过以上的说明,可以发现,FreeRTOS的任务切换都是在PendSV中断函数中进行的。
其源码如下:

__asm void xPortPendSVHandler( void )
{
    extern uxCriticalNesting;
    extern pxCurrentTCB;
    extern vTaskSwitchContext;

/* *INDENT-OFF* */
    PRESERVE8

    mrs r0, psp
    isb

    ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */
    ldr r2, [ r3 ]

    stmdb r0 !, { r4 - r11 } /* Save the remaining registers. */
    str r0, [ r2 ] /* Save the new top of stack into the first member of the TCB. */

    stmdb sp !, { r3, r14 }
    mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
    msr basepri, r0
    dsb
    isb
    bl vTaskSwitchContext
    mov r0, #0
    msr basepri, r0
    ldmia sp !, { r3, r14 }

    ldr r1, [ r3 ]
    ldr r0, [ r1 ] /* The first item in pxCurrentTCB is the task top of stack. */
    ldmia r0 !, { r4 - r11 } /* Pop the registers and the critical nesting count. */
    msr psp, r0
    isb
    bx r14
    nop
/* *INDENT-ON* */
}

(1)、读取进程栈指针,保存在寄存器 r0 里面。
(2)(3)、获取当前任务的任务控制块,并将任务控制块的地址保存在寄存器 r2 里面。
(4)、保存 r4~r11 和 r14 这几个寄存器的值。
(5)、将寄存器r0 的值写入到寄存器 r2 所保存的地址中去,也就是将新的栈顶保存在任务控制块的第一个字段中。此时的寄存器 r0 保存着最新的堆栈栈顶指针值,所以要将这个最新的栈顶指针写入到当前任务的任务控制块第一个字段,而经过(2)和(3)已经获取到了任务控制块,并将任务控制块的首地址写如到了寄存器 r2 中。
(6)、将寄存器 r3 和 r14 的值临时压栈,寄存器 r3 中保存了当前任务的任务控制块,而接下来要调用函数 vTaskSwitchContext(),为了防止 R3 和R14 的值被改写,所以这里临时将 r3和r14 的值先压栈。
(7)(8)、关闭中断,进入临界区。
(9)、调用函数 vTaskSwitchContext(),此函数用来获取下一个要运行的任务,并将pxCurrentTCB更新为这个要运行的任务。
(10)(11)、打开中断,退出临界区。
(12)、刚刚保存的寄存器 r3 和r14 的值出栈,恢复寄存器 r3 和r14 的值。注意,经过(12)步,此时 pxCurrentTCB的值已经改变了,所以读取 r3 所保存的地址处的数据就会发现其值改变了,成为了下一个要运行的任务的任务控制块。
(13)(14)、获取新的要运行的任务的任务堆栈栈顶,并将栈顶保存在寄存器 r0 中。
(15)、r4~r11,r14 出栈,也就是即将运行的任务的现场。
(16)、更新进程栈指针 PSP 的值。
(17)、执行此行代码以后硬件自动恢复寄存器r0~r3、r12、LR、PC 和 xPSR的值,确定异常返回以后应该进入处理器模式还是进程模式,使用主栈指针(MSP)还是进程栈指针(PSP)。很明显这里会进入进程模式,并且使用进程栈指针(PSP),寄存器PC 值会被恢复为即将运行的任务的任务函数,新的任务开始运行!至此,任务切换成功。

任务切换的大致过程可以表述如下:任务A切换前先将cpu使用过程中的一些寄存器的值保存到堆栈里面(现场保护),过程中操作栈顶指针(保存在TCB中)。当要运行任务B时,调用函数 vTaskSwitchContext(),此函数用来获取下一个要运行的任务,并将 pxCurrentTCB 更新为这个要运行的任务,然后从任务堆栈中取出来这些寄存器值,赋给相应的寄存器,cpu开始执行。


4 时间片调度

在 FreeRTOS 中允许一个任务运行一个时间片(一个时钟节拍的长度)后让出 CPU 的使用权,让拥有同优先级的下一个任务运行。
要使用时间片调度的话宏 configUSE_PREEMPTION和宏 configUSE_TIME_SLICING必须为 1。时间片的长度由宏 configTICK_RATE_HZ 来确定,一个时间片的长度就是滴答定时器的中断周期,比如本教程中 configTICK_RATE_HZ 为 1000,那么一个时间片的长度就是 1ms。
时间片调度发生在滴答定时器的中断服务函数中,即xTaskIncrementTick函数:

#if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
        {
            if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
            {
                xSwitchRequired = pdTRUE;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
#endif

可以看到,通过listCURRENT_LIST_LENGTH函数判断当前任务所对应的优先级下是否还有其他的任务。如果当前任务所对应的任务优先级下还有其他的任务那么就返回 xSwitchRequired = pdTRUE。
即函数xTaskIncrementTick() 就 会 返 回 pdTURE , 由 于 函 数 返 回 值 为 pdTURE 因 此 函 数
xPortSysTickHandler()就会进行一次任务切换。从而就可以调度到同优先级的其他任务中去了,当然,如果此时有更高的优先级任务要运行,则会执行优先级更高的任务,此为抢占。


关于任务查找的相关文档可以查看FreeRTOS的学习(二)——任务优先级问题

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS的学习(十四)——PendSV异常 的相关文章

  • FreeRTOS内核配置说明---FreeRTOS Kernel V10.2.1

    FreeRTOS内核是高度可定制的 使用配置文件FreeRTOSConfig h进行定制 每个FreeRTOS应用都必须包含这个头文件 用户根据实际应用来裁剪定制FreeRTOS内核 这个配置文件是针对用户程序的 而非内核 因此配置文件一般
  • FreeRTOS快速上手

    FreeRTOS使用 一 源码下载和移植文件提取 1 1 源码下载 在网站https sourceforge net projects freertos 可以找到freertos最新的源码 1 2 移植文件提取 根据第一步 我们会得到一个f
  • STM32CubeMX+FreeRTOS学习笔记(一)

    嵌入式实时操作系统FreeRTOS 基本概述 在嵌入式领域当中 实时操作系统的应用越来越广泛了 目前嵌入式操作系统种类很多 例如 Clinux C OS II C OS III FreeRTOS RT Thread等等 这篇文章所记录的就是
  • 【FreeRTOS】多任务创建

    作者主页 凉开水白菜 作者简介 共同学习 互相监督 热于分享 多加讨论 一起进步 专栏资料 https pan baidu com s 1nc1rfyLiMyw6ZhxiZ1Cumg pwd free 点赞 收藏 再看 养成习惯 订阅的粉丝
  • FreeRTOS学习(八) 延时函数

    声明及感谢 跟随正点原子资料学习 在此作为学习的记录和总结 环境 keil stm32f103 FreeRTOS延时函数有两个 分别是 vTaskDelay vTaskDelayUntil 1 vTaskDelay 任务相对延时 函数原型
  • Freertos中vTaskDelay()是怎么用的

    1 常见的使用场景 void vLED Task void pvParameters while 1 Heartbeat LED vTaskDelay 1000 portTICK RATE MS 说明 上面这段代码的意思是 led翻转后经过
  • FreeRTOS系列

    1 RTOS简介 RTOS全称为 Real Time Operation System 即实时操作系统 RTOS强调的是实时性 又分为硬实时和软实时 硬实时要求在规定的时间内必须完成操作 不允许超时 而软实时里对处理过程超时的要求则没有很严
  • FreeRTOS ------- 任务(task)

    在学习RTOS的时候 个人觉得带着问题去学习 会了解到更多 1 什么是任务 在FreeRTOS中 每个执行线程都被称为 任务 每个任务都是在自己权限范围内的一个小程序 其具有程序入口每个任务都是在自己权限范围内的一个小程序 其具有程序入口通
  • FreeRTOS+CubeMX系列第一篇——初识FreeRTOS

    文章目录 一 关于FreeRTOS 二 FreeRTOS的特点 三 如何在CubeMX上配置FreeRTOS 四 FreeRTOS文档资料 五 同系列博客 一 关于FreeRTOS 1 什么是FreeRTOS FreeRTOS是一个迷你的实
  • 【FreeRTOS(三)】任务状态

    文章目录 任务状态 任务挂起 vTaskSuspend 取消任务挂起 vTaskResume 挂起任务调度器 vTaskSuspendAll 取消挂起任务调度器 xTaskResumeAll 代码示例 任务挂起 取消任务挂起 代码示例 挂起
  • freeRTOS使用uxTaskGetStackHighWaterMark函数查看任务堆栈空间的使用情况

    摘要 每个任务都有自己的堆栈 堆栈的总大小在创建任务的时候就确定了 此函数用于检查任务从创建好到现在的历史剩余最小值 这个值越小说明任务堆栈溢出的可能性就越大 FreeRTOS 把这个历史剩余最小值叫做 高水位线 此函数相对来说会多耗费一点
  • FreeRTOS,串口中断接收中使用xQueueOverwriteFromISR()函数,程序卡死在configASSERT

    原因 UART的中断优先级设置的太高 高于了configMAX SYSCALL INTERRUPT PRIORITY宏定义的安全中断等级 UART的中断等级小于等于宏定义的优先等级即可
  • 啊哈C的简单使用

    打开啊哈C 新建一个程序输出hello world include
  • FreeRTOS学习---“定时器”篇

    总目录 FreeRTOS学习 任务 篇 FreeRTOS学习 消息队列 篇 FreeRTOS学习 信号量 篇 FreeRTOS学习 事件组 篇 FreeRTOS学习 定时器 篇 FreeRTOS提供了一种软件定时器 用来快速实现一些周期性的
  • 单片机通信数据延迟问题排查

    1 问题说明 笔者在最近的项目中 发现系统的响应延迟较高 经过排查 排除了单片机运行卡死的问题 2 原因分析 具体排查过程这里就不细致说明了 直接给出排查后原因 任务执行周期规划不合理 导致freertos队列发送接收到的命令有延迟 为了便
  • STM32 Freertos 添加 外部sram heap_5.c

    1 添加外部SRAM 初始化 2 添加heap 5 c 3 初始化heap 5 c 外部堆栈 Define the start address and size of the two RAM regions not used by the
  • FreeRTOS实时操作系统(三)任务挂起与恢复

    系列文章 FreeRTOS实时操作系统 一 RTOS的基本概念 FreeRTOS实时操作系统 二 任务创建与任务删除 HAL库 FreeRTOS实时操作系统 三 任务挂起与恢复 FreeRTOS实时操作系统 四 中断任务管理 FreeRTO
  • FreeRTOS多任务调度器基础

    Cortex M4中SysTick调度器核心 Cortex M4中的中断管理 Cortex M4中影子栈指针 Cortex M4中SVC和PendSV异常 1 Cortex M4中SysTick调度器核心 systick每一次中断都会触发内
  • FreeRTOS 配置TICK_RATE_HZ

    我使用的是带有 5 4 版 FreeRTOS 的 MSP430f5438 我有一个有趣的问题 我无法弄清楚 基本上 当我将 configTICK RATE HZ 设置为不同的值时 LED 闪烁得更快或更慢 它应该保持相同的速率 我将 con
  • 如何将 void* 转换为函数指针?

    我在 FreeRTOS 中使用 xTaskCreate 其第四个参数 void const 是传递给新线程调用的函数的参数 void connect to foo void const task params void on connect

随机推荐

  • Gazebo-Ros搭建小车和场景并运行slam算法进行建图4--为机器人添加运动控制器控制其移动

    Gazebo Ros搭建小车和场景并运行slam算法进行建图4 为机器人添加运动控制器控制其移动 1 要想机器人小车在gazebo中运动还需要为其添加运动插件 在文章3中的my robot2 urdf 最下边 xff08 前边 xff09
  • keil 函数点击不能跳转到函数的定义之解决方案

    当右键点击一个函数名并点击Go To Definition Of xxx时 xff0c 没有达到我们预期的效果 显示如下 xff1a 那么解决方法一 xff1a 重新编译一遍整个工程 xff0c 再试试 xff1b 解决方法二 xff1a
  • “字符串的结束标志是‘\0‘,编译器自动在字符串末尾添加”

    字符串的结束标志是 0 xff0c 编译器自动在字符串末尾添加 探究 xff1a 字符串的结束标志是 0 xff0c 编译器自动在字符串末尾添加 编译器 xff1a 编译器就是将 一种语言 xff08 通常为高级语言 xff09 翻译为 另
  • PX4中MPU6000数据读取程序的实现过程

    MPU6000 measure 函数解析 MPU6000 measure mpu report 原始数据结构体对象 report 整合后数据结构体对象 interface gt read MPU6000 SET SPEED MPUREG I
  • 计算机网络(谢希仁 第七版) 数据链路层 个人笔记

    写此博文目的 xff1a 整理知识点方便自己以后复习和深入的学习 数据链路层 1 数据链路 xff1a 除了物理线路外 xff0c 还必须有通信协议来控制这些数据的传输 xff0c 若把这些协议的软件和硬件加到链路上 xff0c 就构成了数
  • 初始视觉里程计

    起因 临近大四的时候 xff0c 被告知毕业设计要做与机器人相关的题目 于是导师给了一个足球场上实现移动机器人视觉自定位的功能 拿到这个题目 xff0c 万般无奈 xff0c 毫无头绪 xff0c 身边的人也没有搞过这个的 xff0c 根本
  • 三相电机驱动电路详解

    最近又开始接触驱动这块儿的电路了 xff0c 好久没学 xff0c 又有点忘了 xff0c 特此记录 驱动MOSFET xff0c 可以选用专用MOSFET驱动IC完成电平转换和驱动 因为MOSFET的栅 源极之间存在寄生电容 xff0c
  • AD2S1210的使用总结

    目录 前言一 AD2S1210工作原理1 旋变信号2 旋变 数字转换3 TYPE II跟踪环路 二 程序设计部分1 初始化2 向AD2S1210中写入数据3 从AD2S1210中读取数据 总结2022年3月8日补充2022年3月31日补充
  • 永磁同步电机MTPA与id=0的控制原理

    目录 MTPA控制方式与id 61 0控制方式的区别 MTPA控制方式与id 61 0控制方式的区别 永磁同步电动机主要可分为 xff1a 表面式和内置式 在表贴式永磁同步电动机中 xff0c 永磁体通常呈瓦片形 xff0c 并位于转子铁心
  • ADB连接Android设备的三种方法

    ADB连接Android设备的三种方法 连接方式有三种方法 xff1a 一 WiFi连接 xff08 手机与pc同一个局域网下 xff09 与电脑在同一局域网内 xff0c Android设备连接WiFi xff0c 然后adb命令 adb
  • 关于电机转子初始位置检测的方法

    目录 电机转子检测的目的对位置的几种方法使用d轴电流吸合时的电角度解算使用q轴电流吸合时的电角度解算总结 电机转子检测的目的 电机实现闭环需要电机的转速和转子实际位置的反馈量 其中对于转子位置的反馈量最为麻烦 xff0c 因为电机的转子检测
  • FreeRTOS的学习(三)——中断机制

    FreeRTOS的学习系列文章目录 FreeRTOS的学习 xff08 一 xff09 STM32上的移植问题 FreeRTOS的学习 xff08 二 xff09 任务优先级问题 FreeRTOS的学习 xff08 三 xff09 中断机制
  • 基于F28335的Simulink代码生成(七)——成果展示

    基于F28335的Simulink代码生成系列文章目录 基于F28335的Simulink代码生成 xff08 一 xff09 搞懂模型的运行逻辑 基于F28335的Simulink代码生成 xff08 二 xff09 EPWM模块同步设置
  • FreeRTOS的学习(五)——系统延时

    FreeRTOS的学习系列文章目录 FreeRTOS的学习 xff08 一 xff09 STM32上的移植问题 FreeRTOS的学习 xff08 二 xff09 任务优先级问题 FreeRTOS的学习 xff08 三 xff09 中断机制
  • FreeRTOS的学习(六)——系统时钟

    FreeRTOS的学习系列文章目录 FreeRTOS的学习 xff08 一 xff09 STM32上的移植问题 FreeRTOS的学习 xff08 二 xff09 任务优先级问题 FreeRTOS的学习 xff08 三 xff09 中断机制
  • FreeRTOS的学习(七)——2.队列入队源码分析

    FreeRTOS的学习系列文章目录 FreeRTOS的学习 xff08 一 xff09 STM32上的移植问题 FreeRTOS的学习 xff08 二 xff09 任务优先级问题 FreeRTOS的学习 xff08 三 xff09 中断机制
  • 温故知新(六)——状态观测器

    目录 1 什么是状态观测器 2 Luenberger状态观测器 1 什么是状态观测器 为了对系统实现状态反馈 xff0c 状态观测器应运而生 状态观测器是一种通过原受控系统的输入 输出量来重新构建一个与原系统相似的动态系统 它的输出信号的状
  • FreeRTOS的学习(八)——4.互斥信号量

    FreeRTOS的学习系列文章目录 FreeRTOS的学习 xff08 一 xff09 STM32上的移植问题 FreeRTOS的学习 xff08 二 xff09 任务优先级问题 FreeRTOS的学习 xff08 三 xff09 中断机制
  • FreeRTOS的学习(十三)——任务创建

    FreeRTOS的学习系列文章目录 FreeRTOS的学习 xff08 一 xff09 STM32上的移植问题 FreeRTOS的学习 xff08 二 xff09 任务优先级问题 FreeRTOS的学习 xff08 三 xff09 中断机制
  • FreeRTOS的学习(十四)——PendSV异常

    FreeRTOS的学习系列文章目录 FreeRTOS的学习 xff08 一 xff09 STM32上的移植问题 FreeRTOS的学习 xff08 二 xff09 任务优先级问题 FreeRTOS的学习 xff08 三 xff09 中断机制