PSoC5LPでFreeRTOSv10.2.1を使ってLチカ

#環境
- PSoC Creator 4.2
- FreeRTOS 10.2.1
- [PSoC5LP Prototyping Kit](https://japan.cypress.com/documentation/development-kitsboards/cy8ckit-059-psoc-5lp-prototyping-kit-onboard-programmer-and)

# プロジェクトを作る
PSoC Creatorを立ち上げ、**File->New->Project**よりプロジェクトを作る。
デバイスは今回用いる**CY8C5888LTI-LP097**を選択。

テンプレートは空っぽの**empty**を選択。

わかりやすい名前とディレクトリを指定してFinishする。

# FreeRTOSを導入する
## ダウンロード
[FreeRTOS](https://sourceforge.net/projects/freertos/files/)よりダウンロードできる。
2019/6/10時点で最新verは10.2.1。
zipとexeがあるが今回はzipを選択。

##導入
zipを解凍すると、いくつかのフォルダが生成される。このうち、**Demo**フォルダは各マイコン用のデモフォルダ、**License**はライセンスが入っている。今回使用する**Source**だけをプロジェクトのディレクトリへコピーする。

##PSoC Creatorへリンク
まずわかりやすいように、デザイン内にFreeRTOS用のフォルダを生成する。
コピーしたファイルをこのフォルダ内にリンクしていく。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264634/313e3c0a-b2c5-9ba1-f85b-e813d7e3e2de.png)
必要なものを列挙すると、

- FreeRTOS/Source/下の.Cソースファイル
- FreeRTOS/include下のヘッダーファイル
- FreeRTOS/portable/MemMangのheap.cファイルどれかひとつ
- FreeRTOS/portable/GCC/ARM_CM3のソースファイル・ヘッダーファイル

をそれぞれ**Header Files**と**Source Files**にドラッグアンドドロップでリンクする。

## FreeRTOSコンフィグファイルの作成
FreeRTOSの設定用ヘッダファイルを作成する。
解凍してできた**FreeRTOS/Demo/CORTEX_CY8C5588_PSoC_Creator_GCC/FreeRTOS_Demo.cydsn**ディレクトリの、**FreeRTOSConfig.h**と**device.h**をコピーして持ってくるのが早い。
FreeRTOSConfig.hはFreeRTOSの設定ファイル、device.hはproject.hのラッパーになっている。筆者の場合めんどくさかったのでdevice.hはコピーしてこないでFreeRTOSConfig.h内の記述をいじって直接project.hをインクルードする形にした。

コピーしてきたら忘れずにPSoC Creatorにリンクしておく。

## PSoC Creatorにインクルードパスを指定する
PSoC Creatorメニューバーの**Project->Build Setting**より**ARM_GCC~->Compiler->General**の**Additional Include Directories**にFreeRTOSのヘッダファイルが存在するディレクトリを指定してやる。
**portable/GCC/ARM_CM3**が忘れやすいので注意すること。
以上でFreeRTOSの最低限の導入はおしまい。

# Lチカする
##Top Design/Pinアサイン
今回はただのLチカなのでDigital Outputピンを一つ置くだけ。
ピンアサインは開発ボードのユーザーLEDとつながっている2.1ピンを指定する。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264634/5ffa3b7e-fc2a-e0c6-f23c-258d9cd5a73b.png)

##プログラム
プログラムは以下のようになる。

```C:main.c
#include "project.h"
#include "FreeRTOS.h"
#include "task.h"

void vTestTask1();//タスクとして走らせる関数
void vTestTask2();
int main(void)
{
    CyGlobalIntEnable; /* Enable global interrupts. */

    /* Place your initialization/startup code here (e.g. MyInst_Start()) */

    //FreeRTOS用の割り込み周りの初期設定。この処理をしないと動かない。
    extern void xPortPendSVHandler( void );
    extern void xPortSysTickHandler( void );
    extern void vPortSVCHandler( void );
    extern cyisraddress CyRamVectors[];

	CyRamVectors[ 11 ] = ( cyisraddress ) vPortSVCHandler;
	CyRamVectors[ 14 ] = ( cyisraddress ) xPortPendSVHandler;
	CyRamVectors[ 15 ] = ( cyisraddress ) xPortSysTickHandler;
    
    //タスクを生成
    xTaskCreate(vTestTask1,"test1",100,NULL,3,NULL);
    xTaskCreate(vTestTask2,"test2",100,NULL,3,NULL);
    //スケジューラを起動
    vTaskStartScheduler();
    
    for(;;)
    {
        /* Place your application code here. */
    }
}

//LEDを点灯させるタスク
void vTestTask1(){
    for(;;){
        vTaskDelay(1000);
        LED_1_Write(1);        
    }    
}
//LEDを消灯させるタスク
void vTestTask2(){
    vTaskDelay(500);
    for(;;){
        vTaskDelay(1000);
        LED_1_Write(0);        
    }    
}
//オーバーフローが起こった際のハンドラ
void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
{
	/* The stack space has been execeeded for a task, considering allocating more. */
	taskDISABLE_INTERRUPTS();
}/*---------------------------------------------------------------------------*/

//メモリの確保に失敗したときのハンドラ
void vApplicationMallocFailedHook( void )
{
	/* The heap space has been execeeded. */
	taskDISABLE_INTERRUPTS();
}

```

FreeRTOSは、タスクとして走らせる関数を、`xTaskCreate();`関数で指定してタスクを生成し、`vTaskStartScheduler();`関数でスケジューラを起動することによって、生成されたタスクを走らせることができる。

`xTaskCreate();`関数の引数は1項目から、走らせる関数、タスク名、スタックサイズ、タスクに渡す引数、優先度、タスクのIDになっている。
今回はtestTask1でLEDを点灯させ、testTask2で消灯させるようなプログラムにした。testTask2の方は500msのディレイを入れているので、1HzのLチカになっているはずだが、同期をとっていないのでズレる可能性もある。

無事コンパイルが通り書き込みに成功すれば、0.5秒ごとにLEDがチカチカするはず。
このLチカはFreeRTOSの(たぶん)最小構成なので、他の機能を試したい場合はデモが参考になる。