Wio Terminal で TinyGo プログラミングを始めよう

## お知らせ

TinyGo 0.26 + Wio Terminal という組み合わせで技術書「基礎から学ぶ TinyGoの組込み開発」 (2022/11/12 発売) を執筆しました。本ページと合わせて確認してみてください。

https://sago35.hatenablog.com/entry/2022/11/04/230919

----

このページには、 Wio Terminal + TinyGo 0.18 を使ってマイコンプログラミングを始めるための情報を記載します。
マイコンプログラミングをしたことがある人もない人も、是非試してみてください。
主に Windows 10 で試しながら書きますが、他の OS でもほとんど同じ動きになると思います。

## TinyGo とは

マイコンや WASM などの Small Places 向けの Go Compiler です。
ここでは Go の文法でマイコン開発ができるもの、という程度の認識でよいです。

* [TinyGo - Go on Microcontrollers and WASM](https://tinygo.org/)

このページは 2022/08/03 にリリースされた TinyGo 0.25 を対象としています。

## Wio Terminal とは

Wio Terminal は Seeed 社のディスプレイ付きの開発ボードです。
320 x 240 のディスプレイ、 WiFi / BLE 搭載、ボタンに加速度センサに MicroSD カードスロットに、と非常に多機能です。

マイコンは Microchip 社の ATSAMD51P19 (Arm Cortex-M4 120MHz) が搭載されています。
基本的には Arduino などでの開発が想定されているが、 TinyGo 0.14 でサポートされました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/404a5d98-173d-958d-f671-22efded38af2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/9e8dba4c-a6d8-2db1-cce2-43cb9352c1cb.png)

https://www.seeedstudio.com/Wio-Terminal-p-4509.html
https://wiki.seeedstudio.com/Wio-Terminal-Getting-Started/

WiFi / BLE 搭載ということで、技適取得済みの Version を買う必要があります。
国内では以下から購入すると良いと思います。


* スイッチサイエンス
    * https://www.switch-science.com/catalog/6360/
* 秋月電子通商
    * http://akizukidenshi.com/catalog/g/gM-15275/
* マルツ
    * https://www.marutsu.co.jp/pc/i/1633550/


## TinyGo のインストール

以下に従ってインストールを実施してください。
0.13.1 までは windows の native 版は日本語環境で動かない問題など色々ありましたが、 0.14 以降は native 版で大丈夫です。
docker で開発したい場合は、 docker 版を使っても問題ありません。
なお、 TinyGo の実行には Go のインストールも必要です。
事前に Go 1.16 あたりをインストールしておいてください。

* https://tinygo.org/getting-started/
    * https://tinygo.org/getting-started/install/linux/
    * https://tinygo.org/getting-started/install/macos/
    * https://tinygo.org/getting-started/install/windows/
    * https://tinygo.org/getting-started/install/using-docker/

### Windows でのインストール例

以下をダウンロードして、 `C:\tinygo\bin\tinygo.exe` となるように配置します。
※実際は PATH が通っていればどこでも良いです or PATH が通ってなくても tinygo.exe を実行出来れば良いです

https://github.com/tinygo-org/tinygo/releases/download/v0.18.0/tinygo0.18.0.windows-amd64.zip

その後 PATH を通します。

```
$ set PATH=%PATH%;C:\tinygo\bin
```

以下で version が表示されたらインストール成功です。

```
$ tinygo version
tinygo version 0.18.0 windows/amd64 (using go version go1.16 and LLVM version 11.0.0)
```

## Hello TinyGo

Hello World に相当するプログラムとして、 L チカ (LED を光らせる) を実施してみます。
パソコンと Wio Terminal を USB ケーブルで接続して、以下を実行します。

```
$ tinygo flash --target wioterminal --size short examples/blinky1
   code    data     bss |   flash     ram
   7720      36    6340 |    7756    6376
```

分かりにくいですが、以下の青 LED が 0.5 秒毎に ON / OFF を繰り返すようになれば成功です。
※`error: multiple serial ports available - use -port flag, available ports are COM6, COM12` の様に表示された場合は  [#port-を指定して書き込む](#port-を指定して書き込む) を見てください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/c41fd457-0593-1a3d-e240-a7ff469ee95a.png)

次に点滅周期を変更してみます。
上記は TinyGo をインストールしたディレクトリのソースを直接書き込んでいたので変更ができません。
※正確には `C:\tinygo\src\examples\blinky1` にあるので変更できますが、しないほうが良いです

以下からソースコードを取得して適当な場所に保存します。
https://github.com/tinygo-org/tinygo/blob/release/src/examples/blinky1/blinky1.go

```go
package main

// This is the most minimal blinky example and should run almost everywhere.

import (
	"machine"
	"time"
)

func main() {
	led := machine.LED
	led.Configure(machine.PinConfig{Mode: machine.PinOutput})
	for {
		led.Low()
		time.Sleep(time.Millisecond * 500)

		led.High()
		time.Sleep(time.Millisecond * 500)
	}
}
```

500 ms 待つところを 1000 ms 等に書き換えてみて、ビルドおよび書き換えができていることを確認してください。
`tinygo flash` は、おおよそ `go build` や `go get` のイメージで package を指定できます。
以下のように現在のフォルダ／ディレクトリに blinky1.go しかない場合は、 `tinygo flash .` のようにして flash することができます。

```
$ dir /b
blinky1.go

$ tinygo flash --target wioterminal --size short .
   code    data     bss |   flash     ram
   7996       8    6344 |    8004    6352
```

ここまでで、最低限の TinyGo 入門ができました。
以降では、ディスプレイなどを使うサンプルを書いていきます。

### Examples

TinyGo の参考になるソースコードは、以下にあります。
マイコン毎にボタンの有無等色々な条件があるため、そのままでは動かないものもあります。
このページでは、 Wio Terminal で動くように修正したサンプルを徐々に公開していく予定です。

* [tinygo.org/x/tinygo/src/examples/](https://github.com/tinygo-org/tinygo/tree/release/src/examples)
* [tinygo.org/x/drivers/examples/](https://github.com/tinygo-org/drivers/tree/release/examples)
* [tinygo.org/x/tinyfont/examples/](https://github.com/tinygo-org/tinyfont/tree/release/examples)


## Wio Terminal の周辺デバイスを使用する (準備)

Wio Terminal には以下の周辺デバイスがパッケージされています。
先に以下を go get しておいてください。
`tinygo.org/x/drivers` の場所に `github.com/tinygo-org/drivers` というような形で go get されます。

```
$ go get tinygo.org/x/drivers
$ go get tinygo.org/x/tinyfont
$ go get tinygo.org/x/tinydraw
```

周辺デバイスを使うためにはピンなどの設定名を知る必要があります。
Arduino などとほぼ同じ名前となっていますが、詳細は以下のあたりに記載されています。

* https://github.com/tinygo-org/tinygo/blob/release/src/machine/board_wioterminal.go
* https://github.com/tinygo-org/tinygo/blob/release/src/machine/board_wioterminal_baremetal.go

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/49bcc304-0caf-2f5a-6b05-cdc5bbff50ad.png)

※画像は [オフィシャルページ](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) にあるもの


## Wio Terminal の周辺デバイスを使用する

以下にてとりあえず使い始めることができます。
Wio Terminal で動かすためには一部変更が必要なものがあります。
URL が `github.com/sago35/tinygo-examples/wioterminal` になっている分は、 wioterminal で直接動くようにソース修正済みです。
適宜参照してください。

* 4MB External Flash
    * [tinygo.org/x/drivers/flash](https://github.com/tinygo-org/drivers/tree/release/flash)
    * [tinygo.org/x/drivers/examples/flash/console/qspi](https://github.com/tinygo-org/drivers/tree/release/examples/flash/console/qspi)
    * https://github.com/sago35/tinygo-examples/tree/master/wioterminal/qspi_flash
* RTL8720DN : WiFi / BLE
    * tinygo-org/drivers 0.17.1 で対応、 webclient と tlsclient が動作します
    * https://github.com/tinygo-org/drivers/tree/release/examples/rtl8720dn/webclient
    * https://github.com/tinygo-org/drivers/tree/release/examples/rtl8720dn/tlsclient
    * https://github.com/tinygo-org/drivers/tree/release/examples/rtl8720dn/webclient-tinyterm
* USB OTG
    * tinygo 0.23 時点では未対応
* USB Device
    * HID : Keyboard
        * https://github.com/tinygo-org/tinygo/tree/release/src/examples/hid-keyboard
    * HID : Mouse
        * https://github.com/tinygo-org/tinygo/tree/release/src/examples/hid-mouse
    * MIDI
        * https://github.com/tinygo-org/tinygo/tree/release/src/examples/usb-midi
* ILI9341 : 320 x 240 LCD
    * 以下の examples は wioterminal でそのまま動作します
    * [tinygo.org/x/drivers/ili9341](https://github.com/tinygo-org/drivers/tree/release/ili9341)
    * [tinygo.org/x/drivers/examples/ili9341/basic](https://github.com/tinygo-org/drivers/tree/release/examples/ili9341/basic)
    * [tinygo.org/x/drivers/examples/ili9341/pyportal_boing](https://github.com/tinygo-org/drivers/tree/release/examples/ili9341/pyportal_boing)
    * [tinygo.org/x/drivers/examples/ili9341/scroll](https://github.com/tinygo-org/drivers/tree/release/examples/ili9341/scroll)
* LIS3DH : 加速度センサ
    * I2C1 / lis3dh.Address0
        * TinyGo 0.24 以降では Arduino と同じ値である I2C0 / lis3dh.Address0 に変更となります
    * [tinygo.org/x/drivers/lis3dh](https://github.com/tinygo-org/drivers/tree/release/lis3dh)
    * [tinygo.org/x/drivers/examples/lis3dh](https://github.com/tinygo-org/drivers/tree/release/examples/lis3dh)
    * https://github.com/sago35/tinygo-examples/tree/master/wioterminal/lis3dh
* Microphone
    * 以下の名前のピンを AD 入力ピンとして設定する
        * WIO_MIC   = PC30
    * [tinygo.org/x/tinygo/src/examples/adc](https://github.com/tinygo-org/tinygo/tree/release/src/examples/adc)
    * https://github.com/sago35/tinygo-examples/tree/master/wioterminal/microphone
* Speaker
    * buzzer (ソフトウェア PWM 制御)
        * buzzer はソフトウェア PWM 制御のため、綺麗な音はならないことに注意
            * 綺麗な音を鳴らす場合は、後述の tone を使ってください
        * 以下の名前のピンを出力ピンとして設定してから buzzer に渡す
            * WIO_BUZZER = PD11
        * [tinygo.org/x/drivers/buzzer](https://github.com/tinygo-org/drivers/tree/release/buzzer)
        * [tinygo.org/x/drivers/examples/buzzer](https://github.com/tinygo-org/drivers/tree/release/examples/buzzer)
        * https://github.com/sago35/tinygo-examples/blob/089f88fc3ecb67854df8e248966d444ac33b18bb/wioterminal/buzzer/main.go
    * tone (ハードウェア PWM 制御)
        * 上記 buzzer に比べて綺麗な音を鳴らすことができます
        * [tinygo.org/x/drivers/tone](https://github.com/tinygo-org/drivers/tree/release/tone)
        * [tinygo.org/x/drivers/examples/tone](https://github.com/tinygo-org/drivers/tree/release/examples/tone)
        * https://github.com/sago35/tinygo-examples/tree/master/wioterminal/buzzer
* microSD Card
    * tinygo-org/drivers 0.17.1 で対応、物理セクタ番号でのアクセス、および FAT32 読み書きに対応
    * https://github.com/tinygo-org/drivers/tree/release/examples/sdcard/console
    * https://github.com/tinygo-org/drivers/tree/release/examples/sdcard/tinyfs
* Light Sensor
    * 以下の名前のピンを AD 入力ピンとして設定する
        * WIO_LIGHT = PD01
    * [tinygo.org/x/tinygo/src/examples/adc](https://github.com/tinygo-org/tinygo/tree/release/src/examples/adc)
    * https://github.com/sago35/tinygo-examples/tree/master/wioterminal/light_sensor
* 5-Way Switch and 3 x buttons
    * 以下の名前のピンを入力として設定する
        * WIO_5S_UP    = PD20
        * WIO_5S_LEFT  = PD12
        * WIO_5S_RIGHT = PD09
        * WIO_5S_DOWN  = PD08
        * WIO_5S_PRESS = PD10
        * WIO_KEY_A = PC26
        * WIO_KEY_B = PC27
        * WIO_KEY_C = PC28
    * [tinygo.org/x/tinygo/src/examples/button](https://github.com/tinygo-org/tinygo/tree/release/src/examples/button)
    * https://github.com/sago35/tinygo-examples/tree/master/wioterminal/buttons
* LED
    * 以下の examples は wioterminal でそのまま動作します
    * [tinygo.org/x/tinygo/src/examples/blinky1](https://github.com/tinygo-org/tinygo/tree/release/src/examples/blinky1)
* Infrared Emmitter (IR 940nm)
    * 以下の名前のピンを出力として設定する
        * WIO_IR = PB31
    * [tinygo.org/x/tinygo/src/examples/blinky1](https://github.com/tinygo-org/tinygo/tree/release/src/examples/blinky1)
    * https://github.com/sago35/tinygo-examples/tree/master/wioterminal/ir

## Examples

### wioterminal/sample

<blockquote class="twitter-tweet"><p lang="en" dir="ltr"><a href="https://twitter.com/hashtag/TinyGo?src=hash&amp;ref_src=twsrc%5Etfw">#TinyGo</a> 0.14 supports <a href="https://twitter.com/hashtag/WioTerminal?src=hash&amp;ref_src=twsrc%5Etfw">#WioTerminal</a>, so I created an example. This is an exanple of how to use many buttons and sensors.<a href="https://t.co/XsypuI0yan">https://t.co/XsypuI0yan</a> <a href="https://t.co/Nx4liThbW4">pic.twitter.com/Nx4liThbW4</a></p>&mdash; takasago (WFH) (@sago35tk) <a href="https://twitter.com/sago35tk/status/1291535390701051904?ref_src=twsrc%5Etfw">August 7, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

ボタン類と LED と LIS3DH と MIC と BUZZER と ILI9341 を使った簡単な Demo を作りました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/8d386553-b2a5-b279-504f-0a7fe0709f95.png)

* ① は上部のボタン A ～ C に対応して、押下で赤く光ります
* ② は十字キーに対応して赤く光ります
    * 十字キー押下で赤く光りつつ音を鳴らします
* ③ は LIS3DH でとった X および Y 軸の傾きを赤で表示します
    * 上図のようになっていると手前に大きく、左に少し傾いていることを表します
* WIO_LIGHT (背面) から読み取った AD 値を表示
* WIO_MIC (左下付近) から読み取った AD 値を表示
* LIS3DH から読み取った X / Y / Z の値を表示

ソースコードは以下です。
uf2 ファイルも置いているので、 TinyGo の環境が無くても試せます。

* https://github.com/sago35/tinygo-examples/tree/master/wioterminal/sample

build 方法は以下の通りです。

```
$ git clone https://github.com/sago35/tinygo-examples
$ cd tinygo-examples
$ tinygo build -o app.uf2 -target wioterminal -size short ./wioterminal/sample
```

## 困ったときは

### port を指定して書き込む

`tinygo flash` 実行して `error: multiple serial ports available - use -port flag` というエラーが表示される場合は、 `-port` オプションを追加する必要があります。
複数のシリアルデバイスの中から tinygo に適切なポートを教えてあげる必要があります。
以下の例の場合は `--port COM4` を指定しています。

```
$ tinygo flash --target wioterminal --size short --port COM4 github.com/tinygo-org/tinygo/src/examples/blinky1
   code    data     bss |   flash     ram
   7516       8    6344 |    7524    6352
```

`COM4` 等のシリアルポート名を調べるには `デバイス マネージャー` の `ポート (COM と LPT)` から確認できます。
以下の画像のように複数の選択肢がある部分は、書き込みたい WioTerminal を接続したり外したりしてあたりをつけて `tinygo flash` してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/3771d415-3e06-ddcc-b748-c42952fd6da2.png)

### COM ポートが見つからない場合

COM ポートが見つからない場合は bootloader モードにする必要があるかもしれません。
例えば、実行直後に crash してしまうプログラムを書き込んでしまった場合などは上記の方法では `tinygo flash` できません。
この場合は、 bootloader モードにすることで復帰できます。
電源ボタンと一体型になっているリセットスイッチを使って、素早く 2 回リセットすることで bootloader に入れます。
※割とシビア (初回リセットから 0.5 秒以内に次のリセットが必要) なので注意

* https://wiki.seeedstudio.com/Wio-Terminal-Getting-Started/#faq
* https://qiita.com/carcon999/items/ec8045adc1309b2e5361

### LSP / gopls が使えない

* [TinyGo + `VSCode or Vim (もしくはそれ以外の LSP 対応エディタ)` で gopls 連携する方法](https://qiita.com/sago35/items/c30cbce4a0a3e12d899c)

## リンク

* [PyPortal で TinyGo プログラミングを始めよう](https://qiita.com/sago35/items/d95981f68231d69bce30)
* YouTube
    * [TinyGo で組み込み開発を始めよう!! (0.14 ver)](https://www.youtube.com/watch?v=hZJVa-7LL9I)
        * Wio Terminal や XIAO 、 Debugger を使ったデバッグ等を紹介しています
    * [WioTerminal を TinyGo で遊ぼう](https://www.youtube.com/watch?v=dbIhStkPFrE)
        * このページに対応した発表動画です
    * [TinyGo ハンズオン - Go で L チカから応用まで](https://www.youtube.com/watch?v=6veEA0fsYuI)
        * Wio Terminal を使ったハンズオンの様子です (2021/11/13)

<iframe width="560" height="315" src="https://www.youtube.com/embed/hZJVa-7LL9I" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<iframe width="560" height="315" src="https://www.youtube.com/embed/dbIhStkPFrE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<iframe width="560" height="315" src="https://www.youtube.com/embed/6veEA0fsYuI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>