FreeRTOS系列|多任务调度

2023-05-16

1. 多任务启动流程

多任务启动流程如下表所示

启动后以下各函数由上至下依次执行含义
osKernelStart()启动内核
vTaskStartScheduler()启动任务调度器
xPortStartScheduler()启动调度器
prvStartFirstTask()启动第一个任务
SVC调用SVC中断

2. 源码分析

  • 启动任务调度器
void vTaskStartScheduler( void ){
  BaseType_t xReturn;
  /* Add the idle task at the lowest priority. */
  #if(configSUPPORT_STATIC_ALLOCATION == 1){
  }
  #else{
	/* 动态创建空闲任务 */
	xReturn = xTaskCreate(prvIdleTask,
						  "IDLE", configMINIMAL_STACK_SIZE,
						  (void *) NULL,
						  (tskIDLE_PRIORITY|portPRIVILEGE_BIT),
						  &xIdleTaskHandle); 
  }
  #endif /* configSUPPORT_STATIC_ALLOCATION */

  if(xReturn == pdPASS){
	/* 关闭中断 */
	portDISABLE_INTERRUPTS();  		
	/* 下一个任务锁定时间赋值为最大,其实就是时间片调度,不让其进行调度 */
	#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
	xNextTaskUnblockTime = portMAX_DELAY;
	/* 调度器的运行状态置位,标记开始运行了 */
	xSchedulerRunning = pdTRUE;
	/* 初始化系统的节拍值为0 */
	xTickCount = ( TickType_t ) 0U;
	/* 启动调度器 */
	if(xPortStartScheduler() != pdFALSE){
	  //如果调度器启动成功就不会执行到这里,所以没有代码
	}
	else{
	  //不会执行到这里,所以没有代码
	}
  }
  else{
	//运行到这里说明系统内核没有启动成功,空闲任务创建失败	
  }
}

  • 启动调度器:FreeRTOS系统时钟是由滴答定时器来提供,任务切换也会用到PendSV中断,这些硬件的初始化在这里完成
BaseType_t xPortStartScheduler( void ){
  /* 为了保证系统的实时性,配置systick和pendsv为最低的优先级 */
  portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
  portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
  /* 配置滴答定时器systick的定时周期,并开启systick中断 */
  vPortSetupTimerInterrupt();
  /* 初始化临界段嵌套计数器 */
  uxCriticalNesting = 0;
  /* 启动第一个任务 */
  prvStartFirstTask();
  /* 代码正常执行的话不会到这里! */
  return 0;
}

  • 启动第一个任务:用于启动第一个任务,是一个汇编函数
__asm void prvStartFirstTask( void ){
  PRESERVE8	//8字节对齐,AAPCS的标准,ARM特有
  /* 将0xE000ED08保存在寄存器R0中;它是中断向量表的一个地址,
     存储的是MSP的指针,最终获取到MSP的RAM的地址 */
  ldr r0, =0xE000ED08
  ldr r0, [r0]	//取R0保存的地址处的值赋给R0
  ldr r0, [r0]	//获取MSP初始值
  /* 重新把MSP的地址,赋值为MSP,相当于复位MSP	*/
  msr msp, r0
  /* 开启全局中断 */
  cpsie i	//使能中断
  cpsie f	//使能中断
  dsb		//数据同步屏障
  isb		//指令同步屏障
  /* 调用SVC  */
  svc 0
  nop
  nop
}


  • 调用SVC中断:在prvStartFirstTask()中通过调用SVC指令触发了SVC中断,而第一个任务的启动就是在SVC中断服务函数中完成的
__asm void vPortSVCHandler(void){
  PRESERVE8//8字节对齐

  /* 获取当前任务控制块 */
  ldr	r3, =pxCurrentTCB
  ldr r1, [r3]	//
  ldr r0, [r1]	//
  /* 出栈内核寄存器,R14其实就是异常返回值 */
  ldmia r0!, {r4-r11, r14}
  /* 进程栈指针PSP设置为任务的堆栈 */
  msr psp, r0
  isb	//指令同步屏障
  /* 把basepri赋值为0,即打开屏蔽中断 */
  mov r0, #0
  msr basepri, r0
  /* 异常退出 */
  bx r14
}

3. 任务切换

3.1 任务切换场合

RTOS系统的核心是任务管理,而任务管理的核心是任务切换,任务切换决定了任务的执行顺序。上下文(任务)切换被触发的场合可以是

  • 系统滴答定时器(SysTick)中断
  • 执行一个系统调用

典型的嵌入式OS系统中,处理器被划分为多个时间片。若系统中只有两个任务,这两个任务会交替执行,任务切换都是在SysTick中断中执行,如下图示:
在这里插入图片描述
在一些OS设计中,为了解决SysTick和IRQ的冲突问题,PendSV异常将上下文切换请求延迟到所有其他IRQ处理都已经完成后,在PendSV异常内执行上下文切换。如下图示:

在这里插入图片描述
PendSV(可挂起的系统调用)异常对OS操作非常重要,其优先级可通过编程设置。可通过将中断控制和状态寄存器ICSR的bit28(挂起位)置1来触发PendSV中断。上面提到过上下文切换被触发的两个场合:SysTick中断和执行一个系统调用,其源码分析如下:

  • SysTick中断
//滴答定时器中断服务函数
void SysTick_Handler(void){
  if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED){ //系统已经运行
	xPortSysTickHandler();
  }
}

void xPortSysTickHandler( void ){
  vPortRaiseBASEPRI();	//关闭中断
  {
	if( xTaskIncrementTick() != pdFALSE ){ //增加时钟计数器xTickCount的值						
	  /* 通过向中断控制和状态寄存器的bit28位写入1挂起PendSV来启动PendSV中断 */
	  portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; 
	}
  }
  vPortClearBASEPRIFromISR();	//打开中断
}

  • 执行一个系统调用
//以任务切换函数taskYIELD()为例
#define taskYIELD()  portYIELD()
#define portYIELD() 
{ 
  /* 通过向中断控制和状态寄存器的bit28位写入1挂起PendSV来启动PendSV中断 */
  portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; 
  __dsb( portSY_FULL_READ_WRITE ); 
  __isb( portSY_FULL_READ_WRITE ); 
}

3.2 PendSV中断服务函数

FreeRTOS任务切换的具体过程是在PendSV中断服务函数中完成的,下面分析PendSV中断服务函数源码,看看切换过程是如何进行的

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

  PRESERVE8

  mrs r0, psp
  isb
  /* 获取当前任务控制块,其实就获取任务栈顶 */
  ldr	r3, =pxCurrentTCB
  ldr	r2, [r3]
  /* 浮点数处理,如果使能浮点数,就需要入栈 */
  tst r14, #0x10
  it eq
  vstmdbeq r0!, {s16-s31}
  /* 保存内核寄存器---调用者需要做的 */
  stmdb r0!, {r4-r11, r14}
  /* 保存当前任务栈顶,把栈顶指针入栈 */
  str r0, [r2]
  stmdb sp!, {r3}
  /* 使能可屏蔽的中断-----临界段 */
  mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
  msr basepri, r0
  dsb
  isb
  /* 执行上线文切换 */
  bl vTaskSwitchContext
  /* 使能可屏蔽的中断 */
  mov r0, #0
  msr basepri, r0
  /* 恢复任务控制块指向的栈顶 */
  ldmia sp!, {r3}
  /* 获取当前栈顶 */
  ldr r1, [r3]
  ldr r0, [r1]
  /* 出栈*/
  ldmia r0!, {r4-r11, r14}
  /* 出栈*/
  tst r14, #0x10
  it eq
  vldmiaeq r0!, {s16-s31}
  /* 更新PSP指针 */
  msr psp, r0
  isb
  /* 异常返回,下面要执行的代码,就是要切换的任务代码了 */
  bx r14
  nop
  nop
}

在PendSV中断服务函数中有调用函数vTaskSwitchContext来获取下一个要运行的任务,其源码如下

void vTaskSwitchContext( void ){
  if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE ){
	/* 标记调度器状态*/
	xYieldPending = pdTRUE;
  }
  else{
	/* 标记调度器状态*/
	xYieldPending = pdFALSE;
	/* 检查任务栈是否溢出 */
	taskCHECK_FOR_STACK_OVERFLOW();
	/* 选择优先级最高的任务,把当前的任务控制块进行赋值 */
	taskSELECT_HIGHEST_PRIORITY_TASK();
  }
}

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

FreeRTOS系列|多任务调度 的相关文章

  • 浮点数在计算机中的表示,程序中浮点数的取值和比较。

    小数的十进制 二进制转换 十进制 gt 二进制 整数部分除2取余 xff0c 小数部分乘2取整 考虑 8 25 整数部分8进行除2取余 xff0c 除2商4余0 除2商2余0 除2商1余0 除2商0余1 所以结果是1000 最后一个余数在最
  • 关于PX4系统移植的新的硬件平台一些尝试总结

    最近尝试将PX4的firmware v1 11 0移植到某stm32h7的飞控平台上 xff08 该飞控硬件 xff0c 适配ardupilot和betaflight的固件 xff0c 但不支持PX4 xff0c 跟厂家沟通过 xff0c
  • RTK中浮点解、固定解的区别

    1 RTK固定解 xff08 fix xff09 简言之 xff0c 拥有固定解意味着解算出了正确的解 在常规条件下 xff0c 你拥有了1 3cm的测量精度 2 RTK浮点解 xff08 float xff09 又称差分解 xff0c 此
  • 飞机的姿态角总结

    飞机的俯仰 横滚 航行角统称姿态角 是飞机机体系相对地理系的相对转角 1 航向角为机体纵轴OYb轴在水平面上投影与OYt之间的夹角 xff0c 取值范围为 0 xff0c 360 xff0c 以机体从北向东偏转为正 2 俯仰角为机体纵轴OY
  • Matlab一些设置记录

    在使用matlab时经常要查一些命令 xff0c 索性在这里整理做一个集合 1 设置figrue背景为白色 xff08 默认为灰色 xff0c 直接截图贴图使用时有一丢丢影响效果 xff09 set 0 39 defaultfigureco
  • 如何学好嵌入式的嵌入式

    近来嵌入式挺火 xff0c 于是大家都往这里挤 我想提醒大家的是 xff0c 嵌入式马上也会成为如今的软件业 在你进来之前请先考虑清楚 但只要我们真的学精了一样东西 xff0c 不管它将来变成什么样 xff0c 哪怕最后只剩下一个人 xff
  • Python全局变量和局部变量(超详细,纯干货,保姆级教学)

    全局变量定义 在函数外部定义的变量 所有函数内部都可以使用这个变量 局部变量定义 在函数内部定义的变量 这个变量只能在定义这个变量的函数内部使用 第一种 xff1a global定义全局变量在自定义函数内部 定义看起来一愣一愣的 xff0c
  • stm32——手动移植HAL库以及错误解决方案(以STM32F103ZE为例)

    寄存器编程的缺点 xff1a 代码可读性差 xff0c 二次开发难度大 xff0c 而且要每次都查阅用户手册 xff0c 非常麻烦 HAL库 xff1a HAL库封装出了一层通用性的接口 xff0c 标准化了一套通用性的接口 xff0c 大
  • MATLAB在线编辑器online

    话不多说直接上网址 https matlab mathworks com 这个和下载的MATLAB功能一模一样 xff0c 这是我找了几个例子运行出来的结果 xff0c 和我想要的一模一样 xff0c 不过对于大多数人而言 xff0c 这个
  • stm32——使用结构体描述寄存器映射

    将地址信息放在一个头文件中方便管理 xff0c 存放地址和偏移量 STM32的外设寄存器的组织形式是 基于基地址 43 寄存器偏移地址 比如 xff0c 在RCC的基地址基础上 xff0c 偏移0x00得到RCC CR寄存器 xff0c 偏
  • 江科大stm32-概述

    第一章 STM32概述 1 1 资源介绍 STM32F103C8T6 51单片机使用的是5V供电 xff0c 还有USB输出的电压也是5V xff0c 5V是不在这个供电电压范围内的 xff0c 不能直接给STM32供电 xff0c 如果是
  • 在eclipse中查看你用的tomcat的路径

    打开eclipse xff0c 选择window gt Preferences gt Server gt Runtime Environments选择你的tomcat然后点Edit xff0c 就会出现它的路径了
  • 安装龙蜥或CentOS 7时出现dracut- initqueue timeout解决方法

    在安装龙蜥7 9操作系统时 xff0c 出现dracut initqueue timeout starting starting timeout scripts报错 CentOS 7 9出现此问题也可以参考同样的方法 如何制作启动盘和系统盘
  • 视觉标记定位aruco使用

    本文的目的是实现生成一张marker broad图片 xff0c 告诉标记检测程序tag在真实世界中的实际大小 检测成功后得到marker的id 四个角点坐标 marker到相机的平移和旋转 xff11 xff0e 下载安装参考 openc
  • github进行修改

    1 xff09 git status xff1a 可以让我们时刻掌握仓库当前的状态 2 xff09 git diff 文件名 xff1a 查看改变的详细信息 xff0c 显示的结果是Unix通用的diff格式 步骤 xff1a 1 修改文件
  • C# 内存与性能优化

    C 内存与性能优化 https www jianshu com p d56f79d83ebd 前两周分享了资源配置与资源管理 xff0c 今天分享一种特殊的资源脚本数据 在Unity项目中 xff0c 我们通常使用C 编写脚本 xff0c
  • Gazebo仿真错误与技巧

    xff08 1 xff09 创建的环境不能保存 打开gazebo创建环境以后 xff0c 不能保存 xff0c 在打开是需要加权限 xff08 sudo xff09 xff0c 详细说明 如果是build可以先保存成模型 xff0c 然后再
  • 《Android入门之旅》

    因为本人在公司任职Java和JavaWeb相关开发工作 EXTJS和JQUERY近年来在网站中使用广泛 EXT江湖对我帮助很大 该书由浅入深地解析了Ext框架的方方面面 xff0c 包括JS基础 Ext的DOM和CSS封装 内置对象的扩展
  • 转发——从搭建小系统到架构分布式

    从搭建小系统到架构分布式 从搭建小系统到架构分布式 SpringBoot是目前Spring技术体系中炙手可热的框架之一 既可用于构建业务复杂的企业应用系统 xff0c 也可以开发高性能和高吞吐量的互联网应用 Spring Boot 框架降低
  • 2018-8-30华为机试第三题

    一个很明显的递归问题 package cn csu ksh import java util ArrayList import java util List import java util Scanner public class Mai

随机推荐

  • 海康威视web3.2开发包开发使用说明

    首言 xff1a 通过海康威视的最新web开发包工具进行js调用引入至vue项目中 xff0c 实现监控设备的对接 xff0c 监控功能的实现 3 2无插件js库同时支持插件安装的模式 目录 首言 xff1a 一 海康威视开发平台 xff1
  • 游戏的navmesh 与rvo动态避障算法(1)

    目前很多手游中如果需要寻路 xff0c 很多时候复杂地形都是需要用到navmesh xff0c 而比较常用的navmesh 系统 xff1a 1 astarpathfinding xff1a 一个老外开发的寻路插件 xff0c 内置有很多寻
  • Python3 指数函数 | numpy.power() math.pow() numpy.exp2() a**b

    对数函数用法 单纯求一个数的指数函数 xff0c 直接用a b比较好 xff1f 2 3 2的三次方 使用pow x y pow 有两种 xff0c 一种是python内置函数 xff0c 一种是math pow 使用python内置函数调
  • SVO2.0

    rpg svo pro open即svo2 0版本在上一年开源了 xff0c 对svo2 0接触了有一小段时间了 xff0c 感觉代码功能和一些函数实现等相比svo1 0版本有区别 xff0c 所以准备把这块好好总结下 xff0c 争取白话
  • ROS CMakeLists.txt中catkin_package和INCLUDE_DIRS的区别

    CMakeLists txt中 catkin package INCLUDE DIRS include 这里代表的是catkin的构建选项 xff0c INCLUDE DIRS表示将使用INCLUDE DIRS后面的内部目录include
  • 利用ROS框架搭建云平台提供机器人服务

    我们要怎么做呢 我们在云平台我们识别物体之后输出的是全局的二维码坐标 x y z 我们接下来要做两件事情 一种是使用云端的服务 xff08 在ROS中的表现形式是云平台提供的action xff09 第二种是请求云端的数据 xff08 可以
  • 虚拟现实技术vr可以用来干什么?虚拟现实技术vr有什么特征

    科技行业的不断蓬勃发展 xff0c 每天会出现一些新的科技产品 xff0c 例如现在很火的虚拟现实技术vr xff0c 虚拟现实技术用的领域很多 xff0c 就拿游戏行业来说 xff0c 玩家可以通过vr眼镜 vr手柄等体验vr游戏 xff
  • vr直播是如何实现的?vr直播都有哪些优势

    科技改变了我们的生活方式 xff0c 提起科技相信大家对这个直播行业恐怕都不陌生 xff0c 最近直播行业也玩出来新的花样 xff0c 引进了vr技术 xff0c 摇身一变 xff0c 变成了vr直播 xff0c 很多朋友不太理解vr直播是
  • Python归并排序

    归并排序 数据科学家每天都在处理算法 然而 xff0c 数据科学学科作为一个整体已经发展成为一个不涉及复杂算法实现的角色 尽管如此 xff0c 从业者仍然可以从建立对算法的理解和知识库中受益 在本文中 xff0c 对排序算法归并排序进行了介
  • 平衡车PID调节总结

    https blog csdn net a568713197 article details 82845959
  • FreeRTOS详解三

  • Invalid bound statement (not found)出现的原因和解决方法

    解决错误的步骤 出现了什么错误可能导致的原因解决办法 出现了什么错误 错误截图 xff1a BindingException 数据绑定异常 not found 找不到 org apache ibatis binding BindingExc
  • TI Processor SDK 如何生成例程

    TI现在新的SDK都叫Process SDK了 例程要自己生成 这样好多人都说自己找不到例程在哪里 其实就是生成这一步搞不定 我以AM5728为例子说 先打开到pdk的目录 编辑箭头所示文件 安装在默认路径Cpan的可以忽略这一步 否则要改
  • PCIE BAR空间理解

    PCIE应用程序编程 xff0c 首先就要理清PCIE BAR空间到底说的是什么 在PCIE配置空间里 xff0c 0x10开始后面有6个32位的BAR寄存器 xff0c BAR寄存器中存储的数据是表示PCIE设备在PCIE地址空间中的基地
  • 老男孩读PCIe之五:TLP结构

    来源 xff1a http www ssdfans com p 61 3683 无论Request TLP xff0c 还是作为回应的Completion TLP xff0c 它们模样都差不多 xff1a 图5 1 TLP主要由三部分组成
  • vxWorks6.9及workBench3.3常见配置

    1 双斜杠注释 在workBench集成开发环境当中 xff0c 默认的注释方式为 xxxxxx 如果想要使用 注释的方法必须修改workBench 的编译选项 xff0c 为编译选项添加c99支持或者gnu89 在编译选项中添加 std
  • 可能是最全的FreeRTOS源码分析及应用开发系列

    可能是最全的FreeRTOS源码分析及应用开发系列 FreeRTOS 是一个可裁剪的小型且免费的 RTOS 系统 xff0c 尺寸非常小 xff0c 可运行于微控制器上 其特点包括 xff1a 内核支持抢占式 xff0c 合作式和时间片调度
  • FreeRTOS系列|FreeRTOS简介

    1 RTOS简介 RTOS全称为 Real Time Operation System xff0c 即实时操作系统 RTOS强调的是实时性 xff0c 又分为硬实时和软实时 硬实时要求在规定的时间内必须完成操作 xff0c 不允许超时 xf
  • FreeRTOS系列|任务创建和删除

    1 任务创建和删除API函数 xTaskCreate 函数 xff1a 动态创建一个新的任务 xff0c 每个任务都需要RAM来保存任务状态 任务控制块 43 任务栈 xff0c 此接口采用动态分配内存资源 BaseType t span
  • FreeRTOS系列|多任务调度

    1 多任务启动流程 多任务启动流程如下表所示 启动后以下各函数由上至下依次执行含义osKernelStart 启动内核vTaskStartScheduler 启动任务调度器xPortStartScheduler 启动调度器prvStartF