freeRTOSConfig.h文件對FreeRTOS進行系統配置


  FreeRTOS內核是高度可定制的,使用配置文件FreeRTOSConfig.h進行定制。每個FreeRTOS應用都必須包含這個頭文件,用戶根據實際應用來裁剪定制FreeRTOS內核。這個配置文件是針對用戶程序的,而非內核,因此配置文件一般放在應用程序目錄下,不要放在RTOS內核源碼目錄下。

在下載的FreeRTOS文件包中,每個演示例程都有一個FreeRTOSConfig.h文件。有些例程的配置文件是比較舊的版本,可能不會包含所有有效選項。如果沒有在配置文件中指定某個選項,那么RTOS內核會使用默認值。典型的FreeRTOSConfig.h配置文件定義如下所示

/*
    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
    All rights reserved

    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

    This file is part of the FreeRTOS distribution.

    FreeRTOS is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License (version 2) as published by the
    Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.

    ***************************************************************************
    >>!   NOTE: The modification to the GPL is included to allow you to     !<<
    >>!   distribute a combined work that includes FreeRTOS without being   !<<
    >>!   obliged to provide the source code for proprietary components     !<<
    >>!   outside of the FreeRTOS kernel.                                   !<<
    ***************************************************************************

    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.  Full license text is available on the following
    link: http://www.freertos.org/a00114.html

    ***************************************************************************
     *                                                                       *
     *    FreeRTOS provides completely free yet professionally developed,    *
     *    robust, strictly quality controlled, supported, and cross          *
     *    platform software that is more than just the market leader, it     *
     *    is the industry's de facto standard.                               *
     *                                                                       *
     *    Help yourself get started quickly while simultaneously helping     *
     *    to support the FreeRTOS project by purchasing a FreeRTOS           *
     *    tutorial book, reference manual, or both:                          *
     *    http://www.FreeRTOS.org/Documentation                              *
     *                                                                       *
    ***************************************************************************

    http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading
    the FAQ page "My application does not run, what could be wrong?".  Have you
    defined configASSERT()?

    http://www.FreeRTOS.org/support - In return for receiving this top quality
    embedded software for free we request you assist our global community by
    participating in the support forum.

    http://www.FreeRTOS.org/training - Investing in training allows your team to
    be as productive as possible as early as possible.  Now you can receive
    FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
    Ltd, and the world's leading authority on the world's leading RTOS.

    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
    including FreeRTOS+Trace - an indispensable productivity tool, a DOS
    compatible FAT file system, and our tiny thread aware UDP/IP stack.

    http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
    Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.

    http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
    Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS
    licenses offer ticketed support, indemnification and commercial middleware.

    http://www.SafeRTOS.com - High Integrity Systems also provide a safety
    engineered and independently SIL3 certified version for use in safety and
    mission critical applications that require provable dependability.

    1 tab == 4 spaces!
*/


#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#include "sys.h"
#include "usart.h"
//針對不同的編譯器調用不同的stdint.h文件
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
    #include <stdint.h>
    extern uint32_t SystemCoreClock;
#endif

//斷言
#define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
#define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)

/***************************************************************************************************************/
/*                                        FreeRTOS基礎配置配置選項                                              */
/***************************************************************************************************************/
#define configUSE_PREEMPTION                    1                       //1使用搶占式內核,0使用協程
#define configUSE_TIME_SLICING                    1                        //1使能時間片調度(默認式使能的)
#define configUSE_PORT_OPTIMISED_TASK_SELECTION    1                       //1啟用特殊方法來選擇下一個要運行的任務
                                                                        //一般是硬件計算前導零指令,如果所使用的
                                                                        //MCU沒有這些硬件指令的話此宏應該設置為0!
#define configUSE_TICKLESS_IDLE                    0                       //1啟用低功耗tickless模式
#define configUSE_QUEUE_SETS                    1                       //為1時啟用隊列
#define configCPU_CLOCK_HZ                        (SystemCoreClock)       //CPU頻率
#define configTICK_RATE_HZ                        (1000)                  //時鍾節拍頻率,這里設置為1000,周期就是1ms
#define configMAX_PRIORITIES                    (32)                    //可使用的最大優先級
#define configMINIMAL_STACK_SIZE                ((unsigned short)130)   //空閑任務使用的堆棧大小
#define configMAX_TASK_NAME_LEN                    (16)                    //任務名字字符串長度

#define configUSE_16_BIT_TICKS                    0                       //系統節拍計數器變量數據類型,
                                                                        //1表示為16位無符號整形,0表示為32位無符號整形
#define configIDLE_SHOULD_YIELD                    1                       //為1時空閑任務放棄CPU使用權給其他同優先級的用戶任務
#define configUSE_TASK_NOTIFICATIONS            1                       //為1時開啟任務通知功能,默認開啟
#define configUSE_MUTEXES                        1                       //為1時使用互斥信號量
#define configQUEUE_REGISTRY_SIZE                8                       //不為0時表示啟用隊列記錄,具體的值是可以
                                                                        //記錄的隊列和信號量最大數目。
#define configCHECK_FOR_STACK_OVERFLOW            0                       //大於0時啟用堆棧溢出檢測功能,如果使用此功能
                                                                        //用戶必須提供一個棧溢出鈎子函數,如果使用的話
                                                                        //此值可以為1或者2,因為有兩種棧溢出檢測方法。
#define configUSE_RECURSIVE_MUTEXES                1                       //為1時使用遞歸互斥信號量
#define configUSE_MALLOC_FAILED_HOOK            0                       //1使用內存申請失敗鈎子函數
#define configUSE_APPLICATION_TASK_TAG            0                       
#define configUSE_COUNTING_SEMAPHORES            1                       //為1時使用計數信號量

/***************************************************************************************************************/
/*                                FreeRTOS與內存申請有關配置選項                                                */
/***************************************************************************************************************/
#define configSUPPORT_DYNAMIC_ALLOCATION        1                       //支持動態內存申請
#define configTOTAL_HEAP_SIZE                    ((size_t)(20*1024))     //系統所有總的堆大小

/***************************************************************************************************************/
/*                                FreeRTOS與鈎子函數有關的配置選項                                              */
/***************************************************************************************************************/
#define configUSE_IDLE_HOOK                        0                       //1,使用空閑鈎子;0,不使用
#define configUSE_TICK_HOOK                        0                       //1,使用時間片鈎子;0,不使用

/***************************************************************************************************************/
/*                                FreeRTOS與運行時間和任務狀態收集有關的配置選項                                 */
/***************************************************************************************************************/
#define configGENERATE_RUN_TIME_STATS            0                       //為1時啟用運行時間統計功能
#define configUSE_TRACE_FACILITY                1                       //為1啟用可視化跟蹤調試
#define configUSE_STATS_FORMATTING_FUNCTIONS    1                       //與宏configUSE_TRACE_FACILITY同時為1時會編譯下面3個函數
                                                                        //prvWriteNameToBuffer(),vTaskList(),
                                                                        //vTaskGetRunTimeStats()
                                                                        
/***************************************************************************************************************/
/*                                FreeRTOS與協程有關的配置選項                                                  */
/***************************************************************************************************************/
#define configUSE_CO_ROUTINES                     0                       //為1時啟用協程,啟用協程以后必須添加文件croutine.c
#define configMAX_CO_ROUTINE_PRIORITIES         ( 2 )                   //協程的有效優先級數目

/***************************************************************************************************************/
/*                                FreeRTOS與軟件定時器有關的配置選項                                            */
/***************************************************************************************************************/
#define configUSE_TIMERS                        1                               //為1時啟用軟件定時器
#define configTIMER_TASK_PRIORITY                (configMAX_PRIORITIES-1)        //軟件定時器優先級
#define configTIMER_QUEUE_LENGTH                5                               //軟件定時器隊列長度
#define configTIMER_TASK_STACK_DEPTH            (configMINIMAL_STACK_SIZE*2)    //軟件定時器任務堆棧大小

/***************************************************************************************************************/
/*                                FreeRTOS可選函數配置選項                                                      */
/***************************************************************************************************************/
#define INCLUDE_xTaskGetSchedulerState          1                       
#define INCLUDE_vTaskPrioritySet                1
#define INCLUDE_uxTaskPriorityGet                1
#define INCLUDE_vTaskDelete                        1
#define INCLUDE_vTaskCleanUpResources            1
#define INCLUDE_vTaskSuspend                    1
#define INCLUDE_vTaskDelayUntil                    1
#define INCLUDE_vTaskDelay                        1
#define INCLUDE_eTaskGetState                    1
#define INCLUDE_xTimerPendFunctionCall            1

/***************************************************************************************************************/
/*                                FreeRTOS與中斷有關的配置選項                                                  */
/***************************************************************************************************************/
#ifdef __NVIC_PRIO_BITS
    #define configPRIO_BITS               __NVIC_PRIO_BITS
#else
    #define configPRIO_BITS               4                  
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY            15                      //中斷最低優先級
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5                       //系統可管理的最高中斷優先級
#define configKERNEL_INTERRUPT_PRIORITY         ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY     ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

/***************************************************************************************************************/
/*                                FreeRTOS與中斷服務函數有關的配置選項                                          */
/***************************************************************************************************************/
#define xPortPendSVHandler     PendSV_Handler
#define vPortSVCHandler     SVC_Handler

#endif /* 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()失敗鈎子函數的函數名和原型必須如下所示:

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.x\FreeRTOS\Demo\Common\Minimal文件夾下的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

       調用任務函數時,需要設置描述任務信息的字符串,這個宏用來定義該字符串的最大長度。這里定義的長度包括字符串結束符’\0’。

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.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.configUSE_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  

 

  表示希望禁止vTaskDelete(),禁止編譯器編譯該函數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM