FreeRTOSをVScode環境で動かす②CMSIS_RTOSラッパーを被せる

[FreeRTOSをVScode環境で動かす①環境構築](https://qiita.com/takeru0x5569/items/e5102258dbf1c61fa80d) の続きです。

# 概要

以前紹介した記事でFreeRTOSを用いてWindowsPC上で２つのタスクを実行する環境を作成しました。
もともとやりたかった事として、__ARMマイコン用ファームの予備検証環境をWindowsで構築する__　という前提があります。

### 具体的に何のARMマイコンなの？
__STマイクロ製__ の __ARM cortexF7__ シリーズをターゲットとしています。

ここで、

__STマイクロのマイコンでRTOSを動かしたい場合は　APIを CMSIS_RTOS に合わせておく__ という制約があります。

今回はCMSIS_RTOSのラッパーを被せていく作業を紹介します。
（CMSIS_RTOSが何者なのかは他のが詳しく紹介記事を書かれているので割愛します）

# 使用する機能
CMSISの全ての機能を使用するとエラー等が出てきたりして、初心者には苦しい状況になるかと思います。。。
今回は最低限の機能だけ使用して、動作する状況を作っていきたいと思います。

## 有効にする構造体など

* enum
    * osPriority 
    * osStatus
* typedef
    * os_pthread
    * TaskHandle_t
* struct
    * osThreadDef_t


# 使用するカーネルコントロール関数

CMSIS_RTOS関数名|機能
---|---
osKernelInitialize  |スケジューラーの初期化
osKernelStart       |スケジューラーの起動
osKernelRunning     |スケジューラーが動作中か否かの判定

# 使用するスレッドマネージメント関数

CMSIS_RTOS関数名|機能
---|---
osThreadCreate　   |スレッドをスケジューラーに登録
osThreadGetId      |実行中のスレッドIDの取得
osThreadTerminate  |スレッドの停止

# 使用するウェイト関連関数
CMSIS_RTOS関数名|機能
---|---
osDelay     |指定時間だけ待つ
osDelayUntil|基準時刻から指定した時間だけ待つ


# コンフィグヘッダの設定

プライオリティの設定を７にします

```c:FreeRTOSConfig.h
#define configMAX_PRIORITIES					(7)
```

理由は cmsis_os.h の中でプライオリティの設定が↓の通り、７段階定義されているため、これに合わせる必要があります。

```c:cmsis_os.h
typedef enum  {
  osPriorityIdle          = -3,          ///< priority: idle (lowest)
  osPriorityLow           = -2,          ///< priority: low
  osPriorityBelowNormal   = -1,          ///< priority: below normal
  osPriorityNormal        =  0,          ///< priority: normal (default)
  osPriorityAboveNormal   = +1,          ///< priority: above normal
  osPriorityHigh          = +2,          ///< priority: high
  osPriorityRealtime      = +3,          ///< priority: realtime (highest)
  osPriorityError         =  0x84        ///< system cannot determine priority or thread has illegal priority
} osPriority;
```


# ユーザー関数
参考までに私の作った関数を紹介します。

* タスクは２つ
* task1は１秒周期でprint
* task1は２秒周期でprint
* ５週したらtask停止

```c:main.c
#include "UserTaskDef.h"
#include <stdio.h>
//===================================================================
//
//===================================================================
int main(){
	if( 0 == TaskInit() ){
		printf("task initialize OK\n");
	}else{
		printf("task initialize ON!!!!!!\n");
	};
	 /* Start scheduler */
	UserTaskStart();

	while (1)
	{
	}
}
```

```c:UserTaskDef.h
#ifndef _DUMMY_TASK_H_
#define _DUMMY_TASK_H_

int TaskInit(void);
void UserTaskStart();

#endif  // include gurde
```

```c:UserTaskDef.c
#include "cmsis_os.h"
#include "UserTaskDef.h"
#include <stdio.h>

//--------------------------------------------------------
// static functions
//--------------------------------------------------------
static void dummyTask1Func(void const *arg);
static void dummyTask2Func(void const *arg);
static osThreadId 			taskHandle1;
static osThreadId 			taskHandle2;

//--------------------------------------------------------
// task Definition
//--------------------------------------------------------
//          Task Name     Entry Function    Priority         instance   Stack Size
osThreadDef(dummyTask1   ,dummyTask1Func   ,osPriorityHigh  , 0       , 0x800);
osThreadDef(dummyTask2   ,dummyTask2Func   ,osPriorityHigh  , 0       , 0x800);

//--------------------------------------------------------
// task Registration
//--------------------------------------------------------
int TaskInit(void){
    if( 1 == osKernelRunning() ){
        return 1;//error
    }

    taskHandle1 = osThreadCreate(osThread(dummyTask1), NULL);
    taskHandle2 = osThreadCreate(osThread(dummyTask2), NULL);
    return 0;//
}
//--------------------------------------------------------
// task Start
//--------------------------------------------------------
void UserTaskStart(){
    if( 0 == osKernelRunning() ){
        osKernelStart();
	}
}
//--------------------------------------------------------
// task1
//--------------------------------------------------------
static void dummyTask1Func(void const *arg){
  uint32_t PreviousWakeTime;
	for(int i=0; i<5; i++){
		printf("dummy_task1\n");
    	osDelayUntil(&PreviousWakeTime , 1000);//1秒周期
	}
  osThreadTerminate(taskHandle1);//タスク停止
}
//--------------------------------------------------------
// task2
//--------------------------------------------------------
static void dummyTask2Func(void const *arg){
  uint32_t PreviousWakeTime;
	for(int i=0; i<5; i++){
		printf("           dummy_task2\n");
    	osDelayUntil(&PreviousWakeTime , 2000);//2秒周期
	}
  osThreadTerminate(taskHandle2);
}
//--------------------------------------------------------
//
//--------------------------------------------------------
void vApplicationMallocFailedHook( void ){
	/* vApplicationMallocFailedHook() will only be called if
	configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook
	function that will get called if a call to pvPortMalloc() fails.
	pvPortMalloc() is called internally by the kernel whenever a task, queue,
	timer or semaphore is created.  It is also called by various parts of the
	demo application.  If heap_1.c, heap_2.c or heap_4.c is being used, then the
	size of the	heap available to pvPortMalloc() is defined by
	configTOTAL_HEAP_SIZE in FreeRTOSConfig.h, and the xPortGetFreeHeapSize()
	API function can be used to query the size of free heap space that remains
	(although it does not provide information on how the remaining heap might be
	fragmented).  See http://www.freertos.org/a00111.html for more
	information. */
	vAssertCalled( __LINE__, __FILE__ );
}

```

# 動作結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204268/68a57492-0e39-d570-9ebf-df9c4ef0cbdd.png)

* ２つのタスクが平行して走っていることが確認できました。
* task1の終了と同時にプログラム全体が停止しました。
* task1の終了後もtask2が５回呼ばれてからプログラム全体が終了を期待していたのですが。。。

# 今後の課題
ここまでで　windowsPC上でFreeRTOSにCMSIS_OSラッパーを被せて動作確認ができました。
次はARMマイコンとのクロスコンパイル環境の構築を目指てみます。