今天開始有決心來學習freertos 的源碼,因爲我感覺非開始不行了。
我從freertos 官網下載了源代碼(10.1.1)。下載源代碼很簡單,只需要在搜索網站上輸入“freertos” 在下面就出現主頁面。點擊進去下載就好了。這個就不多說了,這是我的第一篇學習freertos 的文章,所以提了一下上面的話。謝謝大家提出寶貴意見。
今天的主角:xTaskCreate()
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
)
當我看到這個函數的時候,我第一個想法就是: 它的參數是什麼意思?有什麼作用?
所以我下面的就逐一去找這些參數的定義。
(1)TaskFunction_t : typedef void (*TaskFunction_t)( void * ); 很顯然是函數指針
(2)const char * const pcName : 任務名字
(3)configSTACK_DEPTH_TYPE : #define configSTACK_DEPTH_TYPE uint16_t 是無符號的2字節數值
(4)void * const pvParameters :從名字看是要傳入的參數
(5)UBaseType_t uxPriority : typedef unsigned short UBaseType_t; 是一個無符號的整形數
(6)TaskHandle_t * const pxCreatedTask :這裏面有一個結構體指針。下面列出來
typedef struct tskTaskControlBlock
{
volatile StackType_t *pxTopOfStack;
#if ( portUSING_MPU_WRAPPERS == 1 )
xMPU_SETTINGS xMPUSettings;
#endif
ListItem_t xStateListItem;
ListItem_t xEventListItem;
UBaseType_t uxPriority;
StackType_t *pxStack; /*< Points to the start of the stack. */
char pcTaskName[ configMAX_TASK_NAME_LEN ];
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
StackType_t *pxEndOfStack;
#endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
UBaseType_t uxCriticalNesting;
#endif
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTCBNumber;
UBaseType_t uxTaskNumber;
#endif
#if ( configUSE_MUTEXES == 1 )
UBaseType_t uxBasePriority;
UBaseType_t uxMutexesHeld;
#endif
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
TaskHookFunction_t pxTaskTag;
#endif
#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
void *pvThreadLocalStoragePointers[configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
#endif
#if( configGENERATE_RUN_TIME_STATS == 1 )
uint32_t ulRunTimeCounter;
#endif
#if ( configUSE_NEWLIB_REENTRANT == 1 )
struct _reent xNewLib_reent;
#endif
#if( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue;
volatile uint8_t ucNotifyState;
#endif
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
uint8_t ucStaticallyAllocated;
#endif
#if( INCLUDE_xTaskAbortDelay == 1 )
uint8_t ucDelayAborted;
#endif
#if( configUSE_POSIX_ERRNO == 1 )
int iTaskErrno;
#endif
} tskTCB;
上面的代碼,我刪除了很多的註釋。不刪除註釋的話,顯示的會很亂。看到這個結構體這麼大,我感覺肯定很重要。認真去看他的每一個成員。
(1)volatile StackType_t *pxTopOfStack; :pxTopOfStack 從名字看,是指向棧的最頂端。
這個裏面還用了一個很重要的關鍵字:volatile
(2)xMPU_SETTINGS xMPUSettings; xMPU_SETTINGS 是一個結構體,
typedef struct MPU_SETTINGS
{
xMPU_REGION_REGISTERS xRegion[ portTOTAL_NUM_REGIONS ];
} xMPU_SETTINGS;
typedef struct MPU_REGION_REGISTERS
{
uint32_t ulRegionBaseAddress;
uint32_t ulRegionAttribute;
} xMPU_REGION_REGISTERS;
從代碼看到xRegion 是一個帶有區域基地址和區域屬性的數組結構體。那麼我又想到了一個問題,這個區域是做什麼的啊? 這個問題就暫且保留吧,後面肯定會揭發它。
(3)ListItem_t xStateListItem; 這個裏面我想着重研究明白,ListItem_t 這個結構體。
struct xLIST;
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
configLIST_VOLATILE TickType_t xItemValue;
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
void * pvOwner;
struct xLIST * configLIST_VOLATILE pxContainer;
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
};
typedef struct xLIST_ITEM ListItem_t;
<1>就是一層跟着一層的出現未知的內容。listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE 這個宏又是幹什麼的呢?
宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE用於檢查列表項數據是否完整。
<2>configLIST_VOLATILE TickType_t xItemValue; typedef uint16_t TickType_t; 這僅是一個值,但是我還不知道用來做什麼?
xItemValue是列表項值,通常是一個被跟蹤的任務優先級或是一個調度事件的計數器值。
<3>struct xLIST_ITEM * configLIST_VOLATILE pxNext; 和 struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; 這個就很容易理解了,雙向鏈表的pre 和 next。
<4>void * pvOwner; 指向一個任務TCB。
<5>struct xLIST * configLIST_VOLATILE pxContainer;
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
configLIST_VOLATILE TickType_t xItemValue;
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
/*
* Definition of the type of queue used by the scheduler.
*/
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE
volatile UBaseType_t uxNumberOfItems;
ListItem_t * configLIST_VOLATILE pxIndex;
MiniListItem_t xListEnd;
listSECOND_LIST_INTEGRITY_CHECK_VALUE
} List_t;
從xLIST 結構體中看到xListEnd 中有MiniListItem 子集,而這個子集不難發現是把雙向鏈表的元素選擇出來了。也就是說鏈表索引時只需要讀取這個元素就可以了。
(4)剩下的內容會在遇到的時候,再添加。
到這裏參數就分析完了。但這只是剛開始,因爲讀完這麼多參數功能,我們還需要靜下心來想一想這個函數的參數到底佈下了一張什麼樣的網?? 有函數指針,有任務名字字符串指針,有整型數,有操作句柄--> 在句柄中有列表項,有雙向鏈表,在結構體中有宏檢查數據完整,。。。。。 我們靜下心來思考吧,每個人都有自己的體會。