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


FreeRTOSをVScode環境で動かす①環境構築 の続きです。

概要

以前紹介した記事でFreeRTOSを用いてWindowsPC上で2つのタスクを実行する環境を作成しました。
もともとやりたかった事として、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 基準時刻から指定した時間だけ待つ

コンフィグヘッダの設定

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

FreeRTOSConfig.h
#define configMAX_PRIORITIES                    (7)

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

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;

ユーザー関数

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

  • タスクは2つ
  • task1は1秒周期でprint
  • task1は2秒周期でprint
  • 5週したらtask停止
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)
    {
    }
}
UserTaskDef.h
#ifndef _DUMMY_TASK_H_
#define _DUMMY_TASK_H_

int TaskInit(void);
void UserTaskStart();

#endif  // include gurde
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__ );
}

動作結果

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

今後の課題

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