大多数主机或桌面系统(比如Linux,Mac或Windows)都有一个正常的用例,你可以在早上启动操作系统,然后在晚上关闭它,然后你就离开机器。嵌入式系统是不同的:他们没有参加,他们应该“永远”运行。并非每个嵌入式系统都需要运行操作系统(或者在那个世界中:实时操作系统或RTOS),但这同样适用于:在RTOS启动后,并不意味着它将关闭并重新启动。在某种程度上,他们根本不支持“关闭”和“重启”功能。如果收集覆盖率信息,这将非常有用:

来自FreeRTOS应用程序的覆盖信息

  对于FreeRTOS:如果我真的需要关闭RTOS并重新启动它会怎么样,因为默认情况下不支持。这就是本文的内容......

介绍

  嵌入式系统与桌面系统根本不同:虽然不时关闭和重新启动台式机或笔记本电脑系统是正常的,但这不是计划或打算用于嵌入式系统:本质上它应该“始终”运行。从嵌入式系统的“主要”进一步可以看出这一点:通常主要永远不会返回并保持运行,如下所示:

void main(void) {

InitClocks();

InitPins();

InitDrivers();

for(;;) {

AppRun();

}

/* 从未离开主程序 */

}

  如果使用RTOS运行,类似的东西适用于嵌入式系统,其中看起来类似于:

void main(void) {

InitClocks();

InitPins();

InitDrivers();

CreateInitialTasks();

StartScheduler();

/* 调度程序永远不会终止,所以不应该到达这里 */

for(;;) { }

/* 从未离开主程序 */

}

为什么关机并重启?

  显然,对于嵌入式RTOS而言,RTOS关闭或重启的需求可能不是最需要的。我仍然发现它非常有用:

在调度程序关闭后写入gcov覆盖信息

  • 在监听更新时运行RTOS是有意义的。在某些情况下,在执行更新时运行RTOS肯定是可能的,但在某些阶段我必须停止并重新启动它。这可以通过重置和重新启动系统来完成(例如,请参阅“ 如何使用软件重置ARM Cortex-M ”)。我发现它是关闭RTOS的更好方法,然后在RTOS之外进行更新并重启系统。

从任务结束FreeRTOS调度程序

  • 另一个用例是低功耗应用。虽然FreeRTOS在低功耗模式下也很出色(参见“ 使用FreeRTOS实现低功耗:无空闲模式 ”),但如果可以关闭更多活动系统,应用程序甚至可以进入功耗更低的低功耗模式。因此,只有在我的应用程序的使用寿命期间才能运行RTOS才能有意义,而不是在其他部分运行RTOS,这为我提供了更大的灵活性和更低功耗的机会。

vTaskStartScheduler()后跟低功耗模式

  所以我希望你明白为什么RTOS的关闭和重启是有意义的。包括FreeRTOS在内的大多数RTOS都能够“静音”调度程序(例如vTaskSuspendAll()),但仍然存在RTOS并使用系统资源。但是,如果需要,完全“删除”并重新启动它的能力将是很酷的事情。

FreeRTOS

  FreeRTOS确实有一个调度程序启动函数(vTaskStartScheduler()),甚至在其API中有一个vTaskEndScheduler()函数:

FreeRTOS vTaskEndScheduler()API函数

  但正如论坛和API描述中所述,它仅支持PC端口(请参阅API说明):“ 注意:这仅适用于x86实模式PC端口。“

  原来的FreeRTOS端口也是如此。我扩展的端口确实支持这个,我在ARM Cortex-M和HCS08应用程序中使用它:-)。

vTaskEndScheduler()和vTaskStartScheduler()

  虽然RTOS已准备好将其关闭的API调用,但FreeRTOS在调用vTaskEndScheduler()之后没有适当的基础结构来重新启动RTOS。但这正是我想要的:在结束后重启RTOS。

  要能够结束调度程序,必须在FreeRTOSConfig.h中将以下宏设置为1:

#define INCLUDE_vTaskEndScheduler                 1

  挑战在于:在调度程序启动之后,在vTaskStartScheduler()调用之后立即返回代码并不容易。因为具有自己的堆栈的任务,加上FreeRTOS和M3的标准端口,M4和M7甚至会重置MSP堆栈指针(参见本论坛讨论)。因此,如果我想返回调度程序已启动的位置,我需要阻止重置ARM Cortex上的MSP堆栈指针。这就是我为FreeRTOS添加一个设置来配置它的原因:

重置MSP设置

  这将设置以下配置:

#ifndef configRESET_MSP

#define configRESET_MSP                         (0)

/*!< 1: reset MSP at scheduler start (Cortex M3/M4/M7 only); 0: do not reset MSP */

#endif

  将此设置设置为0,我的端口在调度程序起始点执行*不*重置MSP。

端口代码重置msp堆栈指针

  这意味着并非完整的MSP堆栈可用于中断(参见“ ARM Cortex-M中断和FreeRTOS:第3部分 ”),但这通常也可以。

  为了能够跳回到调度程序的起点,我使用了C库的一个很酷的功能:setjmp / longjmp(参见http://web.eecs.utk.edu/~huangj/cs360/360/notes/ Setjmp / lecture.html)

  首先,我需要一个跳转缓冲区变量:

#if INCLUDE_vTaskEndScheduler

#include <setjmp.h>

static jmp_buf xJumpBuf; /* Used to restore the original context when the scheduler is ended. */

#endif

  在xPortStartScheduler()里面我设置了跳转缓冲区:

#if INCLUDE_vTaskEndScheduler

if(setjmp(xJumpBuf) != 0 ) {

/* here we will get in case of a call to vTaskEndScheduler() */

__asm volatile(

" movs r0, #0         \n" /* Reset CONTROL register and switch back to the MSP stack. */

" msr CONTROL, r0     \n"

" dsb                 \n"

" isb                 \n"

);

return pdFALSE;

}

#endif

vPortStartFirstTask(); /* Start the first task. */

/* Should not get here! */

return pdFALSE;

  如果建立跳转缓冲区,setjmp()返回0,并且在调用setjmp()的情况下返回!= 0将在vTaskEndScheduler()期间调用。

void vTaskEndScheduler( void )

{

/* Stop the scheduler interrupts and call the portable scheduler end

routine so the original ISRs can be restored if necessary.  The port

layer must ensure interrupts enable bit is left in the correct state. */

portDISABLE_INTERRUPTS();

xSchedulerRunning = pdFALSE;

vPortEndScheduler();

}

  然后,vPortEndscheduler()执行RTOS的所有清理和重置。重置要求不会造成调试器对任何RTOS认知的混淆:

void vPortEndScheduler(void) {

vPortStopTickTimer();

vPortInitializeHeap();

uxCriticalNesting = 0xaaaaaaaa;

/* Jump back to the processor state prior to starting the

scheduler.  This means we are not going to be using a

task stack frame so the task can be deleted. */

#if INCLUDE_vTaskEndScheduler

longjmp(xJumpBuf, 1);

#else

for(;;){} /* wait here */

#endif

}

  有了这个,调度程序优雅地终止,我又回到了主堆栈上:

在调用vTaskEndScheduler()之后在msp堆栈上

摘要

  默认情况下,对于嵌入式目标,FreeRTOS不支持结束调度程序或在结束后重新启动调度程序。本文描述了ARM Cortex-M的一个端口,它实现了vTaskEndScheduler(),并能够在没有上电复位的情况下再次调用vTaskStartScheduler()。结束和启动调度程序对于低功耗应用程序非常有用,在应用程序的实时循环或引导加载程序应用程序中不需要RTOS的情况。该概念用于恩智浦的不同ARM Cortex-M内核,包括8/16位S08微控制器,但可以轻松用于任何其他微控制器架构。

参考链接

声明:本文为翻译文章,原文作者是:Erich Styger,原文网址为:https://mcuoneclipse.com/2019/01/20/freertos-how-to-end-and-restart-the-scheduler/

欢迎关注:

FreeRTOS如何结束和重新启动调度程序的更多相关文章

  1. FreeRTOS相关转载-(朱工的专栏)

    FreeRTOS系列第1篇---为什么选择FreeRTOS? 1.为什么学习RTOS? 作为基于ARM7.Cortex-M3硬件开发的嵌入式工程师,我一直反对使用RTOS.不仅因为不恰当的使用RTOS ...

  2. Android应用性能优化(转)

    人类大脑与眼睛对一个画面的连贯性感知其实是有一个界限的,譬如我们看电影会觉得画面很自然连贯(帧率为24fps),用手机当然也需要感知屏幕操作的连贯性(尤其是动画过度),所以Android索性就把达到这 ...

  3. lmap

    1.lamp组件安装 sudo apt-get install apache2 sudo apt-get install php5 sudo apt-get install mysql-server ...

  4. .Net内存泄露原因及解决办法

    .Net内存泄露原因及解决办法 1.    什么是.Net内存泄露 (1).NET 应用程序中的内存 您大概已经知道,.NET 应用程序中要使用多种类型的内存,包括:堆栈.非托管堆和托管堆.这里我们需 ...

  5. inno setup介绍及官方网站地址

    使 用 笔 记 1.Inno Setup 是什么?Inno Setup 是一个免费的 Windows 安装程序制作软件.第一次发表是在 1997 年,Inno Setup 今天在功能设置和稳定性上的竞 ...

  6. 转——Android应用开发性能优化完全分析

    [工匠若水 http://blog.csdn.net/yanbober 转载请注明出处.] 1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关于性能的建议,感觉 ...

  7. Ghost命令使用方法

    我们知道,一般使用Ghost时,都是在DOS提示符后先键入"Ghost",然后再进入Ghost的图形界面操作:那么可不可以让Ghost也只通过命令行的方式工作呢?答案是肯定的,在键 ...

  8. Android 应用开发性能优化完全分析

    1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关于性能的建议,感觉大家你一总结.我一总结的都说到了很多优化注意事项,但是看过这些文章后大多数存在一个问题就是只 ...

  9. 【转】Android应用开发性能优化完全分析

    http://blog.csdn.net/yanbober/article/details/48394201 1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关 ...

随机推荐

  1. 鼠标拖动DOM

    自己收藏,使用angualrjs的directive些的鼠标拖动DOM.... <!DOCTYPE html> <html lang="en"> <h ...

  2. vue cli使用融云实现聊天

    公司有个项目要实现一个聊天功能,需求如下图,略显随意 公司最终选择融云这个吊炸天的即时通信,文档详细的一匹,刚开始看文档感觉很详细实现起来也不麻烦,有很多开源的demo可以在线演示和下载 不过我们的项 ...

  3. Nmap小技巧——探测大网络空间中的存活主机

    Nmap快速探测空间主机是否存活的技巧(来自lijiejie师傅): nmap -v -sn -PE -n --min-hostgroup --min-parallelism -oX nmap_out ...

  4. Mac打开Terminal报错-bash : : command not found

    问题描述: Mac系统在打开Terminal的时候,报错-bash : : command not found. 问题分析: 报错并不影响Terminal的使用,于是忽略不计.但是在修改.bash_p ...

  5. 快速排序-python

  6. Codeforces1153F Serval and Bonus Problem 【组合数】

    题目分析: 我们思考正好被k个区间覆盖的情况,那么当前这个子段是不是把所有的点分成了两个部分,那么在两个部分之间相互连k条线,再对于剩下的分别连线就很好了?这个东西不难用组合数写出来. 然后我们要证明 ...

  7. <Android基础> (六) 数据存储 Part 1 文件存储方式

    第六章 数据存储 6.1 持久化技术 持久化技术指将内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不会丢失. 主要有三种方式用于简单地实现数据持久化功能:文件存储.S ...

  8. 洛谷 P2590 [ZJOI2008]树的统计

    大家好,我非常喜欢暴力数据结构,于是我用块状树过了这道题目 题目: 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE ...

  9. python之路(8)常用模块

    目录 os模块 sys模块 json模块 pickle模块 xml模块 re模块 logging模块 configparser模块 hashlib模块 time模块 random模块 subproce ...

  10. seajs使用方法

    必须执行seajs.use()时,才能自动执行预加载项 <script src="/UILib/sea.js"></script> <script s ...