FreeRTOS学习笔记——FreeRTOS 系统内核控制函数

FreeRTOS 中有一些函数只供系统内核使用,用户应用程序一般不允许使用,这些API 函数就是系统内核控制函数。本章我们就来学习一下这些内核控制函数,本章分为如下几部分:
10.1 内核控制函数预览

10.2 内核控制函数详解

10.1 内核控制函数预览
顾名思义,内核控制函数就是FreeRTOS 内核所使用的函数,一般情况下应用层程序不使用这些函数,在FreeRTOS 官网可以找到这些函数,如图10.1.1 所示:


这些函数的含义如表10.1.1 所示:


10.2 内核控制函数详解
1、函数taskYIELD()
此函数用于进行任务切换,此函数本质上是一个宏,此函数的详细讲解请参考9.2.1 小节。
2、函数taskENTER_CRITICAL()

进入临界区,用于任务函数中,本质上是一个宏,此函数的详细讲解请参考4.4.1 小节。

3、函数taskEXIT_CRITICAL()
退出临界区,用于任务函数中,本质上是一个宏,此函数的详细讲解请参考4.4.1 小节。
4、函数taskENTER_CRITICAL_FROM_ISR()
进入临界区,用于中断服务函数中,此函数本质上是一个宏,此函数的详细讲解请参考4.4.2小节。
5、函数taskEXIT_CRITICAL_FROM_ISR()
退出临界区,用于中断服务函数中,此函数本质上是一个宏,此函数的详细讲解请参考4.4.2小节。
6、函数taskDISABLE_INTERRUPTS()
关闭可屏蔽的中断,此函数本质上是一个宏,此函数的详细讲解请参考4.3 小节。
7、函数taskENABLE_INTERRUPTS()
打开可屏蔽的中断,此函数本质上是一个宏,此函数的详细讲解请参考4.3 小节。
8、函数vTaskStartScheduler()
启动任务调度器,此函数的详细讲解请参考8.3 小节。
9、函数vTaskEndScheduler()

关闭任务调度器,FreeRTOS 中对于此函数的解释如图10.2.1 所示:


可以看出此函数仅用于X86 架构的处理器,调用此函数以后所有系统时钟就会停止运行,所有创建的任务都会自动的删除掉(FreeRTOS 对此函数的解释是会自动删除所有的任务,但是在FreeRTOS 的源码中没有找到相关的处理过程,有可能要根据实际情况编写相关代码,亦或是X86 的硬件会自动处理?笔者不了解X86 架构),多任务性能关闭。可以调用函数vTaskStartScheduler()来重新开启任务调度器。此函数在文件tasks.c 中有如下定义:


函数vPortEndScheduler()在port.c 中有定义,这个函数在移植FreeRTOS 的时候要根据实际使用的处理器来编写,此处没有实现这个函数,只是简单的加了一行断言,函数如下:


可看出,此函数只是简单的将变量uxSchedulerSuspended 加一,uxSchedulerSuspended 是挂起嵌套计数器,调度器挂起是支持嵌套的。使用函数xTaskResumeAll()可以恢复任务调度器,调用了几次vTaskSuspendAll()挂起调度器,同样的也得调用几次 xTaskResumeAll()才会最终恢复任务调度器。
假设现在有这样一种情况,任务1 的优先级为10,此时任务1 由于等待队列(关于队列的知识后面会有专门的章节讲)TestQueue 而处于阻塞态。但是有段其他的代码调用函数vTaskSuspendAll()挂起了任务调度器,在还没有调用xTaskResumeAll()恢复任务调度器之前,有个在外部中断发生了,在中断服务程序里面调用函数xQueueSendFromISR()向任务1 发送了队列TestQueue。如果任务调度器没有阻塞的话函数xQueueSendFromISR()会使任务1 进入就绪态,也就是将任务1 添加到优先级10 对应的就绪列表pxReadyTasksLists[10]中,这样当任务切换的时候任务1 就会运行。但是现在任务调度器由于函数vTaskSuspendAll()而挂起,这个时候任务1 就不是添加到任务就绪列表pxReadyTasksLists[10]中了,而是添加到另一个叫做xPendingReadyList 的列表中,xPendingReadyList 是个全局变量,在文件tasks.c 中有定义。当调用函数xTaskResumeAll()恢复调度器的时候就会将挂到列表xPendingReadyList 中的任务重新移动到它们所对应的就绪列表pxReadyTasksLists 中。
11、函数xTaskResumeAll()

此函数用于将任务调度器从挂起壮态恢复,缩减后的函数代码如下:


(1)、进入临界区。
(2)、调度器挂起嵌套计数器uxSchedulerSuspended 减一。

(3)、如果uxSchedulerSuspended 为0 说明所有的挂起都已经解除,调度器可以开始运行了。

(4)、while()循环处理列表xPendingReadyList,只要列表xPendingReadyList 不为空,说明还有任务挂到了列表xPendingReadyList 上,这里需要将这些任务从列表xPendingReadyList 上移除并添加到这些任务所对应的就绪列表中。
(5)、遍历列表xPendingReadyList,获取挂到列表xPendingReadyList 上的任务对应的任务控制块。
(6)、将任务从事件列表上删除。
(7)、将任务从壮态列表上移除。
(8)、调用函数prvAddTaskToReadyList()将任务添加到就绪列表中。
(9)、判断任务的优先级是否高于当前正在运行的任务,如果是的话需要将xYieldPending 标记为pdTRUE,表示需要进行任务切换。
(10)、根据(9)得出需要进行任务切换。
(11)、标记在函数xTaskResumeAll()中进行了任务切换,变量xAlreadyYielded 用于标记在函数xTaskResumeAll()中是否有进行任务切换。
(12)、调用函数taskYIELD_IF_USING_PREEMPTION()进行任务切换,此函数本质上是一个宏,其实最终调用是通过调用函数portYIELD()来完成任务切换的。
(13)、退出临界区。
(14)、返回变量xAlreadyYielded,如果为pdTRUE 的话表示在函数xTaskResumeAll()中进行了任务切换,如果为pdFALSE 的话表示没有进行任务切换。
12、函数vTaskStepTick()
此函数在使用FreeRTOS 的低功耗tickless 模式的时候会用到, 即宏configUSE_TICKLESS_IDLE 为1。当使能低功耗tickless 模式以后在执行空闲任务的时候系统时钟节拍中断就会停止运行,系统时钟中断停止运行的这段时间必须得补上,这个工作就是由函数vTaskStepTick()来完成的,此函数在文件tasks.c 中有如下定义:


(1)、函数参数xTicksToJump 是要加上的时间值,系统节拍计数器xTickCount 加上这个时间值得到新的系统时间。关于xTicksToJump 这个时间值的确定后面在讲解FreeRTOS 的低功耗模式的时候会详细的讲解。




猜你喜欢

转载自blog.csdn.net/tichimi3375/article/details/80710189