LoginSignup
2
1

More than 3 years have passed since last update.

FreeRTOSにiTRONタスク管理APIっぽいの入れてみた

Last updated at Posted at 2020-09-04

FreeRTOSにiTRONタスク管理APIっぽいの入れてみた。

開発環境:STM32CubeMX (Ver5.6.1)
コンパイラは、EWARMMDK-ARM などお好きな環境で

FreeRTOSの初期状態からの設定変更

タスク状態やスタック領域管理のため、CubeMXにて下記FreeRTOS設定を変更した。

CubeMX画面上の、
 タブ   「Pinout&Configuration」
 画面左帯 「Categories」→「Middleware」→「FREERTOS」
を選択。(Modeは「CMSIS_V1」を選択。※V2未評価のため)

image.png

「Configuration」→「Config parameters」を選択。
  RECORD_STACK_HIGH_ADDRESS ⇒ Enabled     ※スタックサイズを求めるため。
  Memory Allocation       ⇒ Dynamic/Static  ※静的関数(...Static)を有効に。
  GENERATE_RUN_TIME_STATS   ⇒ Enabled     ※タスク状態確認。
  USE_TRACE_FACILITY      ⇒ Enabled     ※タスクトレース有効化。
  USE_STATS_FORMATTING_FUNCTIONS ⇒ Enabled  ※タスクトレース有効化。

「Configuration」→「Include parameters」を選択。
  uxTaskGetStackHighWaterMark ⇒ Enabled  ※タスクの残りスタック量を取得するため。

ソースコード

【注意事項】
 ・タスク管理のため、メモリ操作やソートをしまくっている無理くりソースコードです。
 ・下記ソースコード中の「表示関数の別名定義」箇所(文字出力、メモリ操作関数)は実装済みの関数名に置き換えます。
 ※本記事中のソフトウェアはサンプルコードであり、ソフトウェアを使用した結果いかなる損害等が発生しても当方は一切責任を負いません。

itron.c
/****************************************************************************
 *  iTRON風サポートライブラリ
 ****************************************************************************/

#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <ctype.h>

#include    "itron.h"
#include    "clib.h"
#include    "klib.h"

/*** 表示関数の別名定義 ***/
#define     _PS     sc_puts
#define     _PF     sc_printf
#define     _PR     sc_print
#define     _NL     sc_crlf
#ifdef INC_FREERTOS_H
 #define    _MAL    pvPortMalloc        // RAM割当関数
 #define    _FRE    vPortFree           // RAM開放関数
#else
 #define    _MAL    malloc
 #define    _FRE    free
#endif

TaskStatus_t    *pxTaskStaArr   = NULL;
int             vTaskNum        = 0;

/****************************************************************************
 *  テーブルソート関数
 *  input:
 *      const void *x, *y   比較データ (C標準ライブラリ参照)
 *  output:
 *      int     0 or 1 or -1
 *---------------------------------------------------------------------------
 *  (解説)
 *      タスク番号順に並び替える。
 */
static int sort_info(const void *x, const void *y)
{
    int r1, r2;
    // タスク番号順に並び替える
    r1 = ((const TaskStatus_t*)x)->xTaskNumber;
    r2 = ((const TaskStatus_t*)y)->xTaskNumber;
    //_PF(" r1=%d r2=%d\n", r1, r2);
#if 1
    // 小さい順(昇順)に並び替える。
    return (r1 == r2)? 0: (r1 > r2)? 1: -1;
#else
    // 大きい順(降順)に並び替える。
    return (r1 == r2)? 0: (r1 < r2)? 1: -1;
#endif
}

/************************************************/
/* Get Task Handle                              */
/************************************************/
TaskHandle_t GetTaskHandle(ID tid, int ref)
{
    int num = uxTaskGetNumberOfTasks(); // タスク数チェック
    if (num <= 0) {
        // タスク数エラー
        if (pxTaskStaArr) {
            // 以前の情報領域を破棄
            _FRE(pxTaskStaArr);
            pxTaskStaArr = NULL;
        }
        _PF("Task Number error. %d\n", num);
        vTaskNum = 0;
        return NULL;
    }
    if (vTaskNum != num) {
        // 前回チェックしたタスク数と違う
        vTaskNum = num;
        if (pxTaskStaArr) {
            _FRE(pxTaskStaArr); // 以前の情報領域を破棄
            pxTaskStaArr = NULL;
        }
    }
    if (pxTaskStaArr == NULL) {
        // 新しい情報領域を取得
        pxTaskStaArr = (TaskStatus_t*)_MAL(vTaskNum * sizeof(TaskStatus_t));
        if (pxTaskStaArr == NULL) {
            _PS(" memory alloc error.");
            vTaskNum = 0;
            return NULL;
        }
        //_PF("Arry:%08X tasks:%d (unit-size=%d total=%d) \n\n", pxTaskStaArr, vTaskNum, sizeof(TaskStatus_t), vTaskNum * sizeof(TaskStatus_t));
        ref = 1;
    }

    if (ref) {
        // タスク情報取得
        num = uxTaskGetSystemState( pxTaskStaArr, vTaskNum, NULL );
        if ( vTaskNum != num ) _PF("Illegal task num. %d %d\n", vTaskNum, num);

        // 管理領域をタスク番号順に並び替える。
        qsort(pxTaskStaArr, vTaskNum, sizeof(TaskStatus_t), sort_info); 
    }

    if (tid) {
        for (int x = 0; x < vTaskNum; x++) {
            if (tid == pxTaskStaArr[x].xTaskNumber) {
                // タスクハンドルを返す。
                return pxTaskStaArr[x].xHandle;
            }
        }
    }
    return NULL; // 該当なし
}

/* タスク生成 */
ER_ID acre_tsk(const T_CTSK *pk_ctsk)
{
    TaskHandle_t pxTask;
    TaskStatus_t xTaskStatus;

    if (pk_ctsk->stk) {
        // 静的スタック領域
        /*
            ※注意
                静的コール(スタックアドレス指定あり)の場合、
                スタック後半ブロックをFreeRTOSのタスク管理領域
                (TCB:現バージョンでは約96バイト)として使うよう
                処理するので、スタック領域サイズはその分余裕をもって
                確保すること。
        */
        uint32_t ulStackDepth;          // スタックの深さ

        // スタックサイズ = (指定サイズ - TCBサイズ) / スタック型サイズ
        ulStackDepth = ((pk_ctsk->stksz)-TCB_SIZE)/STK_UNIT;
        if (ulStackDepth < (uint32_t)configMINIMAL_STACK_SIZE) {
            // 最小スタックサイズを満たしていない。
            return E_NOMEM;
        }
#if 0
        _PF(S_BLUE " STK=%08X\n" S_DEF, pk_ctsk->stk);
        _PF(S_BLUE " SIZ=%d[w]\n" S_DEF, ulStackDepth);
        _PF(S_BLUE " TCB=%08X\n" S_DEF, &((StackType_t *)pk_ctsk->stk)[ulStackDepth]);
        dly_tsk(100/MSEC);
#endif
        // タスク生成
        pxTask = xTaskCreateStatic(
                    (TaskFunction_t)pk_ctsk->task,      /* 実行アドレス */
                    pk_ctsk->name,                      /* タスク名 */
                    ulStackDepth,                       /* スタックサイズ (ワード単位) */
                    (void *)pk_ctsk->exinf,             /* パラメータ */
                    (UBaseType_t)pk_ctsk->itskpri,      /* 優先順位 */
                    (StackType_t *)pk_ctsk->stk,        /* スタック開始ポインタ */
                    (StaticTask_t *)&((StackType_t *)pk_ctsk->stk)[ulStackDepth]);
                                                        /* タスク管理領域ポインタ(=スタック後半)*/
    }
    else {
        // 動的スタック領域
        BaseType_t xRsl;
        unsigned short usStackDepth;

        usStackDepth = (unsigned short)((pk_ctsk->stksz)/STK_UNIT);
        if (usStackDepth < configMINIMAL_STACK_SIZE) {
            // 最小スタックサイズを満たしていない。
            return E_NOMEM;
        }
        // タスク生成
        xRsl = xTaskCreate(
                    (TaskFunction_t)pk_ctsk->task,      /* 実行アドレス */
                    pk_ctsk->name,                      /* タスク名 */
                    usStackDepth,                       /* スタックサイズ (ワード単位) */
                    (void *)pk_ctsk->exinf,             /* パラメータ */
                    (UBaseType_t)pk_ctsk->itskpri,      /* 優先順位 */
                    &pxTask);                           /* 作成したタスクのハンドルを引き渡すために使用されます。*/
        if (xRsl != pdPASS) {
            // タスク生成エラー
            return E_SYS;
        }

    }

    if (pxTask == NULL) {
        // 生成エラー
        return E_SYS;
    }

    /* タスク状態設定 */
    if ((pk_ctsk->tskatr & TA_ACT) == 0) {
        // サスペンド状態にする。
        vTaskSuspend(pxTask);
    }

    // タスク番号を返す。
    vTaskGetTaskInfo(pxTask, &xTaskStatus, pdFALSE, eInvalid);
    return (ER_ID)xTaskStatus.xTaskNumber;
}

/* タスク削除 */
ER del_tsk( ID tid )
{
    TaskHandle_t pxTask;
    if (tid <= 0) {
        return E_ID;        // 不正ID
    }
    else if (tid == TSK_SELF) {
        return E_OBJ;       // 自タスク指定禁止
    }
    else {
        pxTask = GetTaskHandle(tid, 0);
        if (pxTask == NULL) {
            return E_ID;
        }
    }
    // 削除
    vTaskDelete(pxTask);
    return E_OK;
}

/* タスク起動 */
ER act_tsk( ID tid )
{
    // レジュームと同じ扱いとする。
    return rsm_tsk(tid);
}

/* タスク起動キャンセル */
ER can_act( ID tid )
{
    // サスペンドと同等扱いとする。
    return sus_tsk(tid);
}

/* タスク起動 */
ER sta_tsk( ID tid, int val )
{
    // レジュームと同じ扱いとする。
    return rsm_tsk(tid);
}

/* タスク強制終了 */
ER ter_tsk( ID tid )
{
    // サスペンドと同等扱いとする。
    return sus_tsk(tid);
}

/* タスク優先度変更 */
ER chg_pri( ID tid, int val )
{
    TaskHandle_t pxTask;
    if (tid <= 0) {
        return E_ID;        // 不正ID
    }
    else if (tid == TSK_SELF) {
        pxTask = NULL;      // 自タスク
    }
    else {
        pxTask = GetTaskHandle(tid, 0);
        if (pxTask == NULL) {
            return E_ID;
        }
    }
    // 変更
    vTaskPrioritySet(pxTask, (UBaseType_t)val);
    // 確認
    if (val != (int)uxTaskPriorityGet(pxTask)) {
        return E_PAR; // 設定エラー
    }
    return E_OK;
}

/* タスク強制待ち状態へ */
ER sus_tsk( ID tid )
{
    TaskHandle_t pxTask;
    if (tid <= 0) {
        return E_ID;        // 不正ID
    }
    else if (tid == TSK_SELF) {
        pxTask = NULL;      // 自タスク
    }
    else {
        pxTask = GetTaskHandle(tid, 0);
        if (pxTask == NULL) {
            return E_ID;
        }
    }
    // サスペンド
    vTaskSuspend(pxTask);
    return E_OK;
}

/* タスク再開 */
ER rsm_tsk( ID tid )
{
    TaskHandle_t pxTask;
    if (tid <= 0) {
        return E_ID;        // 不正ID
    }
    else if (tid == TSK_SELF) {
        return E_OBJ;       // 自タスク指定禁止
    }
    else {
        pxTask = GetTaskHandle(tid, 0);
        if (pxTask == NULL) {
            return E_ID;
        }
    }
    // レジューム
    vTaskResume(pxTask);
    return E_OK;
}

#if 0
/* タスク再開(1回版) */
ER frsm_tsk( ID tid )
{
    TaskHandle_t pxTask = GetTaskHandle(tid, 0);
    if (pxTask == NULL) {
        return E_ID;
    }
    ;
    ;
    return E_OK;
}
#endif

/* タスク起床 */
ER wup_tsk( ID tid )
{
    TaskHandle_t pxTask = GetTaskHandle(tid, 0);
    if (pxTask == NULL) {
        return E_ID;
    }
    ;
    ;
    return E_OK;
}

/* タスク起床キャンセル */
ER can_wup( ID tid )
{
    TaskHandle_t pxTask = GetTaskHandle(tid, 0);
    if (pxTask == NULL) {
        return E_ID;
    }
    ;
    ;
    return E_OK;
}

/* タスク待ち解除 */
ER rel_wai( ID tid )
{
    TaskHandle_t pxTask = GetTaskHandle(tid, 0);
    if (pxTask == NULL) {
        return E_ID;
    }
    ;
    ;
    return E_OK;
}

/************************************************/
/* Refer Task Status                            */
/************************************************/
ER ref_tsk(ID tid, T_RTSK *pk_rtsk)
{
    StaticTask_t *pxTCB;
    TaskStatus_t xTaskStatus;
    TaskHandle_t pxTask = GetTaskHandle(tid, 1);
    if (pxTask == NULL) {
        return E_ID;
    }

    // タスク個別状態取得
    vTaskGetTaskInfo(pxTask, &xTaskStatus, pdTRUE, eInvalid);

    pk_rtsk->tskstat = (int)xTaskStatus.eCurrentState;      /* task state */
    pk_rtsk->tskpri  = (int)xTaskStatus.uxCurrentPriority;  /* current priority */
    pk_rtsk->tskbpri = (int)xTaskStatus.uxBasePriority;     /* base task priority */

    // タスク制御ブロックポインタセット
    pxTCB = (StaticTask_t *)xTaskStatus.xHandle;    // ハンドルは tasks.c  tskTCB構造体ポインタと同じ。
    pk_rtsk->stksz   = (SIZE)((char*)pxTCB->pxDummy8 - (char*)pxTCB->pxDummy6); // pxEndOfStack - pxStack と同義
    pk_rtsk->stksz   = (pk_rtsk->stksz + ((SIZE)portBYTE_ALIGNMENT_MASK+1)) & ~((SIZE)portBYTE_ALIGNMENT_MASK); // マスク
#if 0
        _PF(S_BLUE " pxDummy6=%08X\n" S_DEF, pxTCB->pxDummy6);
        _PF(S_BLUE " pxDummy8=%08X\n" S_DEF, pxTCB->pxDummy8);
        _PF(S_BLUE " SIZ=%d(%d)\n" S_DEF, (int)((char*)pxTCB->pxDummy8 - (char*)pxTCB->pxDummy6), pk_rtsk->stksz);
        dly_tsk(100/MSEC);
#endif

    return E_OK;
}

/*** End of file ***/



●ヘッダファイル

itron.h
/*
 *  itron.h
 */

/*
 *  ITRON仕様共通規定のデータ型・定数・マクロ
 */

#ifndef _ITRON_H
#define _ITRON_H

#include "cmsis_os.h"               /* FreeRTOSインクルードファイル */

#ifdef __cplusplus
extern "C" {
#endif

#define     _uITRON_
/*
 *  ITRON仕様共通データ型
 */

#ifdef INT8_MAX
typedef int8_t          B;          /* 符号付き8ビット整数 */
#endif /* INT8_MAX */

#ifdef UINT8_MAX
typedef uint8_t         UB;         /* 符号無し8ビット整数 */
typedef uint8_t         VB;         /* 型が定まらない8ビットの値 */
#endif /* UINT8_MAX */

typedef int16_t         H;          /* 符号付き16ビット整数 */
typedef uint16_t        UH;         /* 符号無し16ビット整数 */
typedef uint16_t        VH;         /* 型が定まらない16ビットの値 */

typedef int32_t         W;          /* 符号付き32ビット整数 */
typedef uint32_t        UW;         /* 符号無し32ビット整数 */
typedef uint32_t        VW;         /* 型が定まらない32ビットの値 */

#ifdef INT64_MAX
typedef int64_t         D;          /* 符号付き64ビット整数 */
#endif /* INT64_MAX */

#ifdef UINT64_MAX
typedef uint64_t        UD;         /* 符号無し64ビット整数 */
typedef uint64_t        VD;         /* 型が定まらない64ビットの値 */
#endif /* UINT64_MAX */

typedef void            *VP;        /* 型が定まらないものへのポインタ */

typedef int             INT;        /* 自然なサイズの符号付き整数 */
typedef unsigned int    UINT;       /* 自然なサイズの符号無し整数 */

typedef int             TMO;        /* タイムアウト指定 */
typedef uint32_t        SYSTIM;     /* システム時刻 */

typedef INT             BOOL;
typedef INT             FN;
typedef INT             ID;
typedef INT             BOOL_ID;
typedef INT             RDVNO;
typedef UINT            RDVPTN;
typedef UINT            ATR;
typedef UINT            MODE;
typedef INT             ER;
typedef INT             PRI;
typedef ER              ER_ID;
typedef UINT            STAT;
typedef INT             ER_UINT;
typedef UINT            TEXPTN;
typedef UINT            FLGPTN;
typedef UINT            INHNO;
typedef UINT            INTNO;

typedef VP              VP_INT;

typedef void            (*FP)();

typedef unsigned long   SIZE;
typedef unsigned long   ADDR;

typedef void            TASK;       /* */

/* tmout */
#define TMO_POL         ((TickType_t)0)     /* polling */
#define TMO_FEVR        ((TickType_t)-1)    /* wait forever */

/* tskid */
#define TSK_SELF        0           /* 自タスク指定 */

/*
 *  一般定数
 */
#ifndef NULL
 #define NULL           0           /* 無効ポインタ */
#endif /* NULL */

#ifndef true
 #define true           pdTRUE      /* 真 */
#endif /* true */
#ifndef false
 #define false          pdFALSE     /* 偽 */
#endif /* false */

#define E_OK        0           /* 正常終了 */

/*
 *  メインエラーコード
 */
#define E_SYS       (-5)        /* システムエラー */
#define E_NOSPT     (-9)        /* 未サポート機能 */
#define E_RSFN      (-10)       /* 予約機能コード */
#define E_RSATR     (-11)       /* 予約属性 */
#define E_PAR       (-17)       /* パラメータエラー */
#define E_ID        (-18)       /* 不正ID番号 */
#define E_CTX       (-25)       /* コンテキストエラー */
#define E_MACV      (-26)       /* メモリアクセス違反 */
#define E_OACV      (-27)       /* オブジェクトアクセス違反 */
#define E_ILUSE     (-28)       /* サービスコール不正使用 */
#define E_NOMEM     (-33)       /* メモリ不足 */
#define E_NOID      (-34)       /* ID番号不足 */
#define E_NORES     (-35)       /* 資源不足 */
#define E_OBJ       (-41)       /* オブジェクト状態エラー */
#define E_NOEXS     (-42)       /* オブジェクト未生成 */
#define E_QOVR      (-43)       /* キューイングオーバーフロー */
#define E_RLWAI     (-49)       /* 待ち状態の強制解除 */
#define E_TMOUT     (-50)       /* ポーリング失敗またはタイムアウト */
#define E_DLT       (-51)       /* 待ちオブジェクトの削除 */
#define E_CLS       (-52)       /* 待ちオブジェクトの状態変化 */
#define E_WBLK      (-57)       /* ノンブロッキング受付け */
#define E_BOVR      (-58)       /* バッファオーバーフロー */

/*
 *  ITRON仕様共通定数
 */
#ifndef TRUE
 #define    TRUE        true            /* 真 */
#endif
#ifndef FALSE
 #define    FALSE       false           /* 偽 */
#endif

/* tskpri */

#define TPRI_INI    -1
#define TPRI_RUN    -1
#define TPRI_SELF   -1
#define TMIN_TPRI   0
#define TMAX_TPRI   (configMAX_PRIORITIES-1)

ER dly_tsk(TMO tmout);

/*
 *  ITRON API変換 (FreeRTOS関数へ置き換え)
 */
#define     rot_rdq(P)          taskYIELD()                     // タスク回転

#if 0
 #define    dis_int()           taskDISABLE_INTERRUPTS()        // グローバル割込み禁止
 #define    ena_int()           taskENABLE_INTERRUPTS()         // グローバル割込み許可
#else //    ↓こちらの方がネスト考慮されるらしい。
 #define    dis_int()           taskENTER_CRITICAL()            // クリティカルセクションに入る (非コンテキスト処理用)
 #define    ena_int()           taskEXIT_CRITICAL()             // クリティカルセクションから出る (非コンテキスト処理用)
#endif

typedef struct _t_ctsk {
    ATR     tskatr;
    VP_INT  exinf;
    FP      task;
    PRI     itskpri;
    SIZE    stksz;
    VP      stk;
    const char *name;
} T_CTSK;

typedef struct _t_rtsk {
    int     tskstat;
    int     tskpri; 
    int     tskbpri;
    // ;
    // ;
    // ;
    SIZE    stksz;
} T_RTSK;

extern int  vTaskNum;

TaskHandle_t GetTaskHandle(ID tid, int ref); /* タスクハンドル取得 (FreeRTOSとの整合性を取るための関数) */

#define TA_HLNG             0x0000
#define TA_ACT              0x0002

#define STK_UNIT            sizeof(StackType_t)
#define TCB_SIZE            sizeof(StaticTask_t)

// タスク状態をFreeRTOSステータスと紐づけ
#define TTS_RUN             eRunning    /* RUNNING */
#define TTS_RDY             eReady      /* READY */
#define TTS_WAI             eBlocked    /* WAITING */
#define TTS_SUS             eSuspended  /* SUSPENDED */
#define TTS_WAS             eDeleted    /* WAITING-SUSPENDED */
#define TTS_DMT             eInvalid    /* DORMANT */

ER_ID acre_tsk(const T_CTSK *pk_ctsk);  /* タスク生成 */
ER del_tsk( ID tid );                   /* タスク削除 */
ER act_tsk( ID tid );                   /* タスク起動 */
ER can_act( ID tid );                   /* タスク起動キャンセル */
ER sta_tsk( ID tid, int val );          /* タスク起動 */
ER ter_tsk( ID tid );                   /* タスク強制終了 */
ER chg_pri( ID tid, int val );          /* タスク優先度変更 */
ER sus_tsk( ID tid );                   /* タスク強制待ち状態へ */
ER rsm_tsk( ID tid );                   /* タスク再開 */
//ER frsm_tsk( ID tid );                /* タスク再開(1回版) */
ER wup_tsk( ID tid );                   /* タスク起床 */
ER can_wup( ID tid );                   /* タスク起床キャンセル */
ER rel_wai( ID tid );                   /* タスク待ち解除 */

ER ref_tsk(ID tid, T_RTSK *pk_rtsk);    /* Refer Task Status */

#ifdef __cplusplus
}
#endif

#endif /* _ITRON_H */



以上

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1