首頁 > 軟體

FreeRTOS實時作業系統核心設定說明

2022-04-06 19:02:22

FreeRTOS核心是高度可客製化的,使用組態檔FreeRTOSConfig.h進行客製化。每個FreeRTOS應用都必須包含這個標頭檔案,使用者根據實際應用來裁剪客製化FreeRTOS核心。這個組態檔是針對使用者程式的,而非核心,因此組態檔一般放在應用程式目錄下,不要放在RTOS核心原始碼目錄下。

在下載的FreeRTOS檔案包中,每個演範例程都有一個FreeRTOSConfig.h檔案。有些例程的組態檔是比較舊的版本,可能不會包含所有有效選項。如果沒有在組態檔中指定某個選項,那麼RTOS核心會使用預設值。典型的FreeRTOSConfig.h組態檔定義如下所示,隨後會說明裡面的每一個引數。

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*Here is a good place to include header files that are required across
yourapplication. */
#include "something.h"
#define configUSE_PREEMPTION                    1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#define configUSE_TICKLESS_IDLE                 0
#define configCPU_CLOCK_HZ                      60000000
#define configTICK_RATE_HZ                      250
#define configMAX_PRIORITIES                    5
#define configMINIMAL_STACK_SIZE                128
#define configTOTAL_HEAP_SIZE                   10240
#define configMAX_TASK_NAME_LEN                 16
#define configUSE_16_BIT_TICKS                  0
#define configIDLE_SHOULD_YIELD                 1
#define configUSE_TASK_NOTIFICATIONS            1
#define configUSE_MUTEXES                       0
#define configUSE_RECURSIVE_MUTEXES             0
#define configUSE_COUNTING_SEMAPHORES           0
#define configUSE_ALTERNATIVE_API               0/* Deprecated! */
#define configQUEUE_REGISTRY_SIZE               10
#define configUSE_QUEUE_SETS                    0
#define configUSE_TIME_SLICING                  0
#define configUSE_NEWLIB_REENTRANT              0
#define configENABLE_BACKWARD_COMPATIBILITY     0
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
/*Hook function related definitions. */
#define configUSE_IDLE_HOOK                     0
#define configUSE_TICK_HOOK                     0
#define configCHECK_FOR_STACK_OVERFLOW          0
#define configUSE_MALLOC_FAILED_HOOK            0
/*Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS           0
#define configUSE_TRACE_FACILITY                0
#define configUSE_STATS_FORMATTING_FUNCTIONS    0
/*Co-routine related definitions. */
#define configUSE_CO_ROUTINES                   0
#define configMAX_CO_ROUTINE_PRIORITIES         1
/*Software timer related definitions. */
#define configUSE_TIMERS                        1
#define configTIMER_TASK_PRIORITY               3
#define configTIMER_QUEUE_LENGTH                10
#define configTIMER_TASK_STACK_DEPTH            configMINIMAL_STACK_SIZE
/*Interrupt nesting behaviour configuration. */
#define configKERNEL_INTERRUPT_PRIORITY        [dependent of processor]
#define configMAX_SYSCALL_INTERRUPT_PRIORITY   [dependent on processor and application]
#define configMAX_API_CALL_INTERRUPT_PRIORITY  [dependent on processor and application]
/*Define to trap errors during development. */
#define configASSERT( ( x ) )     if( ( x ) == 0) vAssertCalled( __FILE__, __LINE__ )
/*FreeRTOS MPU specific definitions. */
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0
/*Optional functions - most linkers will remove unused functions anyway. */
#define INCLUDE_vTaskPrioritySet                1
#define INCLUDE_uxTaskPriorityGet               1
#define INCLUDE_vTaskDelete                     1
#define INCLUDE_vTaskSuspend                    1
#define INCLUDE_xResumeFromISR                  1
#define INCLUDE_vTaskDelayUntil                 1
#define INCLUDE_vTaskDelay                      1
#define INCLUDE_xTaskGetSchedulerState          1
#define INCLUDE_xTaskGetCurrentTaskHandle       1
#define INCLUDE_uxTaskGetStackHighWaterMark     0
#define INCLUDE_xTaskGetIdleTaskHandle          0
#define INCLUDE_xTimerGetTimerDaemonTaskHandle  0
#define INCLUDE_pcTaskGetTaskName               0
#define INCLUDE_eTaskGetState                   0
#define INCLUDE_xEventGroupSetBitFromISR        1
#define INCLUDE_xTimerPendFunctionCall          0
/* Aheader file that defines trace macro can be included here. */
#end if/* FREERTOS_CONFIG_H*/

1.configUSE_PREEMPTION

為1時RTOS使用搶佔式排程器,為0時RTOS使用共同作業式排程器(時間片)。

注:在多工管理機制上,作業系統可以分為搶佔式和共同作業式兩種。共同作業式作業系統是任務主動釋放CPU後,切換到下一個任務。工作切換的時機完全取決於正在執行的任務。

2.configUSE_PORT_OPTIMISED_TASK_SELECTION

某些執行FreeRTOS的硬體有兩種方法選擇下一個要執行的任務:通用方法和特定於硬體的方法(以下簡稱“特殊方法”)。

通用方法:

  • configUSE_PORT_OPTIMISED_TASK_SELECTION設定為0或者硬體不支援這種特殊方法。
  • 可以用於所有FreeRTOS支援的硬體。
  • 完全用C實現,效率略低於特殊方法。
  • 不強制要求限制最大可用優先順序數目

特殊方法:

  • 並非所有硬體都支援。
  • 必須將configUSE_PORT_OPTIMISED_TASK_SELECTION設定為1。
  • 依賴一個或多個特定架構的組合指令(一般是類似計算前導零[CLZ]指令)。
  • 比通用方法更高效。
  • 一般強制限定最大可用優先順序數目為32。

3.configUSE_TICKLESS_IDLE

設定configUSE_TICKLESS_IDLE為1使能低功耗tickless模式,為0保持系統節拍(tick)中斷一直執行。

通常情況下,FreeRTOS回撥空閒任務勾點函數(需要設計者自己實現),在空閒任務勾點函數中設定微處理器進入低功耗模式來達到省電的目的。因為系統要響應系統節拍中斷事件,因此使用這種方法會週期性的退出、再進入低功耗狀態。如果系統節拍中斷頻率過快,則大部分電能和CPU時間會消耗在進入和退出低功耗狀態上。

FreeRTOS的tickless空閒模式會在空閒週期時停止週期性系統節拍中斷。停止週期性系統節拍中斷可以使微控制器長時間處於低功耗模式。移植層需要設定外部喚醒中斷,當喚醒事件到來時,將微控制器從低功耗模式喚醒。微控制器喚醒後,會重新使能系統節拍中斷。由於微控制器在進入低功耗後,系統節拍計數器是停止的,但我們又需要知道這段時間能折算成多少次系統節拍中斷週期,這就需要有一個不受低功耗影響的外部時鐘源,即微處理器處於低功耗模式時它也在計時的,這樣在重啟系統節拍中斷時就可以根據這個外部計時器計算出一個調整值並寫入RTOS 系統節拍計數器變數中。

4.configUSE_IDLE_HOOK

設定為1使用空閒勾點(Idle Hook類似於回撥函數),0忽略空閒勾點。

當RTOS排程器開始工作後,為了保證至少有一個任務在執行,空閒任務被自動建立,佔用最低優先順序(0優先順序)。對於已經刪除的RTOS任務,空閒任務可以釋放分配給它們的堆疊記憶體。因此,在應用中應該注意,使用vTaskDelete()函數時要確保空閒任務獲得一定的處理器時間。除此之外,空閒任務沒有其它特殊功能,因此可以任意的剝奪空閒任務的處理器時間。

應用程式也可能和空閒任務共用同個優先順序。

空閒任務勾點是一個函數,這個函數由使用者來實現,RTOS規定了函數的名字和引數,這個函數在每個空閒任務週期都會被呼叫。

要建立一個空閒勾點:

設定FreeRTOSConfig.h 檔案中的configUSE_IDLE_HOOK 為1;

定義一個函數,函數名和引數如下所示:

void vApplicationIdleHook(void );

這個勾點函數不可以呼叫會引起空閒任務阻塞的API函數(例如:vTaskDelay()、帶有阻塞時間的佇列和號誌函數),在勾點函數內部使用協程是被允許的。

使用空閒勾點函數設定CPU進入省電模式是很常見的。

5.configUSE_MALLOC_FAILED_HOOK

每當一個任務、佇列、號誌被建立時,核心使用一個名為pvPortMalloc()的函數來從堆中分配記憶體。官方的下載包中包含5個簡單記憶體分配策略,分別儲存在原始檔heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5.c中。僅當使用這五個簡單策略之一時,宏configUSE_MALLOC_FAILED_HOOK才有意義。

如果定義並正確設定malloc()失敗勾點函數,則這個函數會在pvPortMalloc()函數返回NULL時被呼叫。只有FreeRTOS在響應記憶體分配請求時發現堆記憶體不足才會返回NULL。

如果宏configUSE_MALLOC_FAILED_HOOK設定為1,那麼必須定義一個malloc()失敗勾點函數,如果宏configUSE_MALLOC_FAILED_HOOK設定為0,malloc()失敗勾點函數不會被呼叫,即便已經定義了這個函數。malloc()失敗勾點函數的函數名和原型必須如下所示:

void vApplicationMallocFailedHook( void);

6.configUSE_TICK_HOOK

設定為1使用時間片勾點(Tick Hook),0忽略時間片勾點。

注:時間片勾點函數(Tick Hook Function)

時間片中斷可以週期性的呼叫一個被稱為勾點函數(回撥函數)的應用程式。時間片勾點函數可以很方便的實現一個定時器功能。

只有在FreeRTOSConfig.h中的configUSE_TICK_HOOK設定成1時才可以使用時間片勾點。一旦此值設定成1,就要定義勾點函數,函數名和引數如下所示:

void vApplicationTickHook( void );

vApplicationTickHook()函數在中斷服務程式中執行,因此這個函數必須非常短小,不能大量使用堆疊,只能呼叫以”FromISR" 或 "FROM_ISR”結尾的API函數。

在FreeRTOSVx.x.xFreeRTOSDemoCommonMinimal資料夾下的crhook.c檔案中有使用時間片勾點函數的例程。

7.configCPU_CLOCK_HZ

寫入實際的CPU核心時脈頻率,也就是CPU指令執行頻率,通常稱為Fcclk。設定此值是為了正確的設定系統節拍中斷週期。

8.configTICK_RATE_HZ

RTOS 系統節拍中斷的頻率。即一秒中斷的次數,每次中斷RTOS都會進行任務排程。

系統節拍中斷用來測量時間,因此,越高的測量頻率意味著可測到越高的解析度時間。但是,高的系統節拍中斷頻率也意味著RTOS核心佔用更多的CPU時間,因此會降低效率。RTOS演範例程都是使用系統節拍中斷頻率為1000HZ,這是為了測試RTOS核心,比實際使用的要高。(實際使用時不用這麼高的系統節拍中斷頻率)

多個任務可以共用一個優先順序,RTOS排程器為相同優先順序的任務分享CPU時間,在每一個RTOS 系統節拍中斷到來時進行工作切換。高的系統節拍中斷頻率會降低分配給每一個任務的“時間片”持續時間。

9.configMAX_PRIORITIES

設定應用程式有效的優先順序數目。任何數量的任務都可以共用一個優先順序,使用協程可以單獨的給與它們優先權。見configMAX_CO_ROUTINE_PRIORITIES。

在RTOS核心中,每個有效優先順序都會消耗一定量的RAM,因此這個值不要超過你的應用實際需要的優先順序數目。

注:任務優先順序

每一個任務都會被分配一個優先順序,優先順序值從0~ (configMAX_PRIORITIES - 1)之間。低優先順序數表示低優先順序任務。空閒任務的優先順序為0(tskIDLE_PRIORITY),因此它是最低優先順序任務。

FreeRTOS排程器將確保處於就緒狀態(Ready)或執行狀態(Running)的高優先順序任務比同樣處於就緒狀態的低優先順序任務優先獲取處理器時間。換句話說,處於執行狀態的任務永遠是高優先順序任務。

處於就緒狀態的相同優先順序任務使用時間片排程機制共用處理器時間。

10.configMINIMAL_STACK_SIZE

定義空閒任務使用的堆疊大小。通常此值不應小於對應處理器演範例程檔案FreeRTOSConfig.h中定義的數值。

就像xTaskCreate()函數的堆疊大小引數一樣,堆疊大小不是以位元組為單位而是以字為單位的,比如在32位元架構下,棧大小為100表示棧記憶體佔用400位元組的空間。

11.configTOTAL_HEAP_SIZE

RTOS核心總計可用的有效的RAM大小。僅在你使用官方下載包中附帶的記憶體分配策略時,才有可能用到此值。每當建立任務、佇列、互斥量、軟體定時器或號誌時,RTOS核心會為此分配RAM,這裡的RAM都屬於configTOTAL_HEAP_SIZE指定的記憶體區。後續的記憶體設定會詳細講到官方給出的記憶體分配策略。

12.configMAX_TASK_NAME_LEN

呼叫任務函數時,需要設定描述任務資訊的字串,這個宏用來定義該字串的最大長度。這裡定義的長度包括字串結束符’’。

13.configUSE_TRACE_FACILITY

設定成1表示啟動視覺化跟蹤偵錯,會啟用一些附加的結構體成員和函數。

14.configUSE_STATS_FORMATTING_FUNCTIONS(V7.5.0新增)

設定宏configUSE_TRACE_FACILITY和configUSE_STATS_FORMATTING_FUNCTIONS為1會編譯vTaskList()和vTaskGetRunTimeStats()函數。如果將這兩個宏任意一個設定為0,上述兩個函數不會被編譯。

15.configUSE_16_BIT_TICKS

定義系統節拍計數器的變數型別,即定義portTickType是表示16位元變數還是32位元變數。

定義configUSE_16_BIT_TICKS為1意味著portTickType代表16位元無符號整形,定義configUSE_16_BIT_TICKS為0意味著portTickType代表32位元無符號整形。

使用16位元型別可以大大提高8位元和16位元架構微處理器的效能,但這也限制了最大時鐘計數為65535個’Tick’。因此,如果Tick頻率為250HZ(4MS中斷一次),對於任務最大延時或阻塞時間,16位元計數器是262秒,而32位元是17179869秒。

16.configIDLE_SHOULD_YIELD

這個引數控制任務在空閒優先順序中的行為。僅在滿足下列條件後,才會起作用。

  • 使用搶佔式核心排程用
  • 戶任務使用空閒優先順序。

通過時間片共用同一個優先順序的多個任務,如果共用的優先順序大於空閒優先順序,並假設沒有更高優先順序任務,這些任務應該獲得相同的處理器時間。

但如果共用空閒優先順序時,情況會稍微有些不同。當configIDLE_SHOULD_YIELD為1時,其它共用空閒優先順序的使用者任務就緒時,空閒任務立刻讓出CPU,使用者任務執行,這樣確保了能最快響應使用者任務。處於這種模式下也會有不良效果(取決於你的程式需要),描述如下:

圖中描述了四個處於空閒優先順序的任務,任務A、B和C是使用者任務,任務I是空閒任務。上下文切換週期性的發生在T0、T1…T6時刻。當用戶任務執行時,空閒任務立刻讓出CPU,但是,空閒任務已經消耗了當前時間片中的一定時間。這樣的結果就是空閒任務I和使用者任務A共用一個時間片。使用者任務B和使用者任務C因此獲得了比使用者任務A更多的處理器時間。

可以通過下面方法避免:

  • 如果合適的話,將處於空閒優先順序的各單獨的任務放置到空閒勾點函數中;
  • 建立的使用者任務優先順序大於空閒優先順序;
  • 設定IDLE_SHOULD_YIELD為0;

設定configIDLE_SHOULD_YIELD為0將阻止空閒任務為使用者任務讓出CPU,直到空閒任務的時間片結束。這確保所有處在空閒優先順序的任務分配到相同多的處理器時間,但是,這是以分配給空閒任務更高比例的處理器時間為代價的。

17.configUSE_TASK_NOTIFICATIONS(V8.2.0新增)

設定宏configUSE_TASK_NOTIFICATIONS為1(或不定義宏configUSE_TASK_NOTIFICATIONS)將會開啟任務通知功能,有關的API函數也會被編譯。設定宏configUSE_TASK_NOTIFICATIONS為0則關閉任務通知功能,相關API函數也不會被編譯。預設這個功能是開啟的。開啟後,每個任務多增加8位元組RAM。

這是個很有用的特性,一大亮點。

每個RTOS任務具有一個32位元的通知值,RTOS任務通知相當於直接向任務傳送一個事件,接收到通知的任務可以解除任務的阻塞狀態(因等待任務通知而進入阻塞狀態)。相對於以前必須分別建立佇列、二進位制號誌、計數號誌或事件組的情況,使用任務通知顯然更靈活。更好的是,相比於使用號誌解除任務阻塞,使用任務通知可以快45%(使用GCC編譯器,-o2優化級別)。

18.configUSE_MUTEXES

設定為1表示使用互斥量,設定成0表示忽略互斥量。讀者應該瞭解在FreeRTOS中互斥量和二進位制號誌的區別。

關於互斥量和二進位制號誌簡單說:

  • 互斥型號誌必須是同一個任務申請,同一個任務釋放,其他任務釋放無效。
  • 二進位制號誌,一個任務申請成功後,可以由另一個任務釋放。
  • 互斥型號誌是二進位制號誌的子集

19--21

19.configUSE_RECURSIVE_MUTEXES

設定成1表示使用遞迴互斥量,設定成0表示不使用。

20.configUSE_COUNTING_SEMAPHORES

設定成1表示使用計數號誌,設定成0表示不使用。

21.configUSE_ALTERNATIVE_API

設定成1表示使用“替代”佇列函數('alternative' queue functions),設定成0不使用。替代API在queue.h標頭檔案中有詳細描述。

注:“替代”佇列函數已經被棄用,在新的設計中不要使用它!

22.configCHECK_FOR_STACK_OVERFLOW

每個任務維護自己的棧空間,任務建立時會自動分配任務需要的佔記憶體,分配記憶體大小由建立任務函數(xTaskCreate())的一個引數指定。堆疊溢位是裝置執行不穩定的最常見原因,因此FreeeRTOS提供了兩個可選機制用來輔助檢測和改正堆疊溢位。設定宏configCHECK_FOR_STACK_OVERFLOW為不同的常數來使用不同堆疊溢位檢測機制。

注意,這個選項僅適用於記憶體對映未分段的微處理器架構。並且,在RTOS檢測到堆疊溢位發生之前,一些處理器可能先產生故障(fault)或異常(exception)來反映堆疊使用的惡化。如果宏configCHECK_FOR_STACK_OVERFLOW沒有設定成0,使用者必須提供一個棧溢位勾點函數,這個勾點函數的函數名和引數必須如下所示:

void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName );

引數xTask和pcTaskName為堆疊溢位任務的控制程式碼和名字。請注意,如果溢位非常嚴重,這兩個引數資訊也可能是錯誤的!在這種情況下,可以直接檢查pxCurrentTCb變數。

推薦僅在開發或測試階段使用棧溢位檢查,因為堆疊溢位檢測會增大上下文切換開銷。

工作切換出去後,該任務的上下文環境被儲存到自己的堆疊空間,這時很可能堆疊的使用量達到了最大(最深)值。在這個時候,RTOS核心會檢測堆疊指標是否還指向有效的堆疊空間。如果堆疊指標指向了有效堆疊空間之外的地方,堆疊溢位勾點函數會被呼叫。

這個方法速度很快,但是不能檢測到所有堆疊溢位情況(比如,堆疊溢位沒有發生在上下文切換時)。設定configCHECK_FOR_STACK_OVERFLOW為1會使用這種方法。

當堆疊首次建立時,在它的堆疊區中填充一些已知值(標記)。當工作切換時,RTOS核心會檢測堆疊最後的16個位元組,確保標記資料沒有被覆蓋。如果這16個位元組有任何一個被改變,則呼叫堆疊溢位勾點函數。

這個方法比第一種方法要慢,但也相當快了。它能有效捕捉堆疊溢位事件(即使堆疊溢位沒有發生在上下文切換時),但是理論上它也不能百分百的捕捉到所有堆疊溢位(比如堆疊溢位的值和標記值相同,當然,這種情況發生的概率極小)。

使用這個方法需要設定configCHECK_FOR_STACK_OVERFLOW為2.

23.configQUEUE_REGISTRY_SIZE

佇列記錄有兩個目的,都涉及到RTOS核心的偵錯:

它允許在偵錯GUI中使用一個佇列的文字名稱來簡單識別佇列;包含偵錯程式需要的每一個記錄佇列和號誌定位資訊;

除了進行核心偵錯外,佇列記錄沒有其它任何目的。

configQUEUE_REGISTRY_SIZE定義可以記錄的佇列和號誌的最大數目。如果你想使用RTOS核心偵錯程式檢視佇列和號誌資訊,則必須先將這些佇列和號誌進行註冊,只有註冊後的佇列和號誌才可以使用RTOS核心偵錯程式檢視。檢視API參考手冊中的vQueueAddToRegistry() 和vQueueUnregisterQueue()函數獲取更多資訊。

24--36

24configUSE_QUEUE_SETS

設定成1使能佇列集功能(可以阻塞、掛起到多個佇列和號誌),設定成0取消佇列集功能。

25.configUSE_TIME_SLICING(V7.5.0新增)

預設情況下(宏configUSE_TIME_SLICING未定義或者宏configUSE_TIME_SLICING設定為1),FreeRTOS使用基於時間片的優先順序搶佔式排程器。這意味著RTOS排程器總是執行處於最高優先順序的就緒任務,在每個RTOS 系統節拍中斷時在相同優先順序的多個任務間進行工作切換。如果宏configUSE_TIME_SLICING設定為0,RTOS排程器仍然總是執行處於最高優先順序的就緒任務,但是當RTOS 系統節拍中斷髮生時,相同優先順序的多個任務之間不再進行工作切換。

26.configUSE_NEWLIB_REENTRANT(V7.5.0新增)

如果宏configUSE_NEWLIB_REENTRANT設定為1,每一個建立的任務會分配一個newlib(一個嵌入式C庫)reent結構。

27.configENABLE_BACKWARD_COMPATIBILITY

標頭檔案FreeRTOS.h包含一系列#define宏定義,用來對映版本V8.0.0和V8.0.0之前版本的資料型別名字。這些宏可以確保RTOS核心升級到V8.0.0或以上版本時,之前的應用程式碼不用做任何修改。在FreeRTOSConfig.h檔案中設定宏configENABLE_BACKWARD_COMPATIBILITY為0會去掉這些宏定義,並且需要使用者確認升級之前的應用沒有用到這些名字。

28.configNUM_THREAD_LOCAL_STORAGE_POINTERS

設定每個任務的執行緒本地儲存指標陣列大小。

執行緒本地儲存允許應用程式在任務的控制塊中儲存一些值,每個任務都有自己獨立的儲存空間,宏configNUM_THREAD_LOCAL_STORAGE_POINTERS指定每個任務執行緒本地儲存指標陣列的大小。API函數vTaskSetThreadLocalStoragePointer()用於向指標陣列中寫入值,API函數pvTaskGetThreadLocalStoragePointer()用於從指標陣列中讀取值。

比如,許多庫函數都包含一個叫做errno的全域性變數。某些庫函數使用errno返回庫函數錯誤資訊,應用程式檢查這個全域性變數來確定發生了那些錯誤。在單執行緒程式中,將errno定義成全域性變數是可以的,但是在多執行緒應用中,每個執行緒(任務)必須具有自己獨有的errno值,否則,一個任務可能會讀取到另一個任務的errno值。

FreeRTOS提供了一個靈活的機制,使得應用程式可以使用執行緒本地儲存指標來讀寫執行緒本地儲存。具體參見後續文章《FreeRTOS系列第12篇---FreeRTOS任務應用函數》。

29.configGENERATE_RUN_TIME_STATS

設定宏configGENERATE_RUN_TIME_STATS為1使能執行時間統計功能。一旦設定為1,則下面兩個宏必須被定義:

portCONFIGURE_TIMER_FOR_RUN_TIME_STATS():使用者程式需要提供一個基準時鐘函數,函數完成初始化基準時鐘功能,這個函數要被define到宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()上。這是因為執行時間統計需要一個比系統節拍中斷頻率還要高解析度的基準定時器,否則,統計可能不精確。基準定時器中斷頻率要比統節拍中斷快10~100倍。基準定時器中斷頻率越快,統計越精準,但能統計的執行時間也越短(比如,基準定時器10ms中斷一次,8位元無符號整形變數可以計到2.55秒,但如果是1秒中斷一次,8位元無符號整形變數可以統計到255秒)。

portGET_RUN_TIME_COUNTER_VALUE():使用者程式需要提供一個返回基準時鐘當前“時間”的函數,這個函數要被define到宏portGET_RUN_TIME_COUNTER_VALUE()上。

舉一個例子,假如我們設定了一個定時器,每500us中斷一次。在定時器中斷服務例程中簡單的使長整形變數ulHighFrequencyTimerTicks自增。那麼上面提到兩個宏定義如下(可以在FreeRTOSConfig.h中新增):

    extern volatile unsigned longulHighFrequencyTimerTicks;
    #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ( ulHighFrequencyTimerTicks = 0UL )
    #define portGET_RUN_TIME_COUNTER_VALUE() ulHighFrequencyTimerTicks

30.configUSE_CO_ROUTINES

設定成1表示使用協程,0表示不使用協程。如果使用協程,必須在工程中包含croutine.c檔案。

注:協程(Co-routines)主要用於資源發非常受限的嵌入式系統(RAM非常少),通常不會用於32位元微處理器。

在當前嵌入式硬體環境下,不建議使用協程,FreeRTOS的開發者早已經停止開發協程。

31.configMAX_CO_ROUTINE_PRIORITIES

應用程式協程(Co-routines)的有效優先順序數目,任何數目的協程都可以共用一個優先順序。使用協程可以單獨的分配給任務優先順序。見configMAX_PRIORITIES。

32.configUSE_TIMERS

設定成1使用軟體定時器,為0不使用軟體定時器功能。詳細描述見FreeRTOS software timers 。

33.configTIMER_TASK_PRIORITY

設定軟體定時器服務/守護行程的優先順序。詳細描述見FreeRTOS software timers 。

34.configTIMER_QUEUE_LENGTH

設定軟體定時器命令佇列的長度。詳細描述見FreeRTOS software timers。

35.configTIMER_TASK_STACK_DEPTH

設定軟體定時器服務/守護行程任務的堆疊深度,詳細描述見FreeRTOS software timers 。

36.configKERNEL_INTERRUPT_PRIORITY

configMAX_SYSCALL_INTERRUPT_PRIORITY和configMAX_API_CALL_INTERRUPT_PRIORITY

這是移植和應用FreeRTOS出錯最多的地方,所以需要打起精神仔細讀懂。

Cortex-M3、PIC24、dsPIC、PIC32、SuperH和RX600硬體裝置需要設定宏configKERNEL_INTERRUPT_PRIORITY;PIC32、RX600和Cortex-M硬體裝置需要設定宏configMAX_SYSCALL_INTERRUPT_PRIORITY。

configMAX_SYSCALL_INTERRUPT_PRIORITY和configMAX_API_CALL_INTERRUPT_PRIORITY,這兩個宏是等價的,後者是前者的新名字,用於更新的移植層程式碼。

注意下面的描述中,在中斷服務例程中僅可以呼叫以“FromISR”結尾的API函數。

僅需要設定configKERNEL_INTERRUPT_PRIORITY的硬體裝置(也就是宏configMAX_SYSCALL_INTERRUPT_PRIORITY不會用到):configKERNEL_INTERRUPT_PRIORITY用來設定RTOS核心自己的中斷優先順序。呼叫API函數的中斷必須執行在這個優先順序;不呼叫API函數的中斷,可以執行在更高的優先順序,所以這些中斷不會被因RTOS核心活動而延時。

configKERNEL_INTERRUPT_PRIORITY和configMAX_SYSCALL_INTERRUPT_PRIORITY都需要設定的硬體裝置:configKERNEL_INTERRUPT_PRIORITY用來設定RTOS核心自己的中斷優先順序。因為RTOS核心中斷不允許搶佔使用者使用的中斷,因此這個宏一般定義為硬體最低優先順序。configMAX_SYSCALL_INTERRUPT_PRIORITY用來設定可以在中斷服務程式中安全呼叫FreeRTOS API函數的最高中斷優先順序。優先順序小於等於這個宏所代表的優先順序時,程式可以在中斷服務程式中安全的呼叫FreeRTOS API函數;如果優先順序大於這個宏所代表的優先順序,表示FreeRTOS無法禁止這個中斷,在這個中斷服務程式中絕不可以呼叫任何API函數。

通過設定configMAX_SYSCALL_INTERRUPT_PRIORITY的優先順序級別高於configKERNEL_INTERRUPT_PRIORITY可以實現完整的中斷巢狀模式。這意味著FreeRTOS核心不能完全禁止中斷,即使在臨界區。此外,這對於分段核心架構的微處理器是有利的。請注意,當一個新中斷髮生後,某些微處理器架構會(在硬體上)禁止中斷,這意味著從硬體響應中斷到FreeRTOS重新使能中斷之間的這段短時間內,中斷是不可避免的被禁止的。

不呼叫API的中斷可以執行在比configMAX_SYSCALL_INTERRUPT_PRIORITY高的優先順序,這些級別的中斷不會被FreeRTOS禁止,因此不會因為執行RTOS核心而被延時。

例如:假如一個微控制器有8箇中斷優先順序別:0表示最低優先順序,7表示最高優先順序(Cortex-M3和Cortex-M4核心優先數和優先順序別正好與之相反,後續文章會專門介紹它們)。當兩個設定選項分別為4和0時,下圖描述了每一個優先順序別可以和不可做的事件:

configMAX_SYSCALL_INTERRUPT_PRIORITY=4

configKERNEL_INTERRUPT_PRIORITY=0

這些設定引數允許非常靈活的中斷處理:

在系統中可以像其它任務一樣為中斷處理任務分配優先順序。這些任務通過一個相應中斷喚醒。中斷服務例程(ISR)內容應儘可能的精簡---僅用於更新資料然後喚醒高優先順序任務。ISR退出後,直接執行被喚醒的任務,因此中斷處理(根據中斷獲取的資料來進行的相應處理)在時間上是連續的,就像ISR在完成這些工作。這樣做的好處是當中斷處理任務執行時,所有中斷都可以處在使能狀態。

中斷、中斷服務例程(ISR)和中斷處理任務是三碼事:當中斷來臨時會進入中斷服務例程,中斷服務例程做必要的資料收集(更新),之後喚醒高優先順序任務。這個高優先順序任務在中斷服務例程結束後立即執行,它可能是其它任務也可能是中斷處理任務,如果是中斷處理任務,那麼就可以根據中斷服務例程中收集的資料做相應處理。

configMAX_SYSCALL_INTERRUPT_PRIORITY介面有著更深一層的意義:在優先順序介於RTOS核心中斷優先順序(等於configKERNEL_INTERRUPT_PRIORITY)和configMAX_SYSCALL_INTERRUPT_PRIORITY之間的中斷允許全巢狀中斷模式並允許呼叫API函數。大於configMAX_SYSCALL_INTERRUPT_PRIORITY的中斷優先順序絕不會因為執行RTOS核心而延時。

執行在大於configMAX_SYSCALL_INTERRUPT_PRIORITY的優先順序中斷是不會被RTOS核心所遮蔽的,因此也不受RTOS核心功能影響。這主要用於非常高的實時需求中。比如執行電機轉向。但是,這類中斷的中斷服務例程中絕不可以呼叫FreeRTOS的API函數。

為了使用這個方案,應用程式要必須符合以下規則:呼叫FreeRTOS API函數的任何中斷,都必須和RTOS核心處於同一優先順序(由宏configKERNEL_INTERRUPT_PRIORITY設定),或者小於等於宏configMAX_SYSCALL_INTERRUPT_PRIORITY定義的優先順序。

37.configASSERT

斷言,偵錯時可以檢查傳入的引數是否合法。FreeRTOS核心程式碼的關鍵點都會呼叫configASSERT( x )函數,如果引數x為0,則會丟擲一個錯誤。這個錯誤很可能是傳遞給FreeRTOS API函數的無效引數引起的。定義configASSERT()有助於偵錯時發現錯誤,但是,定義configASSERT()也會增大應用程式程式碼量,增大執行時間。推薦在開發階段使用這個斷言宏。

舉一個例子,我們想把非法引數所在的檔名和程式碼行數列印出來,可以先定義一個函數vAssertCalled,該函數有兩個引數,分別接收觸發configASSERT宏的檔名和該宏所在行,然後通過顯示屏或者串列埠輸出。程式碼如下:

    #define configASSERT( ( x ) )     if( ( x ) == 0 )vAssertCalled( __FILE__, __LINE__ )

這裡__FILE__和__LINE__是大多數編譯器預定義的宏,分別表示程式碼所在的檔名(字串格式)和行數(整形)。

這個例子雖然看起來很簡單,但由於要把整形__LINE__轉換成字串再顯示,在效率和實現上,都不能讓人滿意。我們可以使用C標準庫assert的實現方法,這樣函數vAssertCalled只需要接收一個字串形式的引數(推薦仔細研讀下面的程式碼並理解其中的技巧):

     #define STR(x)  VAL(x)
     #define VAL(x)  #x
     #define configASSERT(x) ((x)?(void) 0 :xAssertCalld(__FILE__ ":" STR(__LINE__) " " #x"n"))

這裡稍微講解一下,由於內建宏__LINE__是整數型的而不是字串型,把它轉化成字串需要一個額外的處理層。宏STR和和宏VAL正是用來輔助完成這個轉化。宏STR用來把整形行號替換掉__LINE__,宏VAL用來把這個整形行號字串化。忽略宏STR和VAL中的任何一個,只能得到字串”__LINE__”,這不是我們想要的。

這裡使用三目運運算元’?:’來代替引數判斷if語句,這樣可以接受任何引數或表示式,程式碼也更緊湊,更重要的是程式碼優化度更高,因為如果引數恆為真,在編譯階段就可以去掉不必要的輸出語句。

38.INCLUDE Parameters

以“INCLUDE”起始的宏允許使用者不編譯那些應用程式不需要的實時核心元件(函數),這可以確保在你的嵌入式系統中RTOS佔用最少的ROM和RAM。

每個宏以這樣的形式出現:

INCLUDE_FunctionName

在這裡FunctionName表示一個你可以控制是否編譯的API函數。如果你想使用該函數,就將這個宏設定成1,如果不想使用,就將這個宏設定成0。比如,對於API函數vTaskDelete():

#define INCLUDE_vTaskDelete 1

表示希望使用vTaskDelete(),允許編譯器編譯該函數

#define INCLUDE_vTaskDelete 0

表示禁止編譯器編譯該函數。

以上就是FreeRTOS實時作業系統核心設定說明的詳細內容,更多關於FreeRTOS核心設定的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com