FreeRTOS 任务创建和调度器开启

目录

一、任务创建

1、动态创建任务--常用

2、静态创建任务

二、静态任务和动态任务创建的区别

1、动态创建任务:

2、静态创建任务:

三、任务调度

1、vTaskStartScheduler()调度器:

2、内核相关硬件初始化函数分析:xPortStartScheduler()

3、启动第一个任务函数分析:prvStartFirstTask()

4、SVC中断服务函数

5、MSP、PSP??

6、线程模式(Thread Mode),中断异常模式(Handler Mode)??

7、内核态和用户态??

8、SVC和PendSV的区别??

9、r0-r12寄存器组??


一、任务创建

1、动态创建任务--常用

2、静态创建任务

二、静态任务和动态任务创建的区别

1、动态创建任务:

(1)不需要用户自己建立堆栈。

(2)在运行时动态分配任务所需的内存空间,任务删除时,释放内存

(3)适用于任务数量不确定或需要动态管理任务的场景。

(4)动态创建可能会出现内存不足或者内存碎片的情况。

2、静态创建任务:

(1)需要用户自己建立堆栈。

(2)在编译时分配任务所需的内存空间,任务删除时,不会释放内存

(3)这种方式适用于任务数量是固定的,并且在编译时已知的情况下。

(4)静态创建稳定性高,但是耗内存!任务删除以后这段内存没法释放掉,就只能浪费掉!

三、任务调度

1、vTaskStartScheduler()调度器:

(1) 创建空闲任务;

(2) 创建定时器任务(如果开启);

(3) 关闭中断,在 SVC 中断服务函数 vPortSVCHandler)中会打开中断;

(4) 当宏configGENERATE_RUN-TIME_STATS为1的时候说明使能时间统计功能,此时需要用户实现宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS,此宏用来配置一个定时器/计数器;

(5) 调用函数xPortStartScheduler()来初始化跟调度器启动有关的硬件,比如滴答定时器FPU单元PendSV中断等等。

2、内核相关硬件初始化函数分析:xPortStartScheduler()

(1) 设置PendSV的中断优先级,为最低优先级;

(2) 设置滴答定时器的中断优先级,为最低优先级。

(3) 调用函数vPortSetupTimerInterrupt()来设置滴答定时器的定时周期,并且使能滴答定时器的中断;

(4) 初始化临界区嵌套计数器;

(5) 调用函数prvEnableVFP()使能FPU;

(6) 设置寄存器FPCCR的bit31和bit30都为1,这样S0-S15和FPSCR寄存器在异常入口和退出时的壮态自动保存和恢复。并且异常流程使用惰性压栈的特性以保证中断等待;

(7) 启动第一个任务。

3、启动第一个任务函数分析:prvStartFirstTask()

向量表的起始地址保存的就是主栈指针MSP 的初始值,这一行代码执行完以后寄存器 RO 就存储 MSP 的初始值。现在来看(1)、(2)、(3)这三步起始就是为了获取MSP的初始值。

(5)和(6)、使能中断,关于这两个指令的详细内容请参考《权威指南》的“第4章架构”的第4.2.3 小节。

(7)和(8)、数据同步和指令同步屏障,这两个指令的详细内容请参考《权威指南》的“第 5章 指令集”的 5.6.13 小节。

(9),调用SVC指令触发SVC中断, SVC也叫做请求管理调用, SVC和PendSV异常对于OS的设计来说非常重要。SVC 异常由 SVC 指令触发。关于 SVC 的详细内容请参考《权威指南》的“第 10 章 OS 支持特性”的 10.3 小节。在 FreeRTOS 中仅仅使用 SVC 异常来启动第一个任务,后面的程序中就再也用不到SVC了。

4、SVC中断服务函数

(1)、(2)和(3):目的就是获取要切换到的这个任务的任务栈顶指针,因为任务所对应的寄存器值,也就是现场都保存在任务的任务堆栈中,所以需要获取栈顶指针来恢复这些寄存器值。

(4):通过这一步我们就从任务堆栈中将 R4-R11,R14 这几个寄存器的值给恢复了,注意 R14 的值为OXFFFFFFFD,这个值就是我们在初始化任务堆栈的时候保存的EXC-RETURN的值。

(8):执行此行代码以后硬件自动恢复寄存器R0-R3、R12、LR、PC和xPSR的值,堆栈使用进程栈PSP,然后执行寄存器PC中保存的任务函数。至此, FreeRTOS的任务调度器正式开始运行。

5、MSP、PSP??

        MSP和PSP 双堆栈机制是为了OS设计的,是为了让OS、中断与应用程序代码运行解耦,增加整体程序的健壮性。

        那双堆栈指针的作用是什么?答案是为了隔离OS和应用程序,程序的运行少不了堆栈,因为我们CPU只有少量的通用寄存器,当我们使用的临时变量比较多得时候,就需要将这些临时变量存储到堆栈里,而堆栈的push和pop都是通过SP来实现的,所以通过MSP和PSP就能实现OS内核与应用程序的隔离,应用程序task用PSP,而OS用MSP,这样会非常安全。因为应用程序再怎么折腾也只是在自己的堆栈内折腾,不会影响内核OS。

        在发生中断时,CPU会自动的保存现场,这部分工作是硬件自动完成的,而SP到底是指向PSP还是MSP,则是根据在发生中断前是使用MSP还是PSP,比如发生中断前,正在运行RTOS的task,即在使用PSP,那么CPU保存现场也是使用PSP,然后进入中断服务程序,此时会从PSP切换到MSP。

6、线程模式(Thread Mode),中断异常模式(Handler Mode)??

        特权状态和非特权,即内核态和用户态的设计也是为了OS设计的,让整个程序分层,整体程序更加健壮。

7、内核态和用户态??

用户态--->内核态:唯一途径是通过中断、异常、陷入机制(访管指令)

内核态->用户态:设置程序状态字PSW

8、SVC和PendSV的区别??

        SVC不能挂起,它将立即被执行;而PendSV可以暂时挂起异常,对于操作系统来说这很有用,它可以等待一个重要的任务执行完毕后再处理该异常。

        总得来说就是SVC由用户调用SVC #<immed>时立即触发,而PendSV则是置相应的异常标志位,等待比PendSV优先级高的异常执行完后,再执行PendSV。

        在FreeRTOS中,使用SVC异常来开启第一个任务的调度。然后将PendSV异常优先级设置为最低,保证中断的实时性,后续的上下文切换全由PendSV来实现。

9、r0-r12寄存器组??

  • 28
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值