Wio Terminal で TOPPERS/ASPカーネル : Getting started

数年前に，[R2CA](https://qiita.com/exshonda/items/093870ecdcda6c79678c) を開発したのですが，Arduino M0 がディスコンになり開発を止めていました．

Arduino M0 に近い [Wio Terminal](https://jp.seeedstudio.com/Wio-Terminal-p-4509.html)が発売され，ライブラリを見ていると，[FreeRTOSのArduinoライブラリ](https://github.com/Seeed-Studio/Seeed_Arduino_FreeRTOS)があることを知り，コードを読むとASPカーネルでも出来そうだと考え作成しました．


## Wio Terminal用のArduino環境のインストール

[Seeedのwiki](https://wiki.seeedstudio.com/jp/Wio-Terminal-Getting-Started/)を参考に，Arduino環境とライブラリをインストールしてBlinkが動作することを確認します．

なお，ArduinoIDEは1.8.6以上が必要です．

## ハードウェア設定(オプション)

UART経由のコンソールを出力したい場合は，[適当なUSB-UART](https://www.switch-science.com/catalog/1196/)を裏の拡張コネクタの以下のピンに接続します．

| 端子番号 | 機能 |
----|---- 
|  6 | GND | 
|  8 | TXD | 
| 10 | RXD | 

<img width="400" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106870/6a26b411-fc4f-44e2-738e-812b6de8caec.png">

## ライブラリのインストール

[ここ](https://github.com/exshonda/Arduino_TOPPERS_ASP/releases/)から最新のリリースのZIPファイルをダウンロードします．

Arduino IDEを起動して， スケッチ -> ライブラリをインクルード -> .ZIP形式のライブラリをインストール を選択します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106870/02a170ca-0c3d-9767-95c3-f70f5388f2d0.png)

ファイルダイアログが表示されるのでダウンロードしたZIPファイルを指定してインストールします．

## サンプルの実行

ArduinoIDEの ファイル -> スケッチの例 -> ToppersASP -> ToppersASP_Blink  を選択してサンプルを読み込みます．

- Wio TerminalのUSB端子とPCを接続する．
 - マイコンボードに書き込むを選択して書き込む．
- ターミナルエミュレータを接続
 - Wio TerminalのUSB端子によるCOMポート
 - USB UARTによるCOMポート(オプション)
- 実行
 - Wio TerminalのUSB端子によるCOMポート にターミナルエミュレータを接続すると実行が開始される．

## コード解説

ToppersASP_Blinkでは，次の3個のタスクを実行する（正確にはログタスクを加えて4個）．

- task1()
- task2()
- loop()

### setup()

以下の内容を記載する．

- USBUartの初期化(オプション)
 - 必ずサンプルと同様の順序で記載する．
- その他の初期化(オプション)
 - ポートの初期化等を記載する．
- カーネルの起動
 - StartToppersASP()を呼び出すことでカーネルが起動する．

### カーネルオブジェクトの初期化(user_inirtn())
カーネル起動後に呼び出される．カーネルオブジェクトの初期化処理を記載する．
これらのサービスコールは，この関数内で飲み呼び出し可能．

```
	ER	cre_tsk(ID tskid, const T_CTSK *pk_ctsk);
	ER	cre_sem(ID semid, const T_CSEM *pk_csem);
	ER	cre_flg(ID flgid, const T_CFLG *pk_cflg);
	ER	cre_dtq(ID dtqid, const T_CDTQ *pk_cdtq);
	ER	cre_pdq(ID pdqid, const T_CPDQ *pk_cpdq);
	ER	cre_mbx(ID mbxid, const T_CMBX *pk_cmbx);
	ER	cre_mpf(ID mpfid, const T_CMPF *pk_cmpf);
	ER	cre_cyc(ID cycid, const T_CCYC *pk_ccyc);
	ER	cre_alm(ID almid, const T_CALM *pk_calm);
	ER	cfg_int(INTNO intno, const T_CINT *pk_cint);
	ER	att_isr(const T_CISR *pk_cisr);
	ER	def_inh(INHNO inhno, const T_DINH *pk_dinh);
	ER	def_exc(EXCNO excno, const T_DEXC *pk_dexc);
```

各オブジェクトのIDは次の値を使用する．nは1～10を指定可能．10個以上のオブジェクトを使用したい場合は，./doc/customize.txt を参考のこと．

| オブジェクト | マクロ |
----|---- 
|  タスク              | TASKn | 
|  セマフォ            | SEMn  | 
|  イベントフラグ      | FLGn  | 
|  データキュー        | DTQn  | 
|  優先度データキュー  | PDQn  | 
|  メールボックス      | MBXn  | 
|  メッセージバッファ  | MBFn  | 
|  周期ハンドラ        | CYCHDRn  | 
|  アラームハンドラ    | ALMHDRn  | 

#### タスク生成の例
タスクを生成する例は次のようになる．

```
void
user_inirtn() {

  T_CTSK  ctsk;
  ER    ercd;

  ctsk.tskatr = TA_ACT;
  ctsk.exinf = 1;
  ctsk.task = task1;
  ctsk.itskpri = 10;
  ctsk.stksz = 1024;
  ctsk.stk = NULL;
  ercd = cre_tsk(TASK1, &ctsk);

  ....
}
```
タスク本体の記述は通常のASPカーネルと同じである．タスク本体では，ASPカーネルのAPIとArduinoの両方を呼び出し可能である．

```
void
task1(intptr_t exinf)
{
  int count = 0;
  while(1){
    syslog(LOG_NOTICE, "task1 is running. %d", count++);
    dly_tsk(1000);
  }
}
```

### loop()

loop()関数はASPカーネルの最低優先度のタスクとして実行される．タスクIDは，IDLE_TASK である．



### ToppersASP_Blink のソースコード
```
#include <ToppersASP.h>

#define USE_SERIALUSB

void setup() {
#ifdef USE_SERIALUSB
  SerialUSB.begin(115200);
  ToppersASPDelayMs(1000);
  while (!SerialUSB);
#endif /* USE_SERIALUSB */

  pinMode(LED_BUILTIN, OUTPUT);

  StartToppersASP();
}

void
task1(intptr_t exinf)
{
  int count = 0;
  while(1){
    syslog(LOG_NOTICE, "task1 is running. %d", count++);
    dly_tsk(1000);
  }
}

void
task2(intptr_t exinf)
{
  int count = 0;
  while(1){
    syslog(LOG_NOTICE, "task2 is running. %d", count++);
    dly_tsk(1000);
  }
}

void
user_inirtn(void)
{
  T_CTSK  ctsk;
  ER    ercd;

  ctsk.tskatr = TA_ACT;
  ctsk.exinf = 1;
  ctsk.task = task1;
  ctsk.itskpri = 10;
  ctsk.stksz = 1024;
  ctsk.stk = NULL;
  ercd = cre_tsk(TASK1, &ctsk);

  ctsk.task = task2;
  ercd = cre_tsk(TASK2, &ctsk);
  assert(ercd == E_OK);  
}

int loop_count;

void loop() {
#ifdef USE_SERIALUSB
  SerialUSB.print("loop: ");
  SerialUSB.println(loop_count++);
#else /* USE_SERIALUSB */
	syslog(LOG_NOTICE, "loop is running. %d", loop_count++);
#endif /* USE_SERIALUSB */
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}
```


## 変更履歴
- 2020/09/21
    - 新規作成
-