FreeRTOS的学习(十二)——任务调度器的开启

23 篇文章 27 订阅

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 调度器开启

任务调度器在start_task任务创建后就会开启,也就是调用vTaskStartScheduler函数,其功能就是开启任务调度器。
vTaskStartScheduler内部步骤主要如下:

  1. 创建空闲任务,由于FreeRTOS一直是有任务在运行的,所以在没有用户要求的任务时,会调用名为“IDLE”的空闲任务,空闲任务并不是啥都不干,其存在也会进行如下操作:
    1.1. 判断系统是否有任务删除,如果有的话就在空闲任务中释放被删除任务的任务堆栈和任务控制块的内存。这里值得注意的是,只有某个任务要调用函数 vTaskDelete()删除自身时,需要在空闲任务中释放掉,如果删除的是别的任务那么相应的内存就会被直接释放掉,不需要在空闲任务中释放。因此在上述特殊情况下必须给予空闲任务运行的时间。
    1.2.运行用户设置的空闲任务钩子函数
    1.3.判断是否开启低功耗 tickless 模式,如果开启的话还需要做相应的处理
  2. 如果使能了软件定时器,创建软件定时器任务,其功能代码如下:
#if ( configUSE_TIMERS == 1 )
    {
        if( xReturn == pdPASS )
        {
            xReturn = xTimerCreateTimerTask();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
  1. 关中断。为了保证软件定时器在xPortStartScheduler调用之前和调用期间开始计数,也就是第一个任务开始运行前,是不能计数的。
portDISABLE_INTERRUPTS();
  1. 初始化一些静态全局变量:
xNextTaskUnblockTime = portMAX_DELAY;       			//因为还不知道下面有什么任务要从阻塞出来,所以xNextTaskUnblockTime设置为最大值
xSchedulerRunning = pdTRUE;                 			//判断调度器是否在运行
xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;	//初始化为configINITIAL_TICK_COUNT(0)
  1. 调用函数 xPortStartScheduler来初始化跟调度器启动有关的硬件,比如滴答定时器、FPU单元(M4才有)和 PendSV中断等等。
    5.1. 设置PendSV和Systick中断优先级
    5.2. 初始化滴答定时器,中断周期,中断使能,systcik使能
    5.3. 如果MCUu有 FPU的话,开启FPU
    5.4. 如果使用FPU的话,开启惰性压栈
    5.5. prvStartFirstTask开启第一个任务
    5.6. 在prvStartFirstTask函数中最终通过SVC 0指令引起SVC中断,SVC 也叫做请求管理调用。在 FreeRTOS 中仅仅使用 SVC异常来启动第一个任务,后面的程序中就再也用不到 SVC了。
    SVC 中断服务函数应该为 SVC_Handler
#define vPortSVCHandler 	SVC_Handler

函数具体内容如下:

//SVC中断函数,开启中断并恢复现场
__asm void vPortSVCHandler( void )
{
/* *INDENT-OFF* */
    PRESERVE8
    ldr r3, = pxCurrentTCB //R3=pxCurrentTCB的地址
    ldr r1, [ r3 ] //取 R3 所保存的地址处的值赋给 R1
    ldr r0, [ r1 ]  //取 R1 所保存的地址处的值赋给 R0         
    ldmia r0 !, { r4 - r11 } //出栈 ,R4~R11 和R14
    msr psp, r0 //进程栈指针 PSP 设置为任务的堆栈
    isb                     //指令同步屏障
    mov r0, # 0             //R0=0
    msr basepri, r0         //寄存器 basepri=0,开启中断
    orr r14, # 0xd
    bx r14
}
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
FreeRTOS采用抢占式优先级调度算法进行任务调度,主要包括以下几个步骤: 1. 系统启动时,首先创建一个空闲任务(Idle Task),该任务的优先级最低,用于处理系统空闲时的任务。 2. 用户创建任务时,需要指定任务的优先级、函数指针和任务参数等信息,然后调用xTaskCreate或xTaskCreateStatic函数创建任务。 3. 任务被创建后,系统会将任务加入到就绪任务列表中,等待调度进行调度。就绪任务列表按照任务优先级从高到低排序。当有多个任务具有相同的优先级时,按照先进先出的原则进行排序。 4. 当系统空闲或者当前任务阻塞时,调度会从就绪任务列表中选择优先级最高的任务进行调度,并将当前任务从处理上下文切换到新选定的任务上下文。任务的上下文包括任务的堆栈、寄存和其他状态信息。 5. 调度会在每个任务的堆栈中维护任务的状态信息,包括任务的栈指针、寄存值、程序计数等。当任务被阻塞时,调度会将任务的状态信息保存到任务控制块(TCB)中,等待任务重新被唤醒时,再将状态信息从TCB中恢复。 6. 当任务执行结束或者被删除时,系统会将任务从就绪任务列表或者阻塞任务列表中移除,并释放任务占用的系统资源。 总之,FreeRTOS任务调度会根据任务的优先级和状态等信息,动态地选择合适的任务进行调度,以达到最优的系统性能和响应速度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

LEODWL

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

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

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

打赏作者

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

抵扣说明:

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

余额充值