FreeRTOS任务调度管理

FreeRTOS任务状态机切换流程图

vTaskStartScheduler函数

通过configSUPPORT_STATIC_ALLOCATION这个宏,来决定是创建静态创建Idle任务,还是动态创建任务;静态创建就是TCB和栈空间使用DATA数据段预先分配好的内存,动态创建就是使用malloc分配堆上的内存

1:在vTaskStartScheduler中创建IDLE任务,是确保系统必须至少有一个任务可调度;

2:xPortStartScheduler

  • 根据业务需要,配置PMU;
  • 启动systick开始计数;后续同优先级任务通过tick中断进行任务的时间片调度;
  • 启动第一个任务,从NV中获取栈地址,并配置MSP寄存器,开启全局中断,并调用SV中断去启动第一个任务;注意:只有第一个任务启动的时候,才需要调用SV中断来启动;

xTaskCreate函数

1:先申请TCB和栈空间,如下代码:

2:prvInitialiseNewTask是初始化一个新的任务

  • 设置栈顶地址,如果栈配置的是向下增长的,设置栈顶指向的地址= 栈的基地址 + 栈的深度pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
  • 配置任务名称和初始化任务链表
  • 初始化化栈的空间。用于保存R0~R14寄存器值和函数的入口地址;不同平台稍微有些不一样;

Cortex-M中,有两个栈寄存器:PSPMSP。程序运行时,可以选择使用PSP或MSP作为栈的指针。

缺省情况下,Cortex-M3使用的是单栈模型,即上电后程序工作在特权级线程模式下,此时使用的MSP寄存器作为栈指针寄存器。之后,无论异常还是中断,都使用MSP指向的栈。

3:prvAddNewTaskToReadyList将任务加入就绪任务链表中;

将创建的任务加入到就绪任务链表中,如果当前任务的优先级小于新创建的任务优先级,则执行一次任务抢占;

xPortPendSVHandler(cortex-m3/m4 不带浮点)

保存当前任务端点,将MCU寄存器存入当前任务栈内存中

vTaskSwitchContex切换上下文,恢复要执行任务的上下文

在vTaskSwitchContext中,调用taskSELECT_HIGHEST_PRIORITY_TASK,找到下一个要执行的任务;根据任务优先级,先从高到底查找;

prvSVCHandler

恢复第一个任务的上下文

获取pxCurrentTCB的地址,并从中获取栈顶指针,执行出栈操作,恢复MCU的寄存器,并开始执行任务;

xPortSysTickHandler

portSET_INTERRUPT_MASK_FROM_ISR这个函数屏蔽除NMI之外的所有中断;

xTaskIncrementTick函数作用:

操作系统的运行是由系统节拍时钟驱动的。
系统每次节拍中断服务程序中主要任务由函数 xTaskIncrementTick 完成。
在任务调度器没有挂起的情况下( xTaskIncrementTick != pdFALSE ),该函数主要完成 :

  • 判断节拍计数器xTickCount 是否溢出, 溢出轮换延时函数队列
  • 判断是否有阻塞任务超时,取出插入就绪链表
  • 同优先级任务时间片轮

而当任务调度器被挂起时, 该函数累加挂起时间计数器 uxPendedTicks, 调用用户钩子函数, 此时,正在运行的任务不会被切换, 一直运行。
当恢复调度时, 系统会先重复调用 xTaskIncrementTick 补偿 (uxPendedTicks次)。
不管, 系统调度器是否挂起, 每次节拍中断都会调用用户的钩子函数 vApplicationTickHook 。 由于函数是中断中调用,不要在里面处理太复杂的事情!

vTaskSuspend

1:从readylist或delaylist中移除

2:插入到xSuspendedTaskList链表中

vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );

3:如果当前任务就是要挂起的任务,有两种情况:

  • 调度器在运行状态,调用portYIELD_WITHIN_API,触发pendSV,进行一次任务调度;
  • 调度器停止工作状态,由于调度器未运行,但pxCurrentTCB指向的任务刚刚被挂起,必须调整pxCurrentTCB以指向其他任务,这其中又存在两种情况,一种是所有任务都未就绪,则pxCurrentTCB设置未NULL,否则调用vTaskSwitchContext,找个一个就绪任务,设置pxCurrentTCB

vTaskResume

所有挂起的任务,不再参与任务调度,必须调用vTaskResume,将任务再重新放入到就绪链表中,并判断当前任务和resume的任务优先级,如果resume的任务优先级大于当前任务优先级,则执行一次任务抢占;

vTaskDelay

1、将当前任务放入到延迟任务链表中;

2、当前任务已经处于sleep状态了,通过portYIELD_WITHIN_API,触发pendSV需要重新做一次任务调度了

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杜金新技术博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值