<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          FreeRTOS系列第29篇---FreeRTOS空閑任務(wù)分析

          共 6617字,需瀏覽 14分鐘

           ·

          2021-08-09 21:31


          關(guān)注、星標公眾號,直達精彩內(nèi)容

          ID:技術(shù)讓夢想更偉大

          整理:李肖遙


          當RTOS調(diào)度器開始工作后,為了保證至少有一個任務(wù)在運行,空閑任務(wù)被自動創(chuàng)建,占用最低優(yōu)先級(0優(yōu)先級)。

           xReturn = xTaskCreate( prvIdleTask,
                                 "IDLE",configMINIMAL_STACK_SIZE,
                                 (void * ) NULL,
                                 (tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
                                 &xIdleTaskHandle);

          空閑任務(wù)是FreeRTOS不可缺少的任務(wù),因為FreeRTOS設(shè)計要求必須至少有一個任務(wù)處于運行狀態(tài)。我們來看一下空閑任務(wù)要做的工作。

          1.釋放內(nèi)存

          從V9.0版本開始,如果一個任務(wù)刪除另外一個任務(wù),被刪除任務(wù)的堆棧和TCB立即釋放。

          如果一個任務(wù)刪除自己,則任務(wù)的堆棧和TCB和以前一樣,通過空閑任務(wù)刪除。

          所以空閑任務(wù)開始就會檢查是否有任務(wù)刪除了自己,如果有的話,空閑任務(wù)負責刪除這個任務(wù)的TCB和堆棧空間。

          2. 處理空閑優(yōu)先級任務(wù)

          當使用搶占式內(nèi)核,相同優(yōu)先級的任務(wù)使用時間片方式獲得CPU權(quán)限。

          如果有任務(wù)與空閑任務(wù)共享一個優(yōu)先級,并且宏configIDLE_SHOULD_YIELD設(shè)置為1,那么空閑任務(wù)不必等到時間片耗盡再進行任務(wù)切換。

          所以空閑任務(wù)檢查空閑優(yōu)先級下的就緒列表中是否有多個任務(wù),有的話則執(zhí)行任務(wù)切換,讓用戶任務(wù)獲得CPU權(quán)限。

          configIDLE_SHOULD_YIELD控制任務(wù)在空閑優(yōu)先級中的行為。僅在滿足下列條件后,才會起作用。

          1. 使用搶占式內(nèi)核調(diào)度
          2. 用戶任務(wù)使用空閑優(yōu)先級。

          通過時間片共享同一個優(yōu)先級的多個任務(wù),如果共享的優(yōu)先級大于空閑優(yōu)先級,并假設(shè)沒有更高優(yōu)先級任務(wù),這些任務(wù)應(yīng)該獲得相同的處理器時間。

          但如果共享空閑優(yōu)先級時,情況會稍微有些不同。當configIDLE_SHOULD_YIELD為1時,其它共享空閑優(yōu)先級的用戶任務(wù)就緒時,空閑任務(wù)立刻讓出CPU,用戶任務(wù)運行,這樣確保了能最快響應(yīng)用戶任務(wù)。

          處于這種模式下也會有不良效果(取決于你的程序需要),描述如下:

          圖中描述了四個處于空閑優(yōu)先級的任務(wù),任務(wù)A、B和C是用戶任務(wù),任務(wù)I是空閑任務(wù)。

          上下文切換周期性的發(fā)生在T0、T1…T6時刻。

          當用戶任務(wù)運行時,空閑任務(wù)立刻讓出CPU,但是,空閑任務(wù)已經(jīng)消耗了當前時間片中的一定時間。

          這樣的結(jié)果就是空閑任務(wù)I和用戶任務(wù)A共享一個時間片。

          用戶任務(wù)B和用戶任務(wù)C因此獲得了比用戶任務(wù)A更多的處理器時間。

          「可以通過下面方法避免:」

          1. 如果合適的話,將處于空閑優(yōu)先級的各單獨的任務(wù)放置到空閑鉤子函數(shù)中;
          2. 創(chuàng)建的用戶任務(wù)優(yōu)先級大于空閑優(yōu)先級;
          3. 設(shè)置IDLE_SHOULD_YIELD為0;

          設(shè)置configIDLE_SHOULD_YIELD為0將阻止空閑任務(wù)為用戶任務(wù)讓出CPU,直到空閑任務(wù)的時間片結(jié)束。

          這確保所有處在空閑優(yōu)先級的任務(wù)分配到相同多的處理器時間,但是,這是以分配給空閑任務(wù)更高比例的處理器時間為代價的。

          3.執(zhí)行空閑任務(wù)鉤子函數(shù)

          空閑任務(wù)鉤子是一個函數(shù),這個函數(shù)由用戶來實現(xiàn),RTOS規(guī)定了函數(shù)的名字和參數(shù),這個函數(shù)在每個空閑任務(wù)周期都會被調(diào)用。

          「要創(chuàng)建一個空閑鉤子」

          1. 設(shè)置FreeRTOSConfig.h 文件中的configUSE_IDLE_HOOK為1;
          2. 定義一個函數(shù),函數(shù)名和參數(shù)如下所示:
          void vApplicationIdleHook(void ); 

          這個鉤子函數(shù)不可以調(diào)用會引起空閑任務(wù)阻塞的API函數(shù)(例如:vTaskDelay()、帶有阻塞時間的隊列和信號量函數(shù)),在鉤子函數(shù)內(nèi)部使用協(xié)程是被允許的。

          使用空閑鉤子函數(shù)設(shè)置CPU進入省電模式是很常見的。

          4.低功耗tickless模式

          通常情況下,F(xiàn)reeRTOS回調(diào)空閑任務(wù)鉤子函數(shù)(需要設(shè)計者自己實現(xiàn)),在空閑任務(wù)鉤子函數(shù)中設(shè)置微處理器進入低功耗模式來達到省電的目的。

          因為系統(tǒng)要響應(yīng)系統(tǒng)節(jié)拍中斷事件,因此使用這種方法會周期性的退出、再進入低功耗狀態(tài)。

          如果系統(tǒng)節(jié)拍中斷頻率過快,則大部分電能和CPU時間會消耗在進入和退出低功耗狀態(tài)上。

          FreeRTOS的tickless空閑模式會在空閑周期時停止周期性系統(tǒng)節(jié)拍中斷。

          停止周期性系統(tǒng)節(jié)拍中斷可以使微控制器長時間處于低功耗模式。

          移植層需要配置外部喚醒中斷,當喚醒事件到來時,將微控制器從低功耗模式喚醒。微控制器喚醒后,會重新使能系統(tǒng)節(jié)拍中斷。

          由于微控制器在進入低功耗后,系統(tǒng)節(jié)拍計數(shù)器是停止的,但我們又需要知道這段時間能折算成多少次系統(tǒng)節(jié)拍中斷周期;

          這就需要有一個不受低功耗影響的外部時鐘源,即微處理器處于低功耗模式時它也在計時的;

          這樣在重啟系統(tǒng)節(jié)拍中斷時就可以根據(jù)這個外部計時器計算出一個調(diào)整值并寫入RTOS 系統(tǒng)節(jié)拍計數(shù)器變量中。

          空閑任務(wù)的源代碼如下所示,其中宏portTASK_FUNCTION翻譯出來為:void prvIdleTask(void * pvParameters)

          static portTASK_FUNCTION( prvIdleTask,pvParameters )
          {
            /*防止編譯器警告 */
            (void ) pvParameters;
           
            for(;; )
            {
               /*檢查是否有任務(wù)刪除了自己,如果有的話,空閑任務(wù)負責刪除這個任務(wù)的TCB和堆棧空間 */
               prvCheckTasksWaitingTermination();
           
               #if( configUSE_PREEMPTION == 0 )
               {
              /*如果我們沒有使用搶占式調(diào)度,我們會強制任務(wù)切換,看看是否有其它任務(wù)變得有效.
              如果使用搶占式調(diào)度,是不需要這樣的,因為任務(wù)變得有效后會搶占空閑任務(wù).*/
              taskYIELD();
               }
               #endif/* configUSE_PREEMPTION */
           
               #if( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
               {
              /*  當使用搶占式內(nèi)核,相同優(yōu)先級的任務(wù)使用時間片方式獲得CPU權(quán)限.如果有任務(wù)與空閑
              任務(wù)共享一個優(yōu)先級,那么空閑任務(wù)不必等到時間片耗盡再進行任務(wù)切換.
              如果空閑優(yōu)先級下的就緒列表中有多個任務(wù),則執(zhí)行用戶任務(wù)*/
              if(listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) >( UBaseType_t ) 1 )
              {
                 taskYIELD();
              }
               }
               #endif/* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 )) */
           
               #if( configUSE_IDLE_HOOK == 1 )
               {
              externvoid vApplicationIdleHook( void );
           
              /*調(diào)用用戶定義函數(shù).這樣允許設(shè)計者在不增加任務(wù)開銷的情況下實現(xiàn)后臺功能
              注意:這個函數(shù)中絕對不允許調(diào)用任務(wù)可能引起阻塞的函數(shù).*/
              vApplicationIdleHook();
               }
               #endif/* configUSE_IDLE_HOOK */
           
               #if( configUSE_TICKLESS_IDLE != 0 )
               {
               TickType_txExpectedIdleTime;
           
              /*如果每次執(zhí)行空閑任務(wù)都掛起調(diào)度器,然后再解除調(diào)度器,這很難讓人滿意,因此這里
              執(zhí)行兩次同樣的比較(xExpectedIdleTime和configEXPECTED_IDLE_TIME_BEFORE_SLEEP),
              第一次比較是測試一下是否達到預期的空閑時間,并不會掛起調(diào)度器.*/
              xExpectedIdleTime= prvGetExpectedIdleTime();
           
              if(xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
              {
                vTaskSuspendAll();
                {
                   /*現(xiàn)在調(diào)度器被掛起,需要再次采樣空閑時間,這次空閑時間可以使用了*/
                   configASSERT(xNextTaskUnblockTime >= xTickCount );
                   xExpectedIdleTime= prvGetExpectedIdleTime();
           
                   if(xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
                   {
                  portSUPPRESS_TICKS_AND_SLEEP(xExpectedIdleTime );
                   }
                }
                (void ) xTaskResumeAll();
              }
               }
               #endif/* configUSE_TICKLESS_IDLE */
            }
          }
          免責聲明:本文素材來源網(wǎng)絡(luò),版權(quán)歸原作者所有。如涉及作品版權(quán)問題,請與我聯(lián)系刪除。
          ????????????????  END  ????????????????

          關(guān)注我的微信公眾號,回復“加群”按規(guī)則加入技術(shù)交流群。

          歡迎關(guān)注我的視頻號:


          點擊“閱讀原文”查看更多分享,歡迎點分享、收藏、點贊、在看。

          瀏覽 63
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产一级a毛一级a看免费人交 | 国产一纹黄片 | 欧美日日日日 | 成人五月丁香婷 | 人人妻人人澡人人爽 |