FreeRTOS

PSoC4でFreeRTOS

インターフェース2021年4月号で特集されているFreeRTOSをPSoC4で使ってみたので備忘録として投稿します。
デモとして赤・緑・青色LEDをそれぞれ1,3,5Hzにて点滅させるタスクを動作させます。

確認環境バージョン
FreeRTOSv202012.00
PSoC Creator4.4 (4.4.0.80)
ARM GCC5.4-2016-q2-update

作業手順

1.FreeRTOSのダウンロード

FreeRTOSより、[Download FreeRTOS]を選択します。

Download FreeRTOS画面で、FreeRTOSの[Download]を行います。

ダウンロードしたZIPファイルを適当な場所に解凍します。(解凍したファイルをコピーして使用するので、保存場所は任意)

2.プロジェクトの新規作成

PSoC Creatorで、PSOC4の新規プロジェクトを生成します。赤・緑・青色LEDの駆動端子も設定して、一旦、プロジェクトを終了します。

3.プロジェクトフォルダ内にFreeRTOSのソースファイルをコピーします。

プロジェクトフォルダ(main.cファイルがあるフォルダ)内に、FreeRTOSソースファイル収納用”FreeRTOS”フォルダを作成し、その下に、”include”フォルダと”source”フォルダを作成します。

“include”フォルダ内には、ダウンロードしたFreeRTOSより以下をコピーします。
“ダウンロードフォルダ\FreeRTOSv202012.00\FreeRTOS\Source\include”フォルダ内のすべてのヘッダファイル
“ダウンロードフォルダ\FreeRTOSv202012.00\FreeRTOS\Source\portable\GCC\ARM_CM0″フォルダ内のすべてのヘッダファイル

“source”フォルダ内には、ダウンロードしたFreeRTOSより以下をコピーします。
“ダウンロードフォルダ\FreeRTOSv202012.00\FreeRTOS\Source”フォルダ内のすべてのcファイル
“ダウンロードフォルダ\FreeRTOSv202012.00\FreeRTOS\Source\portable\Common”フォルダ内のすべてのcファイル
“ダウンロードフォルダ\FreeRTOSv202012.00\FreeRTOS\Source\portable\GCC\ARM_CM0″フォルダ内のすべてのcファイル
“ダウンロードフォルダ\FreeRTOSv202012.00\FreeRTOS\Source\portable\MemMang”フォルダ内のいずれか1つのcファイル(今回はheap_1.cを選択、どのファイルを選択するかは同フォルダ内のReadMeを参照)

4.プロジェクトフォルダ内にFreeRTOSConfig.hの作成

ダウンロードしたFreeRTOS内には、PSoC5(ARM Cortex-M3)のデモフォルダがあるので、PSoC4(ARM Cortex-M0)用に一部を編集して下記を使用しました。


//
// for PSoC4
//
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#include "project.h"

#define configUSE_PREEMPTION                    1       // プリエンプティブ RTOS スケジューラを使用する
#define configCPU_CLOCK_HZ                      CYDEV_BCLK__HFCLK__HZ   // 内部クロック周波数
#define configTICK_RATE_HZ                      1000    // RTOS ティック割り込み周波数
#define configMAX_PRIORITIES                    5       // アプリケーション タスクで使用できる優先度の数
#define configMINIMAL_STACK_SIZE                100     // スタックサイズ(ワード数)
#define configMAX_TASK_NAME_LEN                 12      // タスク名の最大文字列長
#define configUSE_16_BIT_TICKS                  0       // ティック割り込み実行回数を使用しない
#define configIDLE_SHOULD_YIELD                 0       // アイドル優先度を使用しない
#define configUSE_MUTEXES                       1       // ミューテックス機能を使用する
#define configUSE_RECURSIVE_MUTEXES             1       // 再帰ミューテックス機能を使用する
#define configUSE_COUNTING_SEMAPHORES           1       // カウンティングセマフォ機能を使用する

#define configUSE_ALTERNATIVE_API               0       // オルタナティブAPIを使用しない
#define configQUEUE_REGISTRY_SIZE               10      // キューレジストリの容量

// メモリ割り当て関連の定義
#define configTOTAL_HEAP_SIZE                   2048    // ヒープで使用可能容量

// フック機能関連の定義
#define configUSE_IDLE_HOOK                     0       // アイドルフックを省略
#define configUSE_TICK_HOOK                     0       // ティックフックを省略
#define configCHECK_FOR_STACK_OVERFLOW          2       // スタックオーバーフローフック関数を使用する
#define configUSE_MALLOC_FAILED_HOOK            1       // ヒープ領域獲得失敗フック関数を使用する

// 実行時タスク状態の情報
#define configGENERATE_RUN_TIME_STATS           0       // 実行状態の情報を使用しない
#define configUSE_TRACE_FACILITY                0       // トレースを支援機能を使用しない

// コルーチン関連の定義
#define configUSE_CO_ROUTINES                   0       // コルーチン機能を使用しない
#define configMAX_CO_ROUTINE_PRIORITIES         2       // コルーチンで使用できる優先順位数
    
// 割込み動作構成(Cortex-M0)
#define configPRIO_BITS                         __NVIC_PRIO_BITS    // 4 priority levels
#define MIN_PRIORITY                            ((1 << configPRIO_BITS) - 1)
#define configKERNEL_INTERRUPT_PRIORITY         ( MIN_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY    ( 2 << (8 - configPRIO_BITS) )

// オプション関数
#define INCLUDE_vTaskPrioritySet                1
#define INCLUDE_uxTaskPriorityGet               1
#define INCLUDE_vTaskDelete                     1
#define INCLUDE_vTaskCleanUpResources           0
#define INCLUDE_vTaskSuspend                    1
#define INCLUDE_vTaskDelayUntil                 1
#define INCLUDE_vTaskDelay                      1
#define INCLUDE_uxTaskGetStackHighWaterMark     1
#define INCLUDE_eTaskGetState                   1

#endif /* FREERTOS_CONFIG_H */

各設定の詳細は、FreeRTOSConfig.hを参照下さい

5.ビルド設定でインクルード・パスを設定します。

Psoc Creatorで、先ほど生成したプロジェクトを立ち上げ、[Project] > [Build Settings]より、ARM GCCコンパイラに、先ほどヘッダファイルをコピーしたフォルダをインクルード・ディレクトリに追加します。

6.デモ用のメイン・プログラムを編集します。


//
// FreeRTOS demo for PSoC4
//
#include 
#include "project.h"
#include 
#include 

#define CORTEX_INTERRUPT_BASE           (16)

#define BLUE_LED_BLINK_FREQ_HZ          (5)
#define GREEN_LED_BLINK_FREQ_HZ         (3)
#define RED_LED_BLINK_FREQ_HZ           (1)

// 青色LEDタスク
void vBlinkTaskBlue(void *pvParameters) {
    while (1) {
        Pin_Blue_LED_Write(~Pin_Blue_LED_Read());
        vTaskDelay(configTICK_RATE_HZ / (BLUE_LED_BLINK_FREQ_HZ * 2));
    }
}

// 緑色LEDタスク
void vBlinkTaskGreen(void *pvParameters) {
    while (1) {
        Pin_Green_LED_Write(~Pin_Green_LED_Read());
        vTaskDelay(configTICK_RATE_HZ / (GREEN_LED_BLINK_FREQ_HZ * 2));
    }
}

// 赤色LEDタスク
void vBlinkTaskRed(void *pvParameters) {
    while (1) {
        Pin_Red_LED_Write(~Pin_Red_LED_Read());
        vTaskDelay(configTICK_RATE_HZ / (RED_LED_BLINK_FREQ_HZ * 2));
    }
}

// FreeRTOSセットアップ
void setupFreeRTOS(void)
{
    // ベクターテーブルにコピーする必要のあるポートレイヤー関数
    extern void vPortSVCHandler(void);          // address 11 - Supervisor Call (SVC, formerly SWI)
    extern void xPortPendSVHandler(void);       // address 14 - PendSV Call
    extern void xPortSysTickHandler(void);      // address 15 - SYSTICK
    
    CyIntSetSysVector(CORTEX_INTERRUPT_BASE + SVCall_IRQn, (cyisraddress)vPortSVCHandler);
    CyIntSetSysVector(CORTEX_INTERRUPT_BASE + PendSV_IRQn, (cyisraddress)xPortPendSVHandler);
    CyIntSetSysVector(CORTEX_INTERRUPT_BASE + SysTick_IRQn, (cyisraddress)xPortSysTickHandler);
}

// メイン
int main(void)
{
    setupFreeRTOS();
    xTaskCreate(vBlinkTaskBlue, "BlinkBlue", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
    xTaskCreate(vBlinkTaskGreen, "BlinkGreen", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, NULL);
    xTaskCreate(vBlinkTaskRed, "BlinkRed", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 3, NULL);
    CyGlobalIntEnable;
    vTaskStartScheduler();
    while (1);
    return 1;
}

// スタックオーバーフローフック関数
void vApplicationStackOverflowHook(xTaskHandle pxTask, char *pcTaskName)
{
    taskDISABLE_INTERRUPTS();
    while (1);
}

// ヒープ領域獲得失敗フック関数
void vApplicationMallocFailedHook(void)
{
    taskDISABLE_INTERRUPTS();
    while (1);
}

/* [] END OF FILE */
ベクターテーブルにポートレイヤ関数を登録する方法は、FreeRTOS内のPSoC5デモでは、ベクターテーブルに直接書き込んでいますが、専用の関数が用意されていますので、今回はこの関数を使用しました。

7.ビルドして実行してみます。

おおよそ1,3,5Hzで点滅していることが確認できました。