日韩在线不卡免费视频一区,日韩欧美精品一区二区三区经典,日产精品码2码三码四码区,人妻无码一区二区三区免费,日本feerbbwdh少妇丰满

圖解FreeRTOS 原理系列之任務管理器基本框架

學習梳理一下FreeRTOS任務管理單元實現(xiàn)思路,代碼分析基于V10.4.3。從本文開始計劃寫個圖解freeRTOS內核系列筆記分享給朋友們,希望大家喜歡。文章中或有錯誤,也請留言交流指正,或加本人微信進行交流~

本文主要學習梳理FreeRTOS任務管理器的基本原理,大體框架。

內核任務管理器需求

先來對比一下裸奔系統(tǒng)與RTOS應用系統(tǒng)的編程模型,看看兩種編程的不同畫風。

裸奔系統(tǒng)

在不用RTOS的單片機應用開發(fā)時,編程模型大概是這樣的畫風:

  • 程序的主體是一個死循環(huán),該應用程序由一系列協(xié)同工作的函數(shù)片段組成,相互實現(xiàn)邏輯配合,實現(xiàn)用戶業(yè)務需求。該應用程序獨占單片機,常規(guī)的單片機系統(tǒng)都僅有有一個計算單元核。
  • 普通外設I/O,這里所說I/O是指廣義的I/O,比如GPIO、PWM、ADC、DAC、LCD顯示(當然這里并不嚴謹,比如ADC,DAC、LCD等也可以產生中斷)等。中斷函數(shù)將異步事件接收成或報文或標志或數(shù)值,在與主循環(huán)發(fā)生邏輯關聯(lián)。
  • 中斷外設,比如UART、USB、I2C、定時器、DMA等根據應用需求而使用的中斷。這些中斷都需要相應的中斷函數(shù)進行處理異步中斷事件。對于輸出可能采樣主動輸出,一般由主循環(huán)某一個動作執(zhí)行;對于輸入設備或許采用輪詢方式,在與主循環(huán)進行耦合。

RTOS應用系統(tǒng)

在一個基于RTOS應用系統(tǒng)中,其編程模型大致是下面這樣一個畫風,有多個并行的任務在相對長的宏觀時間維度看起來,多個任務是并行運行的,但對于常規(guī)單片機而言(一般都是單核),任一時刻只有一個任務或中斷函數(shù)在獨占CPU核。

  • 常見的RTOS沒有設備驅動模型,沒有對外設設備進行抽象,中斷函數(shù)將會由用戶或調用RTOS 機制,比如event/signal等與任務進行通信
  • 任務間還有可能需要通信,或傳遞消息,或完成某項需求相互間需要同步等
  • 同樣任務需要與硬件普通IO外設進行打交道,或入或出。但有可能是這個任務實現(xiàn),也有可能是哪個任務執(zhí)行。完全取決于開發(fā)人員如何設計。
  • RTOS實現(xiàn)任務的切入切出,切入使某任務運行;切出使某任務掛起,出讓CPU,暫停運行。
  • RTOS充當?shù)讓又С止δ?,RTOS還提供豐富的時間管理,隊列、郵箱等機制供應用開發(fā)使用。
  • ......

對于單片機而言,一般只有一個核,所有RTOS為了方便理解,可以看成是最最主要的目就是通過軟件方法將硬件CPU核程序運行環(huán)境抽象為每一個應用任務虛擬出一個軟核。這樣從時間維度上看起來多任務是并行的,而事實上這種并行是偽并行。

上圖僅僅為理解RTOS作用方便,這種虛擬核本質上并不存在,只是將硬件CPU核的運行時上下文(PC指針、狀態(tài)寄存器等寄存器組、任務運行時臨時變量等)通過快照保存切入切出而實現(xiàn)多任務的偽并行運行。

FreeRTOS任務管理器需求

從前文看出,任務管理要實現(xiàn)任務的切入、切出,則首先需要對任務進行抽象描述,以實現(xiàn)在CPU上能夠實現(xiàn)切換。根據閱讀代碼以及文獻加上自己的理解,將內核任務管理器的主要功能需求大致梳理成下面這樣一張用例圖Use case Diagram,僅僅為理解方便,或許并不嚴謹。

從上圖,大致可以看出FreeRTOS任務調度器需要以下一些功能需求:

  • 任務抽象描述,一個任務一般本質上是一個死循環(huán)程序片段(當然也有任務運行著會退出被殺掉的可能)。對于任務的抽象:
    • 一般會有任務的執(zhí)行主體,利用函數(shù)主體函數(shù)指針進行抽象
    • RTOS常規(guī)都是的基于優(yōu)先級搶占調度算法,因此需要抽象出哪個任務具有更高概率能被執(zhí)行,用優(yōu)先級進行描述
    • 任務需要得以切換,就需要將任務在切換間的臨時狀態(tài)進行保存,棧機制就能很好的滿足這樣的需求,因此每個任務都有一個或大或小的任務棧。其本質上是一片連續(xù)的FILO(先入后出)內存。
    • .....
  • 任務創(chuàng)建、刪除等API接口,供應用開發(fā)使用。
  • 任務調度器控制接口,啟動調度器、停止調度器、掛起所有任務、恢復運行等調度器接口。
  • 任務雜項信息接口,比如獲取任務狀態(tài)、tick信息、調試、獲取任務名等API接口
  • 任務調度算法,基于調度策略對運行時的任務進行調度,或掛起、或運行、或就緒等,主要根據調度策略管理任務的切入切出。這里主要涉及到任務間上下文切換、任務與中斷函數(shù)間的上下文切換兩種場景。
  • 抽象C運行時環(huán)境,現(xiàn)代RTOS應用系統(tǒng)一般基于C語言,抽象C運行時環(huán)境,這里主要指棧,當然很多RTOS內核也內核堆,freeRTOS也不例外。熟悉C編程的朋友都知道,堆內存由malloc/free函數(shù)操作集提供用戶接口,既然C堆已有,為何RTOS內核重新造輪子?為啥內核額外需要實現(xiàn)自己的堆管理器呢?這大體是基于下面些緣由:
    • 編譯器C堆實現(xiàn),在小型嵌入式系統(tǒng)上有時候并不能直接使用。
    • C堆的實現(xiàn)可能相對較大,占用了較大代碼空間。比較浪費有限的代碼存儲空間。
    • C堆很少是線程安全的。
    • C堆申請執(zhí)行時間不是確定的, 執(zhí)行功能所需的時間因調用而異。
    • C堆會在單片機有限的內存資源引發(fā)內存碎片問題。
    • C堆會使鏈接器配置復雜化。
    • C堆如引發(fā)未知錯誤,不便于調試。

FreeRTOS任務描述抽象

對于其中幾項必須的關鍵數(shù)據域描述一下其抽象作用:

  • pxTopOfStack:指向任務棧棧頂指針
  • xStateListItem:任務狀態(tài)鏈表描述節(jié)點,用于動態(tài)將該任務添加、刪除到就緒或阻塞任務對列鏈表中
  • xEventListItem:事件鏈表描述節(jié)點,描述本任務相關事件,用于將本任務添加到事件鏈表中。
  • uxPriority:任務優(yōu)先級,用于描述本任務的優(yōu)先級。
  • pxStack:任務棧指針,指向本任務的任務棧。
  • pcTaskName:任務名字符串存儲區(qū),長度可配。默認為16字節(jié)

其他的數(shù)據域,可裁剪實現(xiàn)一些更豐富的功能,比如主要用于防治優(yōu)先級反轉的優(yōu)先級繼承機制,trace追蹤功能等。限于篇幅,也主要梳理任務管理器的主要原理,就不展開了。

任務創(chuàng)建刪除管理

FreeRTOS為用戶提供一組函數(shù)集用于任務的創(chuàng)建、刪除等管理,先看任務的創(chuàng)建API:

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
      const char * const pcName,     
      const configSTACK_DEPTH_TYPE usStackDepth,
      void * const pvParameters,
      UBaseType_t uxPriority,
      TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION;

TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
        const char * const pcName,    
        const uint32_t ulStackDepth,
        void * const pvParameters,
        UBaseType_t uxPriority,
        StackType_t * const puxStackBuffer,
        StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION;

BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition,
          TaskHandle_t * pxCreatedTask ) PRIVILEGED_FUNCTION;

BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition,
          TaskHandle_t * pxCreatedTask ) PRIVILEGED_FUNCTION;
  • xTaskCreate/xTaskCreateStatic 都是用于創(chuàng)建任務而用,其區(qū)別在于:
    • xTaskCreate 申請任務控制塊以及棧從內核堆申請
    • xTaskCreateStatic 創(chuàng)建的任務,其任務控制塊內存以及任務棧內存由用戶傳入。或許有朋友會問StaticTask_t這不是任務控制塊嘛,仔細看看其結構定義其內存對齊及大小剛好是前面說的任務控制塊的定義。
  • xTaskCreateRestricted() /xTaskCreateRestrictedStatic(),主要用于在有或使能MPU單元的芯片中創(chuàng)建任務。這里的MPU是指Memory Protection Unit (MPU),不是微處理器的意思。這兩者的區(qū)別與上面兩個API類似,主要在于其內存分配方式不同,xTaskCreateRestricted是從內核堆動態(tài)申請,xTaskCreateRestrictedStatic用戶傳入。
  • PRIVILEGED_FUNCTION 這個宏是用于存儲保護單元芯片的。

這幾個任務創(chuàng)建函數(shù)都是用于任務創(chuàng)建,任務一旦創(chuàng)建就會被插入任務就緒鏈表中,當調度器調度啟動后就按任務狀態(tài)機根據調度策略以及外部輸入事件進行調度接管。這里以xTaskCreate繪制一下其內在干了些啥:

再看看另外兩個函數(shù):

void vTaskAllocateMPURegions( TaskHandle_t xTask,
        const MemoryRegion_t * const pxRegions ) PRIVILEGED_FUNCTION;
void vTaskDelete( TaskHandle_t xTaskToDelete ) PRIVILEGED_FUNCTION;
  • vTaskAllocateMPURegions: 定義一組內存保護單元(MPU)區(qū)域,供MPU受限任務使用.
  • vTaskDelete: 刪除用使用xTaskCreate()或xTaskCreateStatic()創(chuàng)建的任務。

任務控制管理接口

void vTaskDelay( const TickType_t xTicksToDelay ) PRIVILEGED_FUNCTION;
BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
                            const TickType_t xTimeIncrement ) PRIVILEGED_FUNCTION;
BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
UBaseType_t uxTaskPriorityGetFromISR( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
eTaskState eTaskGetState( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
void vTaskGetInfo( TaskHandle_t xTask,
                   TaskStatus_t * pxTaskStatus,
                   BaseType_t xGetFreeStackSpace,
                   eTaskState eState ) PRIVILEGED_FUNCTION;
void vTaskPrioritySet( TaskHandle_t xTask,
                       UBaseType_t uxNewPriority ) PRIVILEGED_FUNCTION;
void vTaskSuspend( TaskHandle_t xTaskToSuspend ) PRIVILEGED_FUNCTION;
void vTaskResume( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;
BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;

這一系列的API接口操作集主要用于對任務進行掛起延時、獲取優(yōu)先級、自中斷函數(shù)獲取優(yōu)先級、掛起、恢復運行等操作。基本從其函數(shù)名就可以看出其作用。比如:

  • vTaskDelay調用,會使調用該函數(shù)的任務進入阻塞狀態(tài)一段時間,時間為傳入的tick數(shù)。

這里需要注意的是有的函數(shù)在中斷函數(shù)體里面不可以調用,需要使用專用版本,具體可以看看手冊或注釋。

調度器控制接口

void vTaskStartScheduler( void ) PRIVILEGED_FUNCTION;
void vTaskEndScheduler( void ) PRIVILEGED_FUNCTION;
void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION;
BaseType_t xTaskResumeAll( void ) PRIVILEGED_FUNCTION;

這一組函數(shù)API集主要用于調度器的啟動、停止控制:

  • vTaskStartScheduler,主要用于待用戶任務創(chuàng)建好后,硬件初始化后,啟動內核調度器
  • vTaskEndScheduler,可用于停止內核調度器,一般很少用到,在一些安全相關的應用可能會在出故障時主動停止調度器。
  • vTaskSuspendAll,掛起所有任務,可以用用戶邏輯主動掛起所有的任務
  • xTaskResumeAll,恢復所有任務為就緒態(tài)。

任務雜項API集

我根據代碼及注釋及自己理解,將這些API歸類到雜項API集合:

TickType_t xTaskGetTickCountFromISR( void ) PRIVILEGED_FUNCTION;
UBaseType_t uxTaskGetNumberOfTasks( void ) PRIVILEGED_FUNCTION;
char * pcTaskGetName( TaskHandle_t xTaskToQuery ) PRIVILEGED_FUNCTION;     
TaskHandle_t xTaskGetHandle( const char * pcNameToQuery ) PRIVILEGED_FUNCTION;   
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
void vTaskSetApplicationTaskTag( TaskHandle_t xTask,
         TaskHookFunction_t pxHookFunction ) PRIVILEGED_FUNCTION;
TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
TaskHookFunction_t xTaskGetApplicationTaskTagFromISR( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;

void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet,
          BaseType_t xIndex,
          void * pvValue ) PRIVILEGED_FUNCTION;
void * pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery,

void vApplicationStackOverflowHook( TaskHandle_t xTask,
           char * pcTaskName );
void vApplicationTickHook( void ); 
......
BaseType_t xTaskGenericNotifyStateClear( TaskHandle_t xTask,
                                         UBaseType_t uxIndexToClear ) PRIVILEGED_FUNCTION;

uint32_t ulTaskGenericNotifyValueClear( TaskHandle_t xTask,
                                        UBaseType_t uxIndexToClear,
                                        uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION;
void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION;

BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut,
                                 TickType_t * const pxTicksToWait ) PRIVILEGED_FUNCTION;

BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) PRIVILEGED_FUNCTION;

這些函數(shù)具體作用就不贅述,這里僅僅梳理分類,用到時候查手冊即可。

跨平臺移植接口

BaseType_t xTaskIncrementTick( void ) PRIVILEGED_FUNCTION;
void vTaskPlaceOnEventList( List_t * const pxEventList,
                            const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
void vTaskPlaceOnUnorderedEventList( List_t * pxEventList,
                                     const TickType_t xItemValue,
                                     const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
void vTaskPlaceOnEventListRestricted( List_t * const pxEventList,
                                      TickType_t xTicksToWait,
                                      const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION;
BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) PRIVILEGED_FUNCTION;
void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem,
                                        const TickType_t xItemValue ) PRIVILEGED_FUNCTION;

portDONT_DISCARD void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION;
TickType_t uxTaskResetEventItemValue( void ) PRIVILEGED_FUNCTION;
TaskHandle_t xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
void vTaskMissedYield( void ) PRIVILEGED_FUNCTION;
BaseType_t xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION;
BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder,
UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
void vTaskSetTaskNumber( TaskHandle_t xTask,
                         const UBaseType_t uxHandle ) PRIVILEGED_FUNCTION;
void vTaskStepTick( const TickType_t xTicksToJump ) PRIVILEGED_FUNCTION;


eSleepModeStatus eTaskConfirmSleepModeStatus( void ) PRIVILEGED_FUNCTION;

TaskHandle_t pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION;

void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION;

這些接口不同硬件平臺需要做具化的移植,做差異化的處理,但是對于FreeRTOS統(tǒng)一了內部調用的接口。這樣的思路在應用開發(fā)時也可以考慮使用,對于公共部分可以抽象出統(tǒng)一的接口,這樣在不同平臺上可以很方便的進行移植。對于這些接口后面有機會學習整理分享。

對于用例圖中的其他部分,核心調度部分以及上下文切換,篇幅所限留在后面學習整理分享。

總結一下

本文基本學習梳理了一下對于FreeRTOS任務調度器外部接口、以及大體作用,基本組成情況,水平所限,文章中錯誤難免,歡迎交流指正。

聲明:本內容為作者獨立觀點,不代表電子星球立場。未經允許不得轉載。授權事宜與稿件投訴,請聯(lián)系:editor@netbroad.com
覺得內容不錯的朋友,別忘了一鍵三連哦!
贊 1
收藏 3
關注 80
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧