FreeRTOSのタスクの状態監視用のAPIと使い方



下記の記事から続くFreeRTOSの機能に関する記事です。

https://qiita.com/tom_S/items/ea653880132e1fcfed72

タスクの状態を知るためのAPIについてここで説明します。

# API

```c
UBaseType_t uxTaskGetSystemState(
                       TaskStatus_t * const pxTaskStatusArray,
                       const UBaseType_t uxArraySize,
                       unsigned long * const pulTotalRunTime );
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ------------------------------ |
|機能| | 現在生成されているタスク(アイドルタスクとタイマー管理タスクも含む)の情報を取得する |
| 引数 | pxTaskStatusArray | 取得したタスク情報を格納する配列のポインタ。実体はユーザ側で定義 |
|  | uxArraySize | 情報を取得するタスクの最大値 |
|  | pulTotalRunTime  | システム開始からの経過時間が格納される。FreeRTOSConfig.hのconfigGENERATE_RUN_TIME_STATSを1にし、時刻設定用のマクロを定義しないと使用できない。configGENERATE_RUN_TIME_STATSが0の場合は必ず0が格納される |
|返り値| | 情報を取得したタスクの数 |

アイドルタスク情報は必ず取得されます。(実質2つ以上のタスクの情報が取得される)
FreeRTOSConfig.hのconfigUSE_TIMERSを1に定義している場合は、タイマー管理用のタスク情報も必ず取得されます。

```c
void vTaskGetInfo( TaskHandle_t xTask,
                   TaskStatus_t *pxTaskStatus,
                   BaseType_t xGetFreeStackSpace,
                   eTaskState eState );
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ------------------------------ |
|機能|   | タスクの情報を取得する |
| 引数 | xTask | 取得したいタスクのID |
|  | pxTaskStatus | タスク情報を格納する配列のポインタ |
|  | xGetFreeStackSpace | スタックを消費したかの情報を取得する場合はpdTRUEを入れる。 |
|  | eState  | eInvalidを指定することで、現在のタスクの状態をpxTaskStatusに格納する。  |


uxTaskGetSystemState()とvTaskGetInfo()で取得できるタスク情報「TaskStatus_t」の定義は「タスク情報管理構造体(TaskStatus_t)」の項目にて説明します。


```C
void vTaskList( char *pcWriteBuffer );
void vTaskListTasks( char *pcWriteBuffer, size_t uxBufferLength );
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ------------------------------ |
|機能| | タスクをリスト表示にした文字列を返す。FreeRTOSConfig.hに定義されているconfigUSE_TRACE_FACILITYとconfigUSE_STATS_FORMATTING_FUNCTIONSを 1 に定義することで使用可能。実行中には割り込みが禁止されるため注意  |
| 引数 | pcWriteBuffer | タスクをリスト表示にした文字列 |
|  | uxBufferLength | バッファサイズ |




```C
void vTaskGetRunTimeStats( char *pcWriteBuffer );
void vTaskGetRunTimeStatistics( char *pcWriteBuffer, size_t uxBufferLength );
```


| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ------------------------------ |
|機能| | タスクごとの処理時間とCPU使用率を文字列で返す。FreeRTOSConfig.hに定義されているconfigGENERATE_RUN_TIME_STATSとconfigSUPPORT_DYNAMIC_ALLOCATIONとconfigUSE_STATS_FORMATTING_FUNCTIONSを 1 に定義することで使用可能。  |
| 引数 | pcWriteBuffer | タスクごとの処理時間とCPU使用率を示す文字列 |
|  | uxBufferLength | バッファサイズ |


また、この関数を使用するには、「portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()  」と「portGET_RUN_TIME_COUNTER_VALUE() 」を定義する必要があります。詳しくは後述する「CPU使用率の算出に必要なマクロ」の項目をご覧ください。


```c
configRUN_TIME_COUNTER_TYPE xTaskGetIdleRunTimeCounter( void );
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ------------------------------ |
|機能| | アイドルタスクの総処理時間を取得する |
| 返り値 |  | アイドルタスクの総処理時間 |


```c
configRUN_TIME_COUNTER_TYPE ulTaskGetRunTimeCounter( const TaskHandle_t xTask );
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ------------------------------ |
|機能| | タスクの総処理時間を取得する |
| 引数 | xTask | 総処理時間を取得したいタスクのID |
| 返り値 |  | タスクの総処理時間 |


```c
configRUN_TIME_COUNTER_TYPE ulTaskGetRunTimePercent( const TaskHandle_t xTask );
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ------------------------------ |
|機能| | タスクのCPU使用率を取得する |
| 引数 | xTask | タスクのCPU使用率を取得したいタスクのID |
| 返り値 |  | タスクのCPU使用率 |

```c
configRUN_TIME_COUNTER_TYPE ulTaskGetIdleRunTimePercent( void );
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ------------------------------ |
|機能| | アイドルタスクのCPU使用率を取得する |
| 返り値 |  | アイドルタスクのCPU使用率 |


# タスク情報管理構造体(TaskStatus_t)

```c
typedef struct xTASK_STATUS
{
	TaskHandle_t xHandle;
	const char *pcTaskName;		
	UBaseType_t xTaskNumber;	
	eTaskState eCurrentState;	
	UBaseType_t uxCurrentPriority;	
	UBaseType_t uxBasePriority;		
	uint32_t ulRunTimeCounter;		
	StackType_t *pxStackBase;		
	configSTACK_DEPTH_TYPE usStackHighWaterMark;	
} TaskStatus_t;
```

| 項目1 |  説明 |
| ------------- |  ------------------------------ |
| xHandle | タスクID |
| pcTaskName | タスク名 |
| xTaskNumber | タスク番号。タスク生成順に割り振られる |
| eCurrentState | タスクの状態。eReady(実行可能状態)、eRunning(実行中)、eBlocked(ブロック中)、eSuspended(停止中)、eDeleted(削除状態)  |
| uxCurrentPriority | 現在の優先度(ミューテックスの優先度逆転対応時にはuxBasePriorityと違う値になる) |
| uxBasePriority | 元々の優先度 |
| ulRunTimeCounter | タスクが実行されてから経過した時間。追加設定が必要なので後述する |
| pxStackBase | スタックのベースアドレス |
| usStackHighWaterMark | タスクにおける残りのスタックの最小値 |


「usStackHighWaterMark」に、タスクにおける残りのスタックの最小値、つまりタスクが最大でどれだけスタックを消費したかの情報が入ります。
0に近ければ近いほどスタックオーバーフローを起こした可能性が高くなります。
FreeRTOSConfig.hのconfigRECORD_STACK_HIGH_ADDRESS を1にした場合は、スタックのTopアドレスとBottomアドレスも取得可能です。


「ulRunTimeCounter」においては、FreeRTOSConfig.hのconfigGENERATE_RUN_TIME_STATSを1に定義した場合使用可能です。

# CPU使用率の算出に必要なマクロ

TaskStatus_tのulRunTimeCounterの値を取得したり、CPUの使用率を計算するためには、FreeRTOSConfig.hのconfigGENERATE_RUN_TIME_STATSを1に定義することと、下記の二つのマクロも定義する必要があります。

```c
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()  
```

タイマーの初期化、タイマーの開始を定義しておくためのマクロです。ハードウェアに用意されているペリフェラルのカウントアップタイマーを使うのが良いかと思います。FreeRTOSのスケジューラ―が開始するタイミングで呼ばれます。


```c
#define portGET_RUN_TIME_COUNTER_VALUE() 
```

「portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()」で設定・開始したタイマーのカウンタを取得します。このカウンタの値を基に、ulRunTimeCounter を算出します。