FreeRTOS如何结束和重新启动调度程序
大多數(shù)主機(jī)或桌面系統(tǒng)(比如Linux,Mac或Windows)都有一個(gè)正常的用例,你可以在早上啟動(dòng)操作系統(tǒng),然后在晚上關(guān)閉它,然后你就離開機(jī)器。嵌入式系統(tǒng)是不同的:他們沒有參加,他們應(yīng)該“永遠(yuǎn)”運(yùn)行。并非每個(gè)嵌入式系統(tǒng)都需要運(yùn)行操作系統(tǒng)(或者在那個(gè)世界中:實(shí)時(shí)操作系統(tǒng)或RTOS),但這同樣適用于:在RTOS啟動(dòng)后,并不意味著它將關(guān)閉并重新啟動(dòng)。在某種程度上,他們根本不支持“關(guān)閉”和“重啟”功能。如果收集覆蓋率信息,這將非常有用:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 來自FreeRTOS應(yīng)用程序的覆蓋信息
對(duì)于FreeRTOS:如果我真的需要關(guān)閉RTOS并重新啟動(dòng)它會(huì)怎么樣,因?yàn)槟J(rèn)情況下不支持。這就是本文的內(nèi)容......
介紹
嵌入式系統(tǒng)與桌面系統(tǒng)根本不同:雖然不時(shí)關(guān)閉和重新啟動(dòng)臺(tái)式機(jī)或筆記本電腦系統(tǒng)是正常的,但這不是計(jì)劃或打算用于嵌入式系統(tǒng):本質(zhì)上它應(yīng)該“始終”運(yùn)行。從嵌入式系統(tǒng)的“主要”進(jìn)一步可以看出這一點(diǎn):通常主要永遠(yuǎn)不會(huì)返回并保持運(yùn)行,如下所示:
| void?main(void) { ??InitClocks(); ??InitPins(); ??InitDrivers(); ??for(;;) { ????AppRun(); ??} ??/* 從未離開主程序 */ } |
如果使用RTOS運(yùn)行,類似的東西適用于嵌入式系統(tǒng),其中看起來類似于:
| void?main(void) { ??InitClocks(); ??InitPins(); ??InitDrivers(); ??CreateInitialTasks(); ??StartScheduler(); ??/* 調(diào)度程序永遠(yuǎn)不會(huì)終止,所以不應(yīng)該到達(dá)這里 */ ??for(;;) { } ??/* 從未離開主程序?*/ } |
為什么關(guān)機(jī)并重啟?
顯然,對(duì)于嵌入式RTOS而言,RTOS關(guān)閉或重啟的需求可能不是最需要的。我仍然發(fā)現(xiàn)它非常有用:
- 在RTOS關(guān)閉后運(yùn)行某些軟件*是有意義的。例如,如果我收集覆蓋率信息(請(qǐng)參閱“?向Eclipse添加GNU覆蓋工具?”和“?使用Eclipse Neon和ARM gcc 5在嵌入式目標(biāo)上實(shí)現(xiàn)GNU代碼覆蓋率?”),我不希望干擾最后一個(gè)進(jìn)程以轉(zhuǎn)儲(chǔ)數(shù)據(jù)RTOS。另外,我需要獨(dú)占訪問系統(tǒng)資源,包括大量的堆棧空間:關(guān)閉RTOS可以讓我恢復(fù)文件I / O操作所需的所有RAM和堆棧空間。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?在調(diào)度程序關(guān)閉后寫入gcov覆蓋信息
- 在監(jiān)聽更新時(shí)運(yùn)行RTOS是有意義的。在某些情況下,在執(zhí)行更新時(shí)運(yùn)行RTOS肯定是可能的,但在某些階段我必須停止并重新啟動(dòng)它。這可以通過重置和重新啟動(dòng)系統(tǒng)來完成(例如,請(qǐng)參閱“?如何使用軟件重置ARM Cortex-M?”)。我發(fā)現(xiàn)它是關(guān)閉RTOS的更好方法,然后在RTOS之外進(jìn)行更新并重啟系統(tǒng)。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 從任務(wù)結(jié)束FreeRTOS調(diào)度程序
- 另一個(gè)用例是低功耗應(yīng)用。雖然FreeRTOS在低功耗模式下也很出色(參見“?使用FreeRTOS實(shí)現(xiàn)低功耗:無空閑模式?”),但如果可以關(guān)閉更多活動(dòng)系統(tǒng),應(yīng)用程序甚至可以進(jìn)入功耗更低的低功耗模式。因此,只有在我的應(yīng)用程序的使用壽命期間才能運(yùn)行RTOS才能有意義,而不是在其他部分運(yùn)行RTOS,這為我提供了更大的靈活性和更低功耗的機(jī)會(huì)。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? vTaskStartScheduler()后跟低功耗模式
所以我希望你明白為什么RTOS的關(guān)閉和重啟是有意義的。包括FreeRTOS在內(nèi)的大多數(shù)RTOS都能夠“靜音”調(diào)度程序(例如vTaskSuspendAll()),但仍然存在RTOS并使用系統(tǒng)資源。但是,如果需要,完全“刪除”并重新啟動(dòng)它的能力將是很酷的事情。
FreeRTOS
FreeRTOS確實(shí)有一個(gè)調(diào)度程序啟動(dòng)函數(shù)(vTaskStartScheduler()),甚至在其API中有一個(gè)vTaskEndScheduler()函數(shù):
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FreeRTOS vTaskEndScheduler()API函數(shù)
但正如論壇和API描述中所述,它僅支持PC端口(請(qǐng)參閱API說明):“?注意:這僅適用于x86實(shí)模式PC端口。“
原來的FreeRTOS端口也是如此。我擴(kuò)展的端口確實(shí)支持這個(gè),我在ARM Cortex-M和HCS08應(yīng)用程序中使用它:-)。
vTaskEndScheduler()和vTaskStartScheduler()
雖然RTOS已準(zhǔn)備好將其關(guān)閉的API調(diào)用,但FreeRTOS在調(diào)用vTaskEndScheduler()之后沒有適當(dāng)?shù)幕A(chǔ)結(jié)構(gòu)來重新啟動(dòng)RTOS。但這正是我想要的:在結(jié)束后重啟RTOS。
要能夠結(jié)束調(diào)度程序,必須在FreeRTOSConfig.h中將以下宏設(shè)置為1:
| #define INCLUDE_vTaskEndScheduler???????????????? 1 |
挑戰(zhàn)在于:在調(diào)度程序啟動(dòng)之后,在vTaskStartScheduler()調(diào)用之后立即返回代碼并不容易。因?yàn)榫哂凶约旱亩褩5娜蝿?wù),加上FreeRTOS和M3的標(biāo)準(zhǔn)端口,M4和M7甚至?xí)刂肕SP堆棧指針(參見本論壇討論)。因此,如果我想返回調(diào)度程序已啟動(dòng)的位置,我需要阻止重置ARM Cortex上的MSP堆棧指針。這就是我為FreeRTOS添加一個(gè)設(shè)置來配置它的原因:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?重置MSP設(shè)置
這將設(shè)置以下配置:
| #ifndef configRESET_MSP ??#define configRESET_MSP???????????????????????? (0) ???/*!< 1: reset MSP at scheduler start (Cortex M3/M4/M7 only); 0: do not reset MSP */ #endif |
將此設(shè)置設(shè)置為0,我的端口在調(diào)度程序起始點(diǎn)執(zhí)行*不*重置MSP。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 端口代碼重置msp堆棧指針
這意味著并非完整的MSP堆棧可用于中斷(參見“?ARM Cortex-M中斷和FreeRTOS:第3部分?”),但這通常也可以。
為了能夠跳回到調(diào)度程序的起點(diǎn),我使用了C庫(kù)的一個(gè)很酷的功能:setjmp / longjmp(參見http://web.eecs.utk.edu/~huangj/cs360/360/notes/ Setjmp / lecture.html)。
首先,我需要一個(gè)跳轉(zhuǎn)緩沖區(qū)變量:
| #if INCLUDE_vTaskEndScheduler #include <setjmp.h> static?jmp_buf?xJumpBuf; /* Used to restore the original context when the scheduler is ended. */ #endif |
在xPortStartScheduler()里面我設(shè)置了跳轉(zhuǎn)緩沖區(qū):
| #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; |
如果建立跳轉(zhuǎn)緩沖區(qū),setjmp()返回0,并且在調(diào)用setjmp()的情況下返回!= 0將在vTaskEndScheduler()期間調(diào)用。
| 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()執(zhí)行RTOS的所有清理和重置。重置要求不會(huì)造成調(diào)試器對(duì)任何RTOS認(rèn)知的混淆:
| 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 } |
有了這個(gè),調(diào)度程序優(yōu)雅地終止,我又回到了主堆棧上:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 在調(diào)用vTaskEndScheduler()之后在msp堆棧上
摘要
默認(rèn)情況下,對(duì)于嵌入式目標(biāo),FreeRTOS不支持結(jié)束調(diào)度程序或在結(jié)束后重新啟動(dòng)調(diào)度程序。本文描述了ARM Cortex-M的一個(gè)端口,它實(shí)現(xiàn)了vTaskEndScheduler(),并能夠在沒有上電復(fù)位的情況下再次調(diào)用vTaskStartScheduler()。結(jié)束和啟動(dòng)調(diào)度程序?qū)τ诘凸膽?yīng)用程序非常有用,在應(yīng)用程序的實(shí)時(shí)循環(huán)或引導(dǎo)加載程序應(yīng)用程序中不需要RTOS的情況。該概念用于恩智浦的不同ARM Cortex-M內(nèi)核,包括8/16位S08微控制器,但可以輕松用于任何其他微控制器架構(gòu)。
參考鏈接
?
聲明:本文為翻譯文章,原文作者是:Erich Styger,原文網(wǎng)址為:https://mcuoneclipse.com/2019/01/20/freertos-how-to-end-and-restart-the-scheduler/
歡迎關(guān)注:
總結(jié)
以上是生活随笔為你收集整理的FreeRTOS如何结束和重新启动调度程序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 滤波器开发之二:基于算数平均的带阻平滑滤
- 下一篇: 在emIDE中创建STM32项目