前回 micro:bit v2であればTinyGoからもADCが使用できることを確認。前々回まで v1.5で実験していたのですが器材を変更。しかし困った問題が。micro:bitのボード表面の5×5のLEDアレイ、見た目は同じ、でもv1.5とv2では結線が違います。折角作ったv1.5用のインタフェース関数は要作り直し。
※「GoにいればGoに従え」Go関連記事の総Index
v1.5とv2の記述が混ざっているTinyGoのドキュメント
TinyGoで各種マイコンのハードウエアを操作しようとするときに頼りになるのが、Machine packageについて記述したドキュメントです。BBC micro:bit に関しては以下のページです。
Documentation>>Reference>>Microcontrollers>>Machine package>>microbit
前回も書きましたが、BBC micro:bit の v1.x 系ボードと v2.x系ボードの見た目はよく似ていますが、搭載しているMCUが異なる上に、ボード上の回路も異なります。Machine packegeの記述は、v1.x系ボード用と v2.x系ボード用で2種類にわけた方がいいと思うのですが(個人の感想です)、現状は上記のページ一つしかありません(2023年3月23日現在。)
前々回から今回まで調べたことをまとめると以下のようになります。
-
- v2.0ボード(MCUはnRF52系)であれば上記ドキュメントのADCに関する記述通りでAD変換可能。一方nRF51系用のmachine packageのソースにはADCに関する記述が見つからない。TinyGoからターゲットをv1.x系のmicrobitにしてmachineパッケージのADCのAPIを呼び出そうとするとエラーになる。
- ボード表面の5x5のLEDアレイに関する端子の定義は、上記ドキュメントにはv1.x系ボードの端子配線向けの定義が記載されている。v2.x系ボードでは配線異なるのでそのままでは使えない。
今回は、2についての対処について書き留めときます。幸いなことに、Tinygoのmachineパッケージ・フォルダ内の以下のソース中にはv2.xボード用のLED端子の定義が記載されています。
board_microbit-v2.go
v1.x系と「似た」以下の端子名で定義されてますが、そもそも実体LEDとCOL/ROWの対応関係が、v1.xとv2.xで異なっているので、v1.x系用に作ったIF関数などはそのままでは動きませぬ。
-
- LED_COL_1 ~ LED_COL_5
- LED_ROW_1 ~ LED_ROW_5
過去回で作成したv1.x用の駆動ルーチンをv2.0に移植
以下の過去回で作成した、5x5アレイに任意のパターンを表示できる、ダイナミック駆動かつGoルーチン化によりメインと並行動作するLED駆動ルーチンを移植してみました。
GoにいればGoに従え(4) micro:bitのLED、goroutineで動的駆動じゃ
LED駆動部分のソースが以下に。
package main import ( "machine" ) func InitLED() { machine.LED_ROW_1.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.LED_ROW_2.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.LED_ROW_3.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.LED_ROW_4.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.LED_ROW_5.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.LED_COL_1.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.LED_COL_2.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.LED_COL_3.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.LED_COL_4.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.LED_COL_5.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.LED_ROW_1.Low() machine.LED_ROW_2.Low() machine.LED_ROW_3.Low() machine.LED_ROW_4.Low() machine.LED_ROW_5.Low() } func SetLED(arg uint32) { if (arg & 0x01084210) != 0 { machine.LED_COL_1.Low() } else { machine.LED_COL_1.High() } if (arg & 0x00842108) != 0 { machine.LED_COL_2.Low() } else { machine.LED_COL_2.High() } if (arg & 0x00421084) != 0 { machine.LED_COL_3.Low() } else { machine.LED_COL_3.High() } if (arg & 0x00210842) != 0 { machine.LED_COL_4.Low() } else { machine.LED_COL_4.High() } if (arg & 0x00108421) != 0 { machine.LED_COL_5.Low() } else { machine.LED_COL_5.High() } } func DispLED1(arg uint32) { machine.LED_ROW_1.Low() machine.LED_ROW_2.Low() machine.LED_ROW_3.Low() machine.LED_ROW_4.Low() machine.LED_ROW_5.Low() if (arg & 0x01F00000) != 0 { SetLED(arg & 0x01F00000) machine.LED_ROW_1.High() } } func DispLED2(arg uint32) { machine.LED_ROW_1.Low() machine.LED_ROW_2.Low() machine.LED_ROW_3.Low() machine.LED_ROW_4.Low() machine.LED_ROW_5.Low() if (arg & 0x000F8000) != 0 { SetLED(arg & 0x000F8000) machine.LED_ROW_2.High() } } func DispLED3(arg uint32) { machine.LED_ROW_1.Low() machine.LED_ROW_2.Low() machine.LED_ROW_3.Low() machine.LED_ROW_4.Low() machine.LED_ROW_5.Low() if (arg & 0x00007C00) != 0 { SetLED(arg & 0x00007C00) machine.LED_ROW_3.High() } } func DispLED4(arg uint32) { machine.LED_ROW_1.Low() machine.LED_ROW_2.Low() machine.LED_ROW_3.Low() machine.LED_ROW_4.Low() machine.LED_ROW_5.Low() if (arg & 0x000003E0) != 0 { SetLED(arg & 0x000003E0) machine.LED_ROW_4.High() } } func DispLED5(arg uint32) { machine.LED_ROW_1.Low() machine.LED_ROW_2.Low() machine.LED_ROW_3.Low() machine.LED_ROW_4.Low() machine.LED_ROW_5.Low() if (arg & 0x0000001F) != 0 { SetLED(arg & 0x0000001F) machine.LED_ROW_5.High() } }
一方、上記に表示をお願いするmain関数のサンプルが以下に。go func()部分も別ファイルに追い出した方がカッコ良いのですが、今回は表示だけなので、その動作が分かりやすい方向ということで。
package main import ( "time" ) func main() { InitLED() var dispPattern [4]uint32 dispPattern[0] = 0x01000000 dispPattern[1] = 0x01151151 dispPattern[2] = 0x00E8C62E dispPattern[3] = 0x01FFFFFF var pat = 0 var row = 1 go func() { for { switch row { case 1: DispLED1(dispPattern[pat]) case 2: DispLED2(dispPattern[pat]) case 3: DispLED3(dispPattern[pat]) case 4: DispLED4(dispPattern[pat]) case 5: DispLED5(dispPattern[pat]) } row++ if row > 5 { row = 1 } time.Sleep(time.Millisecond * 7) } }() for { pat++ if pat > 3 { pat = 0 } time.Sleep(time.Second * 5) } }
ビルドして実行
上記2つのソースファイルが含まれるGo プロジェクトのフォルダ内で、以下のコマンドラインを実行すれば、ソースがビルドされ、オブジェクトが microbit v2機のFlashに書き込まれます。
$ tinygo flash -target microbit-v2
メンドかったけれども、v2対応版も作れた。