FreeRTOS如何结束和重新启动调度程序

大多数主机或桌面系统(比如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关闭或重启的需求可能不是最需要的。我仍然发现它非常有用:

  • 在RTOS关闭后运行某些软件*是有意义的。例如,如果我收集覆盖率信息(请参阅“ 向Eclipse添加GNU覆盖工具 ”和“ 使用Eclipse Neon和ARM gcc 5在嵌入式目标上实现GNU代码覆盖率 ”),我不希望干扰最后一个进程以转储数据RTOS。另外,我需要独占访问系统资源,包括大量的堆栈空间:关闭RTOS可以让我恢复文件I / O操作所需的所有RAM和堆栈空间。

                                                                             在调度程序关闭后写入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微控制器,但可以轻松用于任何其他微控制器架构。

参考链接

  1. 本文讨论的McuOnEclipse FreeRTOS端口:https//github.com/ErichStyger/McuOnEclipseLibrary/tree/master/lib/FreeRTOS
  2. 使用NXP MCUXpresso IDE在GitHub上使用gcov的示例项目:https//github.com/ErichStyger/mcuoneclipse/tree/master/Examples/MCUXpresso/FRDM-K64F/FRDM-K64F_gcov
  3. FreeRTOS网页:https//www.freertos.org/
  4. FreeRTOS vTaskEndScheduler API:https://www.freertos.org/a00133.html
  5. 关于FreeRTOS和MSP的恩智浦社区讨论:https//community.nxp.com/thread/493367
  6. 有关setjmp / longjmp的维基百科:https//en.wikipedia.org/wiki/Setjmp.h
  7. 关于ARM Cortex-M中断的教程系列:ARM Cortex-M,中断和FreeRTOS:第1部分
  8. MCUXpresso IDE v10.3.0:新的恩智浦MCUXpresso IDE V10.3.0版本

 

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

欢迎关注:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499419.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

先进过程控制之一:浅说APC

先进过程控制&#xff08;APC&#xff09;技术作为在生产装置级的信息化应用&#xff0c;在优化装置的控制水平和提高生产过程的管理水平的同时&#xff0c;还为企业创造了可观的经济效益。 1、什么是APC 先进过程控制&#xff0c;简称APC&#xff0c;并不是什么新概念。它仅…

STM32与多台MS5803压力传感器I2C通讯

MS5803压力传感器支持SPI和I2C总线通讯&#xff0c;拥有24位AD转换。能够同时获得压力值和温度值&#xff0c;其中压力测量范围为10-1100mbar&#xff0c;温度的测量范围是-40-85摄氏度。各引脚功能及参数如下&#xff1a; 传感器内部结构图如下&#xff1a; 通讯协议的选择通过…

STM32F0使用LL库实现SHT70通讯

在本次项目中&#xff0c;限于空间要求我们选用了STM32F030F4作为控制芯片。这款MCU不但封装紧凑&#xff0c;而且自带的Flash空间也非常有限&#xff0c;所以我们选择了LL库实现。本篇我们将基于LL库采用模拟I2C接口的方式实现温湿度采集。 1、SHT70简述 SHT70是一款集温湿度…

STM32F0使用LL库实现PWM输出

在本次项目中&#xff0c;限于空间要求我们选用了STM32F030F4作为控制芯片。这款MCU不但封装紧凑&#xff0c;而且自带的Flash空间也非常有限&#xff0c;所以我们选择了LL库实现。本文我们将说明如何通过LL库实现PWM信号的输出。 1、概述 我们知道STM32的TIM计时器可以输出P…

STM32F0使用LL库实现Modbus通讯

在本次项目中&#xff0c;限于空间要求我们选用了STM32F030F4作为控制芯片。这款MCU不但封装紧凑&#xff0c;而且自带的Flash空间也非常有限&#xff0c;所以我们选择了LL库实现。本篇将说明基于LL实现USART通讯。 1、概述 我们想要实现基于RS485的Modbus通讯实际就是基于US…

STM32基于SPI和AD7192的数据采集

在开发臭氧发生器的时&#xff0c;我们需要一个高分辨率的AD采集&#xff0c;于是选择了AD7192&#xff0c;选择这款ADC的原因比较简单。首先它是24位的符合我们的精度要求&#xff1b;其次它自带时钟&#xff0c;便于节省空间&#xff1b;第三它有4路单端或2路差分输入&#x…

Modbus协议栈实现Modbus RTU多主站支持

前面我们已经详细讲解过Modbus协议栈的开发过程&#xff0c;并且利用协议栈封装了Modbus RTU主站和从站&#xff0c;Modbus TCP服务器与客户端&#xff0c;Modbus ASCII主站与从站应用。但在使用过程中&#xff0c;我们发现一些使用不便和受限的地方&#xff0c;所以我们就想要…

STM32基于AD5663的UV灯电压控制

在开发臭氧发生器的时&#xff0c;我们使用UV灯来实现臭氧的产生。而UV灯的强度决定了臭氧产生的浓度&#xff0c;UV灯的光强则与其控制电压密切相关。所以我们要控制产生的臭氧的浓度就需要调节其控制电压。我们选择了AD5663这一模拟量输出模块来实现这一点。 1、AD5663简介 …

实现Modbus ASCII多主站应用

前面我们已经分析了Modbus RTU的更新设计和具体实现&#xff08;如果不清楚可查看前一篇文章&#xff09;。其实Modbus ASCII与Modbus RTU都是基于串行链路实现的&#xff0c;所以有很多的共同点&#xff0c;基于此&#xff0c;这篇文章我们只讨论与Modbus RTU所不同的部分。 …

STM32一种基于NTC的控温电路及软件实现

NTC&#xff08;Negative Temperature Coefficient&#xff09;是一种随温度上升时&#xff0c;电阻值呈指数关系减小的热敏电阻。应用广泛&#xff0c;最近我们就采用了NTC来控制加热并测温&#xff0c;并达到了预期的效果。 1、硬件设计 我们使用三极管作为加热元件&#x…

STM32利用光敏二极管实现光度测量

最近我们在开发臭氧发生器时&#xff0c;需要监测生成的臭氧的浓度&#xff0c;于是想到使用光度计来测量。因为不同浓度的臭氧对管的吸收作用是不相同的&#xff0c;于是检测光照强度的变化就可以得到相应的浓度数据。 1、硬件设计 此次光照度检测我们选用了S1336-5BQ光电点二…

STM32的ADC通道间干扰的问题

最近我们在开发一个项目时&#xff0c;用到了MCU自带的ADC&#xff0c;在调试过程中发现通道之间村在相互干扰的问题。以前其实也用过好几次&#xff0c;但要求都不高所以没有太关注&#xff0c;此次因为物理量的量程较大&#xff0c;所以看到了变化。 首先来说明一下此次的软…

实现Modbus TCP多网段客户端应用

对于Modbus TCP来说与Modbus RTU和Modbus ASCII有比较大的区别&#xff0c;因为它是运行于以太网链路之上&#xff0c;是运行于TCP/IP协议之上的一种应用层协议。在协议栈的前两个版本中&#xff0c;Modbus TCP作为客户端时也存在一些局限性。我们将对这些不足作一定更新。 1、…

改进初学者的PID-介绍

最近看到了Brett Beauregard发表的有关PID的系列文章&#xff0c;感觉对于理解PID算法很有帮助&#xff0c;于是将系列文章翻译过来&#xff01;在自我提高的过程中&#xff0c;也希望对同道中人有所帮助。作者Brett Beauregard的原文网址&#xff1a;http&#xff1a;//brettb…

改进初学者的PID-采样时间

最近看到了Brett Beauregard发表的有关PID的系列文章&#xff0c;感觉对于理解PID算法很有帮助&#xff0c;于是将系列文章翻译过来&#xff01;在自我提高的过程中&#xff0c;也希望对同道中人有所帮助。作者Brett Beauregard的原文网址&#xff1a;http&#xff1a;//brettb…

改进初学者的PID-微分冲击

最近看到了Brett Beauregard发表的有关PID的系列文章&#xff0c;感觉对于理解PID算法很有帮助&#xff0c;于是将系列文章翻译过来&#xff01;在自我提高的过程中&#xff0c;也希望对同道中人有所帮助。作者Brett Beauregard的原文网址&#xff1a;http&#xff1a;//brettb…

LwIP应用开发笔记之一:LwIP无操作系统基本移植

现在&#xff0c;TCP/IP协议的应用无处不在。随着物联网的火爆&#xff0c;嵌入式领域使用TCP/IP协议进行通讯也越来越广泛。在我们的相关产品中&#xff0c;也都有应用&#xff0c;所以我们结合应用实际对相关应用作相应的总结。 1、技术准备 我们采用的开发平台是STM32F407…

改进初学者的PID-修改整定参数

最近看到了Brett Beauregard发表的有关PID的系列文章&#xff0c;感觉对于理解PID算法很有帮助&#xff0c;于是将系列文章翻译过来&#xff01;在自我提高的过程中&#xff0c;也希望对同道中人有所帮助。作者Brett Beauregard的原文网址&#xff1a;http&#xff1a;//brettb…

改进初学者的PID-积分饱和

最近看到了Brett Beauregard发表的有关PID的系列文章&#xff0c;感觉对于理解PID算法很有帮助&#xff0c;于是将系列文章翻译过来&#xff01;在自我提高的过程中&#xff0c;也希望对同道中人有所帮助。作者Brett Beauregard的原文网址&#xff1a;http&#xff1a;//brettb…

改进初学者的PID-手自动切换

最近看到了Brett Beauregard发表的有关PID的系列文章&#xff0c;感觉对于理解PID算法很有帮助&#xff0c;于是将系列文章翻译过来&#xff01;在自我提高的过程中&#xff0c;也希望对同道中人有所帮助。作者Brett Beauregard的原文网址&#xff1a;http&#xff1a;//brettb…