LoRaモジュールLRA1だけでLチカをやってみる

[LRA1](http://www.i2-ele.co.jp/LoRa.html) は単なる通信モジュールだけではなく、モジュール単体でプログラムを実行できる機能を持っています。加えてI/Oポート(GPIO)がユーザーに開放されているので、これらをプログラムで制御することで外部のマイコンを使わないでIoTデバイスを組むこともできます。この記事ではその特長を生かしてLEDをチカチカすることをやってみたいと思います

プログラム言語はBASICです。懐かしいと思った方もいらっしゃると思います。MSXというテレビに繋いで使う家庭用のパソコンが流行った頃があって、その中に使われていたのがBASICです。現在のVisual Basicやエクセルで使われているVBAにもBASICという名前が入っていますが、親戚なので若干似ている所があるかもしれませんが別物と考えていた方がいいでしょう

# BASICについて

BASICの使い方やコマンドなどは [LoRaモジュール資料](http://www.i2-ele.co.jp/LoRa.html) の [ソフトウェアリファレンスマニュアル](https://www.i2-ele.co.jp/LRA1_software.html) に詳しく掲載されていますので、ここでは覚えておきたいことを簡単にまとめています

また、 [UART/BASICプログラムチュートリアル](https://www.i2-ele.co.jp/LRA1_UART_BASIC.html) にサンプルプログラムがいくつか掲載されていますので、それを参考にしてもいいでしょう

## BASICの基礎知識

* オブジェクト指向ではなく、シングルスレッドで動作しますので行いたい処理を上から下に書いていくイメージで作ります
* BASICの独特なルールとして先頭に `行番号` を入れて、番号に続けて命令文を入れていきます
    * 行番号の小さい順から処理が進められ、最後の行まで処理が進むと終了します
    * 行番号はよく `10, 20, 30...` と `+10きざみ` で入れて行くことが多いですが `+1` でも `+100` でも構いません。後で間に処理を追加したくなった時に `10, 11, 20, 30...` のように番号の間に足して行けるのですが、番号を詰めすぎると入れられなくなって番号の降り直しが必要になるので注意が必要です
        * 行番号の降り直しは `RENUM [増加数]` コマンドで行えます
        * ただし、GOTO文などでの移動先を示した行番号は降り直しされないので、手間はかかってしまいます
    * コマンドを `:` で繋げることで1行に複数のコマンドを書くことができます
* コマンド名、変数名は大文字と小文字を区別しません
    * 個人的に全て大文字で書いてますが、 `PRINT` でも `print` でも `Print` でも好きなように入力して構いません
    * LRA1のインタプリタでキャメルケース(先頭だけ大文字の表記)に置き換えられます

## インタプリタの使い方

* `プログラム入力モード` というのがあります。 `EDIT 1` とコマンドを入れると入力モードが許可になり、 `EDIT 0` と入れると禁止になります。入力モードを許可にしないでプログラムを入れようとすると `Edit mode error` になります
    * プログラム入力モードが許可の時はプロンプトが `>>` になり、禁止の時は `>` になります
    * 電源を入れた直後は禁止になっています
* プログラムの入力は通常のエディタとは異なり、1行ずつ確定してメモリーに保持していく手順を踏みます
    * 1行毎の入力で(Enterキーを押した時に)、その行のプログラムが中間コードに変換されます。変換の時に入力ミスがあるとエラーが出ます
    * カーソルキーで自由に移動して一部分を修正するという操作には対応していませんので、入れ間違いが無いか確認しながら1行1行入れて行くのがコツです
    * 保持されたプログラムを確認するには `LIST` コマンドを使います
    * 入力した行のプログラムを後で変更したい時は、変更したい行の行番号を入れて、新しいプログラムを入れなおします
    * 入力した行を消したい時は、消したい行の行番号だけをいれてEnterキーを押します
* 保持されたプログラムを全消去するには `NEW` コマンドを使います

## LRA1のプログラム仕様

* プログラム(中間コードに変換後)のサイズは 4096 byteまでです
* 行番号は 1～65535 まで使えます
* 1行に入力できる文字数は254文字までですが、中間コードに変換した結果が254 byteである必要がありますので、これより短くなる可能性があります

# ピン配列の確認

ピン配列はハードウェアマニュアルに掲載されています。以下の表はハードウェアマニュアルより引用しました

| PIN番号 | 信号名 | I/O | 詳細 |
|--------|--------|-----|------|
| 1 | PB02 | I/O ANALOG |
| 2 | PA05/UART RX | IN | UART 専用 PIN |
| 3 | PA04/UART TX | OUT | UART 専用 PIN |
| 4 | PB03 | I/O ANALOG |
| 5 | PA27 | I/O | |
| 6 | PB22 | I/O | |
| 7 | PA06/WAKEUP | I/O ANALOG(※1) | I/O または ↑立ち上がりで SLEEP/DEEP 解除 (※1) |
| 8 | PA07 | I/O ANALOG | |
| 9 | PA08 | I/O ANALOG | |
| 10 | VDD | POWER | |
| 11 | VDD | POWER | |
| 12 | GND | POWER | |
| 13 | GND | POWER | |
| 14 | PA09 | I/O ANALOG | |
| 15 | PA13 | I/O | |
| 16 | PA16/SDA | - | I2C 専用 PIN |
| 17 | PA17/SCL | - | I2C 専用 PIN |
| 18 | PA18 | I/O | |
| 19 | PA28 | I/O | |
| 20 | PA23 | I/O | |
| 21 | PB23 | I/O | |
| 22 | GND | POWER | |
| 23 | PA15 | I/O | |
| 24 | PA14/ACTIVE | I/O(※2) | I/O または 通常:O.C SLEEP 中:L (※2) |
| 25 | PA19 | I/O | |
| 26 | PA22 | I/O | |
| 27 | PA25 | I/O | |
| 28 | PA24 | I/O | |
| 29 | PA31/SWDIO | - | |
| 30 | PA30/SWDCLK | - | |
| 31 | PA01/XOUT32 | I/O | 外部クロック使用時 XOUT 32.768kHz |
| 32 | PA0/XIN32 | I/O | 外部クロック使用時 XIN 32.768kHz |
| 33 | RESET | - | |
| 34 | GND | POWER | |
| 35 | RF_GND | RF | |
| 36 | RF_OUT | RF | LRA1-SMA のみ、他は未接続 |
| 37 | RF_GND | RF |  |

> ※1. I/O として使用可能ですが、SLEEP/DEEP を使用した場合は WAKEUP_IN として入力ポートに強制的に切り替わりますので SLEEP/DEEP 機能を使用する場合はご注意ください。
>
> ※2. I/O として使用可能ですが、SLEEP/DEEP を使用した場合は ACTIVE_OUT として出力ポートに強制的に切り替わりますので SLEEP/DEEP 機能を使用する際はご注意ください。

Lチカやスイッチを繋ぐなど、ユーザーに使えるようにしているピンは表で `I/O` と表記されている箇所です。その中でも、一部は特定の機能専用に割り当てられているポートがありますが、これらを除いて使うのが無難です

## 評価ボードの場合

* PA18とPA19は基板上のLEDに繋がっています。LCDの右にある2つのLEDでPA18は赤、PA19は緑に光ります
* 評価ボードには1～34番までのピンがモジュールと繋がっています
* ピンは写真のように左下から `下上 一つ右にずれて下上 更にずれて...` と配置されています。親切にも基板上に番号が書かれていますので、これ(赤丸で囲った場所)を目印にすればいいでしょう
![P3220058.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61404/ed991c84-db69-a96a-8476-1fe878a74b24.jpeg)

## ピン指定の番号

PIN番号はモジュールの足や評価ボードに付いているピンに順番に当てた番号です

プログラム上で指定するのは信号名に記載された `PA` や `PB` に続く2桁の番号です。 `PA` はそのままの番号で指定しますが、 `PB` はその番号に `32を加えた数` が指定する番号になります

```:番号の指定例
PA18 は 18
PB23 は (23 + 32) なので 55
```

## LEDの接続

I/Oのピンであればどこでもいいですが、ここではGNDの近くにある PA13 を選びました

![P_20200324_215419_vHDR_Auto.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61404/ba9496ad-75ed-35af-8fad-1ba2818d993b.jpeg)

写真では 13番(GND) と 15番(PA13) のピンをLEDに繋いでいます。LEDには数100Ωの抵抗を挟んでください

# プログラムの入力

PCとLRA1を繋いでターミナルを開きます。詳しい手順は [前の記事](https://qiita.com/suzutsuki0220/items/7c96d8d3ebd5404d1036) を見てください

ターミナルを開いたら、最初にコマンド `EDIT 1` で入力を許可の状態にします

```shell:LRA1プロンプト
i2-ele LRA1
Ver 0.31.g
OK
>
>EDIT 1
OK
>>
```

プロンプトが `>>` に変わったことをご確認ください

# LEDを点灯・消灯する

## LED点灯

プロンプトで `OUTP [LEDを繋いだピン],1` を入力するとLEDが点灯します

```shell:例)PA13に繋いだLEDを光らせる
>>OUTP 13,1
OK
```

## LED消灯

`OUTP [LEDを繋いだピン],0` を入力するとLEDが消灯します

```shell:例)PA13に繋いだLEDを消す
>>OUTP 13,0
OK
```

## プログラムで繰り返し点灯・消灯を行う

BASICのプログラムを実行してLEDの点灯・消灯を繰り返し行って見ます。以下のサンプルコードを入力してください

```vb:Lチカサンプルコード
10 WHILE 1
20 OUTP 13,1
30 DELAY 1000
40 OUTP 13,0
50 DELAY 1000
60 LOOP
```

### 実行

プログラムの入力を終えたら実行してみます `RUN` と入れてください。LEDがチカチカしたはずです

```shell
>>RUN
```

プログラム実行中はプロンプトが入力を受け付けなくなります。プログラムの中断は `Ctrl + c` を押してください

### プログラムの変更

メモリに保持されているプログラムを確認するには `LIST` コマンドを入れます

```shell:LISTコマンドの実行結果
>>LIST
10 While 1
20 Outp 13,1
30 Delay 1000
40 Outp 13,0
50 Delay 1000
60 Loop
[55/4096 bytes]
OK
```

ここで、30行目の DELAY の値を変えてみます。変更したい行の行数とコマンドを入れます

```shell
>>30 DELAY 100
```

そして `RUN` コマンドを入れてプログラムを実行してみます

```shell
>>RUN
```

LEDの点灯時間が短くなりました。再度 `LIST` で確認すると入力しなおした30行目の DELAY の値が `1000` から `100` に変わっているのが分かります

```shell
>>LIST
10 While 1
20 Outp 13,1
30 Delay 100
40 Outp 13,0
50 Delay 1000
60 Loop
[54/4096 bytes]
OK
```

このようにしてLRA1にプログラムを入れることができます

## プログラムの保存と起動時の実行

### 保存

入力したプログラムは保存をしないと、電源を切るかリセットした時には失われてしまいます。プログラムの保存には `PSAVE` コマンドを使います

```shell
>>PSAVE
OK
```

### 読込み

保存したプログラムは `PLOAD` コマンドで読込みできます。起動した状態から `LIST` コマンドを入れて `PLOAD` コマンドで復元されていることを確認します

```shell
i2-ele LRA1
Ver 0.31.g
OK
>LIST
[0/4096 bytes]
OK
>PLOAD
OK
>LIST
10 While 1
20 Outp 13,1
30 Delay 100
40 Outp 13,0
50 Delay 1000
60 Loop
[54/4096 bytes]
OK
```

### 起動時の実行

電源ONした時にBASICプログラムを動かすには `AUTO` という名前の変数に `pload:run` (つまりBASICのコマンドでプログラムの読み込みと実行)を設定します。変数を変えた後は、その値を保持するために `SSAVE` コマンド(LoRa変数の保存)を実行します

```shell:起動時の実行を設定する
>AUTO="pload:run"
OK
>SSAVE
OK
```

これで、電源を入れなおした時にLEDがチカチカします。起動時の実行もターミナルを開いて `Ctrl + c` のキー入力で中断できます

起動時の実行を止めたい時はAUTO変数を空にしてください

```shell:起動時の実行を止める
>AUTO=
OK
>SSAVE
OK
```

AUTO変数の中身は `?AUTO` で確認できます

# 消費電力について

モジュール内のプログラム機能を使う利点として、消費電力の削減が挙げられます。電池で動かすとなると、処理用の別のマイコンがあるとその分の電力も必要になりますので運用上は不利になってしまいます

## LRA1の消費電力

LRA1の消費電力はハードウェアマニュアルの 8.3 電気的特性 にある通り送信時でも 37mA です。センサーの値を送るだけであれば送信時間も1時間に何回かなので、そんな頻繁ではないと思います

| 条件 | 消費電流 |
|:-----|:-------:|
| 送信時(13dBm出力) | 37mA |
| 受信時 | 13mA |
| 通常動作時 | 0.7mA |
| Sleep時 | 1.8uA |
| Deep Sleep時 | 0.6uA |

動作電圧 3.3V時 ハードウェアマニュアルより抜粋

## Wi-Fiの消費電力

あくまでも参考として比較ですが、Wi-Fiが搭載された ESP32 の消費電力を挙げてみました。Ambient さんの [記事](https://ambidata.io/samples/m5stack/m5stackcurrent/) から拝借させていただきます

記事には、M5Stack と ESPr Developer32 の消費電力値がありますが、M5StackはLCDや充電回路が入っていてLRA1と条件が違いすぎますので、ESPr Developer32 の値と比べてみます

| 処理 | 消費電流 |
|:-----|:--------|
| WiFi.begin〜WiFi.status | 47〜160mA、ピークでは320mA |
| ambient.send | 44〜120mA |
| deepsleep中 | 0.3mA |

LRA1とは計測条件が違いますので、明確な比較ではないのですがWi-Fiとの違いがイメージ出来るのではないかと思います

LRA1の通常動作時の電流(0.7mA)がESP32のDeep Sleep時(0.3mA)と 0.4mA しか変わらないというのは気になります。もう少し使いこなせるようになったら消費電力の検証も行ってみたいですね