GoにいればGoに従え(2) 再びmicro:bit v1.5のLED配列に謀られる

Joseph Halfmoon

昨晩、アイキャッチ画像の御本「基礎から学ぶ TinyGoの組込み開発」を購入させていただきました(AmazonのKindle形式電子書籍版ですけど。)これを読めば立派にTinyGo書ける人になること必定?しかし、すみません、まだ読んでません。今回はダメダメなまま前回心に引っかかっていた問題に再突入。

※「GoにいればGoに従え」Go関連記事の総Index

前回心に引っかかっていた問題

前回吉例LチカをBBC micro:bit 上でやってみました。TinyGoから呼び出せる micro:bit用のmachineパッケージには、LED_ROW群3本とLED_COL群9本というボード上の5x5のLEDマトリックスを駆動するための端子が定義されてます。ROW群の最小番号の1番とCOL群の最小番号の1番を組み合わせたら、当然のように5x5の左上のLEDが点灯しました。

BBC micro:bit でもv2になると、ROW5本、COL5本で綺麗に5×5マトリックスを構成してますが、v1系の配列は非対称であることは知ってます。回路図が以下に。

https://github.com/bbcmicrobit/hardware/blob/master/V1.5/SCH_BBC-Microbit_V1.5.PDF

以前 Arduino環境で BBC micro:bit したときにはピン番号の読み方でハマりました(そのときの記事がこちら。)その時と違い上記の回路図相当のROW、COL信号で駆動しているのだもの間違いないハズ。しかし、まだありましたな。

回路図上でのLEDの順番と実際の5x5マトリックス上での順番は関係なかったという件に愕然。左上から順番と思い込んでプログラム書いたらサッパリでした。

ROW、COLとLEDの物理配置

結局、LEDの物理配置を探るためのプログラムを書く羽目になり、調査した結果が以下です。Cxがmachine.LED_COL_xに対応し、Rxがmachine.LED_COL_yに対応してます。以下の5x5の配列は、USBソケットの方向を上、カードエッジを下とした場合の物理配置です。

C1-R1 C4-R2 C2-R1 C5-R2 C3-R1
C4-R3 C5-R3 C6-R3 C7-R3 C8-R3
C2-R2 C9-R1 C3-R2 C9-R3 C1-R2
C8-R1 C7-R1 C6-R1 C5-R1 C4-R1
C3-R3 C7-R2 C1-R3 C6-R2 C2-R3

なんじゃらほいの、COL、ROWバラバラ、あちゃこっちゃに飛んでるのでありました。いやな予感がしたのは、以前遭遇していたのに老人の忘却力で忘れかけていたからか?

今回作成のTinyGoプログラム

ともあれCOL、ROWの組み合わせが判明したので、任意の複数のLEDをパターン点灯させるための関数を自前で書いてみました。多分TinyGoの既存のモジュールの中には同様なことができるモジュールありそうですが、今回は自前主義(まだモジュール化もしておらず。)

uint32型の整数値を1個渡すだけで、いかなるLED点灯パターンにでもなる

関数であります。整数型へのエンコードは、

    • 点灯を1、消灯を0とする
    • 5x5マトリックスの左上をビット0,右下をビット24としてビット列を作成し、uint32型整数に格納する

という方式。整数値を1個渡すだけで〇でも×でもハート型でもお好みのパターンが表示できると。

ともあれ、今回はテストなので「左上から右下に向かって1秒ごとに1ビットが動いていくようなパターン」で動作させてみました。ダラダラなソースコードが以下に。

package main

import (
    "fmt"
    "machine"
    "time"
)

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_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_COL_6.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_COL_7.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_COL_8.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_COL_9.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_ROW_1.Low()
    machine.LED_ROW_2.Low()
    machine.LED_ROW_3.Low()
}

func dispLED(arg uint32) {
    machine.LED_ROW_1.Low()
    machine.LED_ROW_2.Low()
    machine.LED_ROW_3.Low()
    if (arg & 0x0404001) != 0 {
        machine.LED_COL_1.Low()
    } else {
        machine.LED_COL_1.High()
    }
    if (arg & 0x1000404) != 0 {
        machine.LED_COL_2.Low()
    } else {
        machine.LED_COL_2.High()
    }
    if (arg & 0x0101010) != 0 {
        machine.LED_COL_3.Low()
    } else {
        machine.LED_COL_3.High()
    }
    if (arg & 0x0080022) != 0 {
        machine.LED_COL_4.Low()
    } else {
        machine.LED_COL_4.High()
    }
    if (arg & 0x0040048) != 0 {
        machine.LED_COL_5.Low()
    } else {
        machine.LED_COL_5.High()
    }
    if (arg & 0x0820080) != 0 {
        machine.LED_COL_6.Low()
    } else {
        machine.LED_COL_6.High()
    }
    if (arg & 0x0210100) != 0 {
        machine.LED_COL_7.Low()
    } else {
        machine.LED_COL_7.High()
    }
    if (arg & 0x0008200) != 0 {
        machine.LED_COL_8.Low()
    } else {
        machine.LED_COL_8.High()
    }
    if (arg & 0x0002800) != 0 {
        machine.LED_COL_9.Low()
    } else {
        machine.LED_COL_9.High()
    }
    if (arg & 0x00F8815) != 0 {
        machine.LED_ROW_1.High()
    }
    if (arg & 0x0A0540A) != 0 {
        machine.LED_ROW_2.High()
    }
    if (arg & 0x15023E0) != 0 {
        machine.LED_ROW_3.High()
    }
}

func main() {
    initLED()
    var idx = 0
    var dpx = 0x1
    for {
        fmt.Println(idx)
        dispLED(uint32(dpx))
        dpx = dpx << 1
        time.Sleep(time.Millisecond * 1000)
        idx++
        if idx > 24 {
            idx = 0
            dpx = 0x1
        }
    }
}

いやあ、たった25個とは言え、物理配置のデバッグは辛かったっす。どこかにボードレイアウトと信号の対応書いてある資料があるのではないか?ないハズはないだろうに。

GoにいればGoに従え(1) TinyGoの復活というか再インストール へ戻る

GoにいればGoに従え(3) micro:bitのLED、ダイナミック駆動じゃね へ進む