GoにいればGoに従え(16) TinyGo、6軸センサに誰?と micro:bit v2

Joseph Halfmoon

第13回でmicrobit v2とv1.5のI2Cバスの差について調べました。しかしv2の内部I2Cバスについては触ってません。内部I2Cバスには3軸加速度センサと3軸電子コンパスが接続されてます。手元のmicro:bit v2ではLSM303AGRという1チップで両方できる優れもののデバイスが搭載されています。

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

micro:bit v2 内部I2Cバス

おさらいしておくと、micro:bit v1.5以前にはI2Cバスは一つしかなかったものが、micro:bit v2からは2つになっています。外部デバイス用にカードエッジの端子に接続している方がI2C1。そして内部デバイス用にボード内で閉じているのがI2C0です。以下の micro:bit のドキュメントに解説されてます。

Use of the I2C bus

LSM303AGR

STmicroelectronics製の6軸センサ、LSM303AGRは3軸の加速度センサと3軸の電子コンパスをワンパッケージに封入したデバイスです。冒頭のアイキャッチ画像に赤矢印つけておきましたが、老眼の目にはマーキングが読めない超小型のデバイスです。ST社の製品ページが以下に。

LSM303AGR

micro:bit はモーションセンサを搭載するという仕様は一貫しているみたいですが、搭載デバイスはバージョンにより異なるようです。手元のmicro:bit についてはv1.5でもv2でも同じ LSM303AGR を搭載してました。

お陰で過去回でv1.5の内外共用のI2CバスでLSM303AGRへアクセスしている例が参考にできました。その時の記事が以下に。ただし言語はMicroPythonですが。

MicroPython的午睡(5) LSM303AGRへアクセス、micro:bit

LSM303AGRの場合、パッケージは1個ですがI2Cのアドレスは2個割り当てられてます。バス的にはデバイスは2個ね。以降、加速度センサ側をACC、電子コンパス側をMAGと略記します。I2Cアドレス(7ビット)は以下のとおり。

    • ACC 0x19
    • MAG 0x1E

上記のI2Cアドレスにアクセスし、ちゃんと通信できていることを確かめたいです。勿論、副作用なく。そのときに使えるのがWHOAMIというレジスタです。そこを読むとデータシートに記載のデバイス固有の数字が読み出せます。このレジスタもACC側とMAG側にそれぞれあります。WHOAMIのレジスタアドレスが以下に。

    • WHOAMI ACC REG ADR= 0x0F
    • WHOAMI MAG REG ADR= 0x4F

そして上記レジスタを読み出すと以下の値が読み出せる筈

    • WHOAMI ACC REG VALUE= 0x33
    • WHOAMI MAG REG VALUE= 0x40

デバイスに向かってあなたは誰?と誰何するっと。上記の合言葉が返ってくればよし、返ってこなかったらどうしよう(まさかそんなことはあるまいが。)

今回実験に使用したGoソース

第13回で使用したソースを流用してます。ただし、内部I2Cバスなので、I2C0を使用し、接続するピンもSCL0_PIN、SCA0_PIN指定です。ボード内部で接続されているのでピンを変更すると動かない筈。

まずは、LSM303AGRへアクセスするためのソースです。今のところWHOAMIレジスタの読み出し機能のみ実装。

package main

import (
    "machine"
    "time"
)

const LSM303AGR_ACC = 0x19
const LSM303AGR_MAG = 0x1E
const WHOAMI_A_ADR = 0x0F
const WHOAMI_M_ADR = 0x4F

var i2c0 = machine.I2C0 // internal I2C bus

func InitInternalI2C() {
    i2c0.Configure(machine.I2CConfig{
        Frequency: machine.TWI_FREQ_100KHZ,
        SCL:       machine.SCL0_PIN,
        SDA:       machine.SDA0_PIN,
    })
    time.Sleep(10 * time.Millisecond)
}

func ReadWhoAmI(opt bool) (bool, byte) {
    var tmpADR byte
    var tmpREG byte
    dat := []byte{0}
    if opt {
        tmpADR = LSM303AGR_ACC
        tmpREG = WHOAMI_A_ADR
    } else {
        tmpADR = LSM303AGR_MAG
        tmpREG = WHOAMI_M_ADR
    }
    err := i2c0.ReadRegister(tmpADR, tmpREG, dat)
    if err != nil {
        return false, 0
    }
    return true, dat[0]
}

上記ソースの隣においてある仮のmain()関数です。LSM303AGRのWHOAMIレジスタを読み出して、標準出力に16進で値を書き出すだけのもの。

package main

import (
    "fmt"
    "time"
)

func main() {
    InitInternalI2C()
    opt := false

    for {
        opt = !opt
        success, dat := ReadWhoAmI(opt)
        if success {
            if opt {
                fmt.Printf("ACC WHO AM I: %02x\r\n", dat)
            } else {
                fmt.Printf("MAG WHO AM I: %02x\r\n", dat)
            }
        } else {
            fmt.Printf("ERROR: ReadWhoAmI\r\n")
        }
        time.Sleep(time.Second * 2)
    }
}
実機動作確認

いつものように以下のようにしてビルド&フラッシュ書き込み(勿論micro:bit v2ボードをUSB接続してあります。)

$ tinygo flash -target=microbit-v2

書き込み完了後、USBシリアルで接続(115200ボー)すれば以下のごとし。

LSM303WHOAMI

出力数字は16進です。予定どおりとな。

GoにいればGoに従え(15) TinyGo、クラスは無いけど。micro:bit v2 へ戻る

GoにいればGoに従え(17) TinyGo、電子コンパス読み取り。micro:bit v2 へ進む