TOPPERS BASE PLATFORMを使ったRTOS隠蔽化実験

・はじめに
　TOPPERS BASE PLATFORMの最初のリリースは2018年で４年目となりました。当初、TOPPERS教育WGの組込みプラットフォーム教育用の教材として作成した組込みソフトウェアプラットフォームです。開発時、ASP3系のカーネルが開発中で、きちんとした組込みシステム作成には、とても使用できるレベルではなかったため、安定したASPカーネルを使用して作成しました。そろそろ、「いつまで、古いRTOSを使っているのか」と言われそうな雰囲気なので、来年のバージョンV1.4.3から、RTOSを隠蔽化して、新しいRTOS上でもプラットフォームが動作するかの実験を行ってみました。
　組込みプラットフォームをRTOSに非依存にすることは、一般の組込み開発でも求められる要素です。例えば、組込みプラットフォーム上にプリンタシステムが載っていると想定すると、ハードウェアは日々進化しますし、また、コスト面で、より安価がハードウェアが必要となることもあります。その時、ちょうどよいハードウェアがFreeRTOS上のデバイスドライバを供給しているとすると、当然、プリンタシステムを持つ組込みプラットフォームがASPカーネルで作成されていたとしても、新しいハードウェア用にFreeRTOSで動作した方が、開発面で有利とわけです。

・アプローチ方法
　現状のTOPPERS BASE PLATFORMの各ドライバ、ミドルウェアで使用しているRTOSに依存したサービスコール(JSP/ASPカーネルに準拠)は、以下の通で単純にサービスコールをマクロ化することで、対応しようと考えました。
・dly_tsk　　DELAY_TASK　〇
・slp_tsk　　SLEEP_TASK
・tslp_tsk　 TIME_SLEEP_TASK
・wup_tsk　  WAKEUP_TASK
・wai_sem　　WAIT_SEMAPHORE　〇
・twai_sem　 TWAI_SEMAPHORE  〇
・sig_sem　　SIGNAL_SEMAPHORE 〇
・isig_sem　 INTERRUPT_SEGNAL_SEMAPHORE　〇
・loc_cpu　　LOCK_CPU　〇
・unl_cpu　　UNLOCK_CPU　〇
・ena_int　　ENABLE_INTERRUPT　〇
・dis_int　　DISABLE_INTERRUPT 〇
・sta_cyc　　START_CYCLIC_HANDLER
・stp_cyc　　STOP_CYCCLIC_HANDLER
・rcv_dtq　　RECEIVE_DATA_QUEUE
・trcv_dtq　 TIME_RECEIVE_DATA_QUEUE
・psnd_dtq　 POLLING_SEND_DATA_QUEUE
・ipsnd_dtq　INTERRUPT_POLLING_SEND_DATA_QUEUE

　基本的に、デバイスドライバーは〇の付いたサービスコールがあれば作成できます。割り込み等のサービスコールは、サービスコールの範疇かも疑問です。〇の付いていないものはミドルウェアで使用しているものです。

　TOPPERS BASE PLATFORMの以下のディレクトリのソースのサービスコールの直接記述をやめ、上記の右のマクロに書き換えて隠蔽化を行います。
以下は、stm32f4xx用のSPIドライバーの待ち時間関数ですが、twai_semをTIME_WAIT_SEMAPHOREにdly_tskをDELAY_TASKに書き換えました。これらの変更をすべてのTOPPERS BASE PLATFORMに対して行いました。

```
/*
 *  SPI内部転送終了待ち
 */
ER
spi_inwait(SPI_Handle_t *hspi, uint32_t timeout)
{
	ER ercd = E_OK;
	int tick = timeout;

	while((hspi->status & SPI_STATUS_BUSY) != 0 && tick > 0){
		if(hspi->Init.semid != 0)
    		TIME_WAIT_SEAMPHORE(hspi->Init.semid, 1);
		else
			DELAY_TASK(1);
		tick--;
	}
	dma_end(hspi->hdmarx);
	dma_end(hspi->hdmatx);
	if(hspi->ErrorCode != 0)
		ercd = E_OBJ;
	else if(tick == 0)
		ercd = E_TMOUT;
	hspi->TxXferCount = 0;
	hspi->RxXferCount = 0;
	return ercd;
}
```

一括して、左のサービスコールに定義で入れ替えれば、簡単に(μITRON系)のRTOSに対応できるということです。変換用のインクルードファイルは、pdicディレクトリの直下に置きます。

```
/*
 *  TOPPERS/ASP Kernel
 *      Toyohashi Open Platform for Embedded Real-Time Systems/
 *      Advanced Standard Profile Kernel
 * 
 *  Copyright (C) 2008-2011 by Embedded and Real-Time Systems Laboratory
 *              Graduate School of Information Science, Nagoya Univ., JAPAN
 *  Copyright (C) 2015-2021 by TOPPERS PROJECT Educational Working Group.
 * 
 *  上記著作権者は，以下の(1)～(4)の条件を満たす場合に限り，本ソフトウェ
 *  ア（本ソフトウェアを改変したものを含む．以下同じ）を使用・複製・改
 *  変・再配布（以下，利用と呼ぶ）することを無償で許諾する．
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
 *      権表示，この利用条件および下記の無保証規定が，そのままの形でソー
 *      スコード中に含まれていること．
 *  (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
 *      用できる形で再配布する場合には，再配布に伴うドキュメント（利用
 *      者マニュアルなど）に，上記の著作権表示，この利用条件および下記
 *      の無保証規定を掲載すること．
 *  (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
 *      用できない形で再配布する場合には，次のいずれかの条件を満たすこ
 *      と．
 *    (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
 *        作権表示，この利用条件および下記の無保証規定を掲載すること．
 *    (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
 *        報告すること．
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
 *      また，本ソフトウェアのユーザまたはエンドユーザからのいかなる理
 *      由に基づく請求からも，上記著作権者およびTOPPERSプロジェクトを
 *      免責すること．
 * 
 *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，特定の使用目的
 *  に対する適合性も含めて，いかなる保証も行わない．また，本ソフトウェ
 *  アの利用により直接的または間接的に生じたいかなる損害に関しても，そ
 *  の責任を負わない．
 * 
 *  @(#) $Id: base_platform.h 700 2021-10-03 18:12:09Z roi $
 */
/*
 *  TOPPERS BASE PLATFORMの外部宣言
 */

#ifndef _BASE_PLATFORM_H_
#define _BASE_PLATFORM_H_

#ifdef __cplusplus
 extern "C" {
#endif

/*
 *  バージョン情報
 */
#define	TPLATFORM_PRVER 0x1043		/* プラットフォームのバージョン番号 */


/*
 *  リアルタイムカーネル定義(JSP/ASP)
 */
#define DELAY_TASK								dly_tsk
#define SLEEP_TASK								slp_tsk
#define TIME_SLEEP_TASK							tslp_tsk
#define WAKEUP_TASK								wup_tsk
#define WAIT_SEAMPHORE							wai_sem
#define TIME_WAIT_SEAMPHORE						twai_sem
#define SIGNAL_SEAMPHORE						sig_sem
#define INTERRUPT_SIGNAL_SEAMPHORE				isig_sem
#define LOCK_CPU								loc_cpu
#define UNLOCK_CPU								unl_cpu
#define ENABLE_INTERRUPT						ena_int
#define DISABLE_INTERRUPT						dis_int

#define GET_TASK_ID								get_tid
#define ACTIVATE_TASK							act_tsk
#define START_CYCLIC_HANDLER					sta_cyc
#define STOP_CYCLIC_HANDLER						stp_cyc
#define RECEIVE_DATA_QUEUE						rcv_dtq
#define TIME_RECEIVE_DATA_QUEUE					trcv_dtq
#define POLLING_SEND_DATA_QUEUE					psnd_dtq
#define INTERRUPT_POLLING_SEND_DATA_QUEUE		ipsnd_dtq

#ifdef __cplusplus
}
#endif

#endif

```

（実は、FreeRTOSにも対応したので、この後、思った以上の大開発となりました）
・pdic    PDICドライバー
・gdic    GDICドライバー
・files   ファイルシステム
・usb     USBホスト、デバイスミドルウェア
・ui      グラフィックUIミドルウェア
・lwIP    lwIP中のTOPPERS依存部のみマクロ化
タスクモニターはRTOS依存で、マクロ化は行わない。また、もともと、JPEGやMP3はRTOSに依存性はないので不要です。

・第１次作業（ASP3カーネルへのポーティング）
　最初のターゲットであるSTM32F401 nucleo-64用のASP3カーネルの簡易パッケージをダウンロード展開して、タスクモニタを追加する。タスクモニタは時間設定付きのサービスコールの時間を1000倍すれば、すぐに動くと思ったのですが、カーネル内でtask_terminateという関数名がグローバルで使われていて、タスクモニタ内で同一名の関数をtask_terminate2に書き換えたり、古いstm32cube用のハードウェア設定インクルードファイル(stm32f4fxx.h)をカーネル内で参照し、その設定がアプリレベルまで影響を及ぼしたり。また、TOPPERS BASE PLATFORM中のソースが、itron.hやkernel_impl.h等をインクルードしていたので、これをやめ、kenrel.hのみを使うように書き換えたり等で、ソースレベルで細かく修正を行いました。
pdicの下のマクロ対応インクルードファイルをASP3用に入れ替え

```
/*
 *  TOPPERS/ASP3 Kernel
 *      Toyohashi Open Platform for Embedded Real-Time Systems/
 *      Advanced Standard Profile Kernel
 * 
 *  Copyright (C) 2008-2011 by Embedded and Real-Time Systems Laboratory
 *              Graduate School of Information Science, Nagoya Univ., JAPAN
 *  Copyright (C) 2015-2021 by TOPPERS PROJECT Educational Working Group.
 * 
 *  上記著作権者は，以下の(1)～(4)の条件を満たす場合に限り，本ソフトウェ
 *  ア（本ソフトウェアを改変したものを含む．以下同じ）を使用・複製・改
 *  変・再配布（以下，利用と呼ぶ）することを無償で許諾する．
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
 *      権表示，この利用条件および下記の無保証規定が，そのままの形でソー
 *      スコード中に含まれていること．
 *  (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
 *      用できる形で再配布する場合には，再配布に伴うドキュメント（利用
 *      者マニュアルなど）に，上記の著作権表示，この利用条件および下記
 *      の無保証規定を掲載すること．
 *  (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
 *      用できない形で再配布する場合には，次のいずれかの条件を満たすこ
 *      と．
 *    (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
 *        作権表示，この利用条件および下記の無保証規定を掲載すること．
 *    (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
 *        報告すること．
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
 *      また，本ソフトウェアのユーザまたはエンドユーザからのいかなる理
 *      由に基づく請求からも，上記著作権者およびTOPPERSプロジェクトを
 *      免責すること．
 * 
 *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，特定の使用目的
 *  に対する適合性も含めて，いかなる保証も行わない．また，本ソフトウェ
 *  アの利用により直接的または間接的に生じたいかなる損害に関しても，そ
 *  の責任を負わない．
 * 
 *  @(#) $Id: base_platform.h 700 2021-11-12 13:42:25Z roi $
 */
/*
 *  TOPPERS BASE PLATFORMの外部宣言
 */

#ifndef _BASE_PLATFORM_H_
#define _BASE_PLATFORM_H_

#ifdef __cplusplus
 extern "C" {
#endif

/*
 *  バージョン情報
 */
#define	TPLATFORM_PRVER 0x1043		/* プラットフォームのバージョン番号 */


/*
 *  リアルタイムカーネル定義(ASP3)
 */
#define DELAY_TASK(t)							dly_tsk((t)*1000U)
#define SLEEP_TASK								slp_tsk
#define TIME_SLEEP_TASK(t)						tslp_tsk((t)*1000U)
#define WAKEUP_TASK								wup_tsk
#define WAIT_SEAMPHORE							wai_sem
#define TIME_WAIT_SEAMPHORE(id, t)				twai_sem((id), ((t)*1000U))
#define SIGNAL_SEAMPHORE						sig_sem
#define INTERRUPT_SIGNAL_SEAMPHORE				isig_sem
#define LOCK_CPU								loc_cpu
#define UNLOCK_CPU								unl_cpu
#define ENABLE_INTERRUPT						ena_int
#define DISABLE_INTERRUPT						dis_int

#define GET_TASK_ID								get_tid
#define ACTIVATE_TASK							act_tsk
#define START_CYCLIC_HANDLER					sta_cyc
#define STOP_CYCLIC_HANDLER						stp_cyc
#define RECEIVE_DATA_QUEUE						rcv_dtq
#define TIME_RECEIVE_DATA_QUEUE					trcv_dtq
#define POLLING_SEND_DATA_QUEUE					psnd_dtq
#define INTERRUPT_POLLING_SEND_DATA_QUEUE		ipsnd_dtq

#ifdef TOPPERS_NUCLEO_F401RE
#define TOPPERS_STM32F401_NUCLEO
#include "stm32f4xx_tbp.h"
#endif

#ifdef __cplusplus
}
#endif

#endif

```

ASP用とASP3用で、変更となる引数をカーネルに合わせて調整しています。
85行目のstm32f4xx_thp.hのインクルードですが、ASP3カーネルの実装でSTM32CubeのCPUコア用のstm32f4xx.hをインクルードしています。この定義が一部、TOPPERS BASE PLATFORMで使用しているコア定義stm32f4xx.hを重複してWarningを出すので、重ならない部分のみを取り出し、stm32f4xx_tbp.hを作ってインクルードしデバイスドライバーで参照できるようにしました。

【ASP3ポーティング手順のまとめ】
1)V1.4.3以降のTOPPERS BASE PLATFORM(ST/RV)をダウンロードしてtarコマン ドで解凍する．

2)プラットフォームの部品（以下）を、実行確認したasp3ディレクトリに ディレクトリ毎コピーする．
 files		(ファイルシステム)
 gdic		(GDICドライバ)
 pdic		(PDICドライバ)
 stmcube	(参照STM32Cubeソース)
 ui		(UIミドルウェア)
 usb		(USBミドルウェア)

3)メモリマネージャーをコピーする．
  asp/syssvc中の以下のファイルをasp3/syssvcにコピー
  malloc.c/tlsf.c/tlsf.cfg/tlsf.h

4)不要なディレクトリを削除
  filesディレクトリ中のsysディレクトリを削除
　(これはASPカーネルは変数の型定義を独自に定義していますが、ASP3カーネルではstdint.hを使用しています。標準的なC言語のインクルードファイルを参照するとstdint.hを参照するため、カーネル内の独自な型定義とぶつかってエラーとなります。ASPカーネルでビルドを行うには、これを回避するため、sys/_stdint.hのダミーを作って、stdint.hを参照しないための仕掛けです。ASP3カーネルでは、この仕掛けは不要なため、削除となります)

5)仕様変更となった静的サービスコールを修正
  周期ハンドラの静的サービスコールを修正（USBミドルウェアのみ使用）
　usb/host/tusbh.cfgのCRE_CYCをASP3の仕様に修正
　　CRE_CYC(TUSBH_CYC_HDR, { TA_NULL, 0, tusbhCyclicHandler, 1, 0 });
　　　　　↓
　　CRE_CYC(TUSBH_CYC_HDR, { TA_NULL, { TNFY_HANDLER, 0, 
　　　　　　　　　　　　　　　　　　tusbhCyclicHandler }, 1000, 0 });
　（ASPとASP3の静的APIの差異として、CRE_CYC以外にもCRE_ISRがありますが、これはアプリ側の変更となるため、記載していません）
ASP3対応のTOPPERS BASE PLATFORMアプリとして、STM32F401 nucleo-64ボードにUSBシールド（USBシールドの内容はTOPPERS BASE PLATFORM V1.4.2 Reference Manual(ST)中に記載があります。このシールドをSTN32F401 nucleo-64に装着するとUSBホストやデバイスが利用できるようになります）を付け、USBホストアプリを動かします。（USBホストが一番サービスコールを使用するため）
シールド上のUSBコネクタにマウスを接続して、マウスのデータの取り込みが正しく動作するかを確認します。
![IMG_20211220_154344.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/961086/33e83884-0d21-fd3a-8a9e-440c248dcad2.jpeg)


　以上で、細かい問題は発生しましたが、TOPPERS BASE PLATFORMの問題ではなく、USBホストアプリは動作しました。以下は、起動時のログ表示：
![asp3-t1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/961086/b1e44e6c-acd6-7cab-52f3-37e076ddb744.png)
以下は、エナミュレーション後、マウスのデータの表示を行うログ：
![asp3-t2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/961086/75c65a2c-647b-6018-13e6-3011f8d95e16.png)


・第２次作業（FreeRTOSへのポーティング）
　図に乗って、別系列へのRTOSへポーティングするとどうなるかの実験を行いました。FreeRTOSの基本スタンスは、「CPUとシステムタイマー関連のみポーティングソースとして提供し、他のソフトは自作してください」のスタンスのRTOSです。加えて、cmsis-osのようにFreeRTOSに新たなAPIを追加して、別のRTOSを作成もできます。今回ポーティングを行ったのは、FreeRTOS V10.4.3 LTS Patch2です。
　また、TOPPERS BASE PLATFORMが静的APIを使用しているので、これを、そのまま使用したいという野望があり、FreeRTOS+Configuretarという、新たな枠組みでポーティングを行いました。簡単に説明すると、割り込み系や静的生成機能はFreeRTOSにはないので、これらをASPカーネルのリソースで保管する形を作ってしまおうというものです。(ena_intというサービスコールはFreeRTOSにはないので、この形で機能拡張してしまおうということ。但し、FreeRTOS系の名称ならばvEnableInterrupt等の名前に書き換えた方がそれらしいですか...)

　ER型について、μITRONではE_OKは0ですが、FreeRTOSでは、これに相当するリターン値は pdTRUEで、値がが1なので、E_OKを1と定義し直しています。（定義を変えても、まったく、動作上は問題なく動作しました。）
 FreeRTOSのリソースの設定、または、FreeRTOSで規定していない機能（割込み等）のリソースの生成はASPカーネル用のコンフィギュレータで自動生成します。
・CRE_TSK:FreeRTOSのタスクリソースを静的に生成
・CRE_SEM:FreeRTOSのバイナリセマフォリソースを動的に生成
・CRE_DTQ:FreeRTOSのキューデータリソースを動的に生成
・CRE_CYC:FreeRTOSのタイムマネージャーを動的に生成
・ATT_ISR,DEF_INH,CFG_INT:ASPカーネルの割込みリソースを静的にそのまま使用
・ATT_INI:ASPカーネルの割込み初期設定機能をそのまま使用
ハードウェアの初期化も、aspカーネル用をそのまま使用します。
他のFreeRTOSのサービスコールを使用したい場合は、_main()を書き換えるか、タスク中に動的に生成できます。
割込みも、WEEK関数の割込みハンドラが、そのまま残っているので、グローバル定義して使用可能です。割込み設定もx_config_int関数を使用してもよいし、自作しても問題ありません。
　以下がメイン関数（_mainとしている）です。この関数が呼ばれる前に、C言語の初期化やハードウェアの初期化(hardware_init_hook)は終了しています。システムクロック（SystemFrequency：これは定義）を変数SystemCoreClockに入れてFreeRTOSに渡します。（渡し方はFreeRTOSConfig.hを参照してください。）_main関数内で_kernel_init()関数で、コンフィギュレータで生成されたデータをもとにFreeRTOSのリソースを生成します。（リソースの生成はFreeRTOSの初期化、タスク生成前に行っても問題ありません。）その後、vTaskStartScheduler()関数を呼び出して、FreeRTOSの初期化とタスクの起動を行います。正常に起動すれば、この関数をぬけてくることはありません。
　その前のコンパイルスイッチconfigSUPPORT_STATIC_ALLOCATION内の関数はアイドルタスクとタイムマネージャータスクを静的に生成するためのコールバック関数です。

```
/*
 *  FreeRTOS+Confgurator
 * 
 *  Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
 *                              Toyohashi Univ. of Technology, JAPAN
 *  Copyright (C) 2004-2012 by Embedded and Real-Time Systems Laboratory
 *              Graduate School of Information Science, Nagoya Univ., JAPAN
 *  Copyright (C) 2016-2021 by TOPPERS PROJECT Educational Working Group.
 * 
 *  上記著作権者は，以下の(1)～(4)の条件を満たす場合に限り，本ソフトウェ
 *  ア（本ソフトウェアを改変したものを含む．以下同じ）を使用・複製・改
 *  変・再配布（以下，利用と呼ぶ）することを無償で許諾する．
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
 *      権表示，この利用条件および下記の無保証規定が，そのままの形でソー
 *      スコード中に含まれていること．
 *  (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
 *      用できる形で再配布する場合には，再配布に伴うドキュメント（利用
 *      者マニュアルなど）に，上記の著作権表示，この利用条件および下記
 *      の無保証規定を掲載すること．
 *  (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
 *      用できない形で再配布する場合には，次のいずれかの条件を満たすこ
 *      と．
 *    (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
 *        作権表示，この利用条件および下記の無保証規定を掲載すること．
 *    (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
 *        報告すること．
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
 *      また，本ソフトウェアのユーザまたはエンドユーザからのいかなる理
 *      由に基づく請求からも，上記著作権者およびTOPPERSプロジェクトを
 *      免責すること．
 * 
 *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，特定の使用目的
 *  に対する適合性も含めて，いかなる保証も行わない．また，本ソフトウェ
 *  アの利用により直接的または間接的に生じたいかなる損害に関しても，そ
 *  の責任を負わない．
 * 
 *  $Id: main.c 2416 2021-11-22 16:44:27Z roi $
 */

/* 
 *  FreeRTOS TOPPERS 拡張のメイン
 *
 *  コンフィグレータで拡張されたRTOSリソースの初期化後、FreeRTOSの実行．
 */

#include "FreeRTOS.h"
#include <target_syssvc.h>
#include "task.h"
#include "queue.h"
#include "semphr.h"


uint32_t SystemCoreClock = SystemFrequency;


#if configSUPPORT_STATIC_ALLOCATION == 1

static StaticTask_t IdleTaskStatic, TimerTaskStatic;
static uint32_t IdleTaskStack[configMINIMAL_STACK_SIZE];
static uint32_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];

void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
	*ppxIdleTaskTCBBuffer = &IdleTaskStatic;
	*ppxIdleTaskStackBuffer = IdleTaskStack;
	*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}

void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
                                     StackType_t ** ppxTimerTaskStackBuffer,
                                     uint32_t * pulTimerTaskStackSize )
{
	*ppxTimerTaskTCBBuffer = &TimerTaskStatic;
	*ppxTimerTaskStackBuffer = TimerTaskStack;
	*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}


#endif	/* configSUPPORT_STATIC_ALLOCATION */

/*
 * main関数
 */ 
void
_main(void)
{
	/* RTOSリソース初期化 */
	_kernel_init();

	vTaskStartScheduler();
	for (;;) {
	}
}
```

　TOPPERS BASE PLATFORM中のサービスコールマクロを、実際の関数に置き替えるためのインクルードファイルは以下の通りです。流石にinline関数でないと書き換えられない変換が多々ありました。ASP/ASP3版と見比べてみてください。


```
/*
 *  FreeRTOS+Confgurator
 * 
 *  Copyright (C) 2008-2011 by Embedded and Real-Time Systems Laboratory
 *              Graduate School of Information Science, Nagoya Univ., JAPAN
 *  Copyright (C) 2015-2021 by TOPPERS PROJECT Educational Working Group.
 * 
 *  上記著作権者は，以下の(1)～(4)の条件を満たす場合に限り，本ソフトウェ
 *  ア（本ソフトウェアを改変したものを含む．以下同じ）を使用・複製・改
 *  変・再配布（以下，利用と呼ぶ）することを無償で許諾する．
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
 *      権表示，この利用条件および下記の無保証規定が，そのままの形でソー
 *      スコード中に含まれていること．
 *  (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
 *      用できる形で再配布する場合には，再配布に伴うドキュメント（利用
 *      者マニュアルなど）に，上記の著作権表示，この利用条件および下記
 *      の無保証規定を掲載すること．
 *  (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
 *      用できない形で再配布する場合には，次のいずれかの条件を満たすこ
 *      と．
 *    (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
 *        作権表示，この利用条件および下記の無保証規定を掲載すること．
 *    (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
 *        報告すること．
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
 *      また，本ソフトウェアのユーザまたはエンドユーザからのいかなる理
 *      由に基づく請求からも，上記著作権者およびTOPPERSプロジェクトを
 *      免責すること．
 * 
 *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，特定の使用目的
 *  に対する適合性も含めて，いかなる保証も行わない．また，本ソフトウェ
 *  アの利用により直接的または間接的に生じたいかなる損害に関しても，そ
 *  の責任を負わない．
 * 
 *  @(#) $Id: base_platform.h 700 2021-12-08 18:12:09Z roi $
 */
/*
 *  TOPPERS BASE PLATFORMの外部宣言
 */

#ifndef _BASE_PLATFORM_H_
#define _BASE_PLATFORM_H_

#ifdef __cplusplus
 extern "C" {
#endif

/*
 *  バージョン情報
 */
#define	TPLATFORM_PRVER 0x1043		/* プラットフォームのバージョン番号 */


/*
 *  リアルタイムカーネル定義(FreeRTOS+Confgurator)
 */
#define DELAY_TASK(t)							vTaskDelay((t)/portTICK_RATE_MS)
#define SIGNAL_SEAMPHORE(id)					xSemaphoreGive(getFreeRTOSSemahoreHandle((id)))
#define WAIT_SEAMPHORE(id)						xSemaphoreTake(getFreeRTOSSemahoreHandle((id)), portMAX_DELAY)
#define ENABLE_INTERRUPT						ena_int
#define DISABLE_INTERRUPT						dis_int
#define RECEIVE_DATA_QUEUE(id, p)				xQueueReceive(getFreeRTOSQueueHandle((id)), (p), portMAX_DELAY)
#define TIME_RECEIVE_DATA_QUEUE(id, p, t)		xQueueReceive(getFreeRTOSQueueHandle((id)), (p), (t)/portTICK_RATE_MS)
#define POLLING_SEND_DATA_QUEUE(id, d)			xQueueSendToBack(getFreeRTOSQueueHandle((id)), &(d), 0)

Inline ER SLEEP_TASK(void){
	TaskHandle_t chandle = getFreeRTOSTaskHandle(TSK_SELF, NULL, NULL);

	if(chandle == NULL)
		return E_OBJ;
	else{
		vTaskSuspend(chandle);
		return E_OK;
	}
}

Inline ER WAKEUP_TASK(ID tskid){
	TaskHandle_t chandle = getFreeRTOSTaskHandle(tskid, NULL, NULL);

	if(chandle  == NULL)
		return E_OBJ;
	else{
		vTaskResume(chandle);
		return E_OK;
	}
}

Inline ER TIME_SLEEP_TASK(TMO tmout){
	TaskHandle_t chandle = getFreeRTOSTaskHandle(TSK_SELF, NULL, NULL);

	if(chandle == NULL)
		return E_OBJ;
	else{
		vTaskSuspendTimeout(chandle, tmout/portTICK_RATE_MS);
		return E_OK;
	}
}


Inline ER TIME_WAIT_SEAMPHORE(ID semid, TMO tmout){
	SemaphoreHandle_t shandle;
	TickType_t timeout;

	if((shandle = getFreeRTOSSemahoreHandle(semid)) == NULL)
		return E_PAR;
	if(tmout == TMO_FEVR)
		timeout = portMAX_DELAY;
	else
		timeout = tmout/portTICK_RATE_MS;
	return (ER)xSemaphoreTake(shandle, timeout);
}

Inline ER INTERRUPT_SIGNAL_SEAMPHORE(ID semid){
	SemaphoreHandle_t shandle;
	portBASE_TYPE xHigherPriorityTaskWoken;

	if((shandle = getFreeRTOSSemahoreHandle(semid)) == NULL)
		return E_PAR;
	xSemaphoreGiveFromISR( shandle, &xHigherPriorityTaskWoken );
	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
	return E_OK;
}

Inline ER LOCK_CPU(void){
	vPortEnterCritical();
	return E_OK;
}

Inline ER UNLOCK_CPU(void){
	vPortExitCritical();
	return E_OK;
}

Inline ER START_CYCLIC_HANDLER(ID cycid){
	TimerHandle_t thandle = getFreeRTOSTimerHandle(cycid);

	if(thandle != NULL){
		if(xTimerStart(thandle, 0) == pdTRUE)
			return E_OK;
		else
			return E_SYS;
	}
	else
		return E_OBJ;
}

Inline ER STOP_CYCLIC_HANDLER(ID cycid){
	TimerHandle_t thandle = getFreeRTOSTimerHandle(cycid);

	if(thandle != NULL){
		if(xTimerStop(thandle, 0) == pdTRUE)
			return E_OK;
		else
			return E_SYS;
	}
	else
		return E_OBJ;
}

Inline ER INTERRUPT_POLLING_SEND_DATA_QUEUE(ID qid, int data){
	QueueHandle_t qhandle;
	portBASE_TYPE xHigherPriorityTaskWoken;

	if((qhandle = getFreeRTOSQueueHandle(qid)) == NULL)
		return E_OBJ;
	xQueueSendToBackFromISR( qhandle, &data, &xHigherPriorityTaskWoken );
	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
	return E_OK;
}

#define GET_TASK_ID								get_tid
#define ACTIVATE_TASK							act_tsk

#ifdef __cplusplus
}
#endif

#endif

```

上記のTIME_SLEEP_TASK中のvTaskSuspendTimeout関数ですが、FreeRTOSには、タスク対するブロック機能はsuspendとresumeしかありません。suspendには時間指定はありませんので、自作したものです。その他はFreeRTOSのサービスコールです。getFreeRTOS...関数はIDからハンドラを取り出す関数です。


```
void
vTaskSuspendTimeout(TaskHandle_t thandle, const TickType_t xTicksToDelay)
{
	int tskno;

	if(xTicksToDelay == 0)
		return;
	for(tskno = 0 ; tskno < TNUM_TSKID ; tskno++){
		if(thandle == tbp_tsk_table[tskno])
			break;
	}
	if(tskno == TNUM_TSKID)
		return;
	vTaskEnterCritical();
	if(TimerPeriod > xTicksToDelay){
		TimerPeriod = xTicksToDelay;
		xTimerChangePeriod(tbp_cyc_table[TNUM_CYCID], TimerPeriod, 0);
	}
	tbp_tasksleep_time[tskno] = xTicksToDelay;
	if(TasksleepCount == 0)
		xTimerStart(tbp_cyc_table[TNUM_CYCID], 0);
	TasksleepCount++;
	vTaskExitCritical();
	vTaskSuspend(thandle);
	tbp_tasksleep_time[tskno] = 0;
}

```

自分自身をsuspendする場合、その時間をtbp_tasksleep_timeに保存しておき、タイムマネージャーを起動して、時間が経過したらresumeしてもらう形で実装しました。


FreeRTOS+Confugurater版でも、問題なくTOPPERS BASE PLATFORMのサンプルプログラムは動作しました。
ASP3と同等に、USBホストアプリ動かしました。以下はFreeRTOSの起動ログ：
![freertos-t1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/961086/7aff486d-34f4-da03-13ec-f74d91d58c6c.png)
続けてエナミュレーション中のログ表示：
![freertos-t2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/961086/1f181fa0-a5f2-7dab-27a2-7d1f68eb5753.png)

・考察
　TOPPERS BASE PLATFORMマクロ化により、ASP以外のRTOSでも問題なく、TOPPERS BASE PLATFORMのドライバーやミドルウェアが動作することがわかりました。このバージョンはV1.4.3として、来年リリースする予定です。
　実は、FreeRTOSへのConfiguraterの対応ですが、すでにTOPPERS BASE PLATFORMが実装されている以下のボードで実装が終了しています。
・STMicroelectronix系：18のボード
・RISC/V系：Hi-Five1とlongan-nano
　RISC/V系のポーティングは、FreeRTOS V10.4.3 LTS Patch2で提供されるportable/GCC/RISC-Vのソースでは、いろいろと問題が発生したので、新しく作り直しています。
　TOPPERSプロジェクトはFreeRTOSを普及する団体ではないので、ここで開発したプログラムを、どのように扱おうかを思案中です。何か要望がありましたら、ご連絡ください。

・その他気付いたこと
１）カーネル中のハードウェアのリソースの定義（インクルードファイル）は、使用するものだけをローカルにした方が良いですね。（私の方も、ASPカーネルの実装の中にstm32f4xx.hという名前でハードウェアリソースを置いたので、人のことは言えませんが...、新しい系列をポーティングすることがあったら、やめようと思います）デバイスドライバーを自由に作ろうとする場合、RTOSを部品化としてを取り込もうとすると、古いデバイスリソースの参照がで来るのは邪魔です。今回の実験でLINUX等のドライバーでローカルにハードウェアのリソース定義している意味が良くわかりました。もちろん、FreeRTOSのportable以下のソースも同様な構成となっています。組込みプラットフォームでデバイスドライバ用に好きなようにハードウェアリソースを構築するとこが可能です。リアルタイムカーネルの基本的な要素である組込みシステムのカーネル部品として使用するために最適の構造を持っていると言えます。
２）カーネル内で変数の型定義を独自にしているのは、邪魔です。（コンパイルするたびにエラー発生の要因になります）。やっぱり、カーネルでも、C言語と同一型を定義するなら、stdint.hを参照してほしいです。