GoにいればGoに従え(18) TinyGo、加速度センサ読み取り。micro:bit v2

Joseph Halfmoon

前回は、BBC micro:bit v2 搭載のSTmicroelectronics社製LSM303AGRのうち磁気センサ(電子コンパス)の読み取りを確認。今回は加速度センサについて読み取りを実行です。読み取りそのものは難しくないけれども、いろいろ出来るので設定すべきレジスタが多いです。最初に一度やるだけだけれども。

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

前回は LSM303AGRのデータシートにあわせ、ST社の下記のアプリケーションノートを参照させていただきながらプログラムを作成いたしました。書いてある通りにプログラムを書けば動くと。お楽。

AN4825

LSM303AGRの制御用のTinyGoソース

前回、mb20lsm303.goというファイル名で全文かかげたファイルに追加した部分を以下に掲げました。

まず const定義が大量に。先頭の const OUTZ_H_REG_Mは磁気センサの定義の末尾で、それ以降が追加した加速度センサのレジスタです。以下はアプリケーションノートを見て、最低限必要なレジスタのみ列挙しているのですが、それでもレジスタ数が多いです。

途中略以降が、追加した2関数です。InitAccNormal1Hz()は、加速度センサ部分を初期化する関数で、最初に1度呼び出す必要があります。初期化成功すれば真を返します。なお、設定はNormalモード(10bit レゾリューション)で、±2Gがフルスケール、一番遅いデータレート1Hz、3軸動作です。フィルタ、FIFO、割り込み等まったく使わずポーリング用の設定です(ほぼほぼデフォルト設定。)

ReadACCData()は、加速度センサの読み取り結果を返してきます。戻り値は4要素で最初に読み取りの成功、不成功を真偽値で、つづいて読み取った値を16ビットの整数3個で返してきます。X、Y、Zの順番です。

上記の初期化関数で±2Gをフルスケールとしているので、16ビット整数の-32768が-2G、+32767が+2Gにマップされるのだと思います。細かい誤差とか知らんけど。

//~冒頭略
const OUTZ_H_REG_M = 0x6D
const CTRL_REG1_A = 0x20
const CTRL_REG2_A = 0x21
const CTRL_REG3_A = 0x22
const CTRL_REG4_A = 0x23
const CTRL_REG5_A = 0x24
const CTRL_REG6_A = 0x25
const REF_DATAC_A = 0x26
const STATUS_REG_A = 0x27
const OUTX_L_REG_A = 0x28
const OUTX_H_REG_A = 0x29
const OUTY_L_REG_A = 0x2A
const OUTY_H_REG_A = 0x2B
const OUTZ_L_REG_A = 0x2C
const OUTZ_H_REG_A = 0x2D
const INT1_THS_A = 0x32
const INT1_DUR_A = 0x33
const INT1_CFG_A = 0x34
// 途中略
func InitAccNormal1Hz() bool {
    ok := write1Byte(LSM303AGR_ACC, CTRL_REG1_A, 0x17) //ODR=1Hz, Normal, All axis enabled
    if !ok {
        return false
    }
    ok = write1Byte(LSM303AGR_ACC, CTRL_REG2_A, 0x00) //HPF=Normal, bypass
    if !ok {
        return false
    }
    ok = write1Byte(LSM303AGR_ACC, CTRL_REG3_A, 0x00) //all interrupts are disabled.
    if !ok {
        return false
    }
    ok = write1Byte(LSM303AGR_ACC, CTRL_REG4_A, 0x00) //continuous, little endian, +-2g, Normal mode.
    if !ok {
        return false
    }
    ok = write1Byte(LSM303AGR_ACC, CTRL_REG5_A, 0x00) //Normal mode, FIFO disabled
    if !ok {
        return false
    }
    ok = write1Byte(LSM303AGR_ACC, CTRL_REG6_A, 0x00) //INT2 disabled
    if !ok {
        return false
    }
    ok = write1Byte(LSM303AGR_ACC, REF_DATAC_A, 0x00) //REFERENCE/DATACAPTURE_A = 0x00
    if !ok {
        return false
    }
    ok = write1Byte(LSM303AGR_ACC, INT1_THS_A, 0x00) //INT1 Threshold is 0x00
    if !ok {
        return false
    }
    ok = write1Byte(LSM303AGR_ACC, INT1_DUR_A, 0x00) //INT1 DURATION is 0x00
    if !ok {
        return false
    }
    ok = write1Byte(LSM303AGR_ACC, INT1_CFG_A, 0x00) //INT1 All functions are disabled
    if !ok {
        return false
    }
    // After interrupt setting
    //	ok = write1Byte(LSM303AGR_ACC, CTRL_REG5_A, 0x00) //Normal mode, FIFO disabled
    //	if !ok {
    //		return false
    //	}
    return true
}

func ReadACCData() (bool, int16, int16, int16) {
    ok, reg := read1Byte(LSM303AGR_ACC, STATUS_REG_A)
    if !ok {
        fmt.Printf("ERROR ACC 0\r\n")
        return false, 0, 0, 0
    }
    cnt := 3
    if (reg & 0x08) == 0 { //Check ZYXDA only, Ignore Overrun
        for cnt > 0 {
            ok, reg = read1Byte(LSM303AGR_ACC, STATUS_REG_A)
            if ok && ((reg & 0x80) != 0) {
                break
            }
            cnt--
        }
    }
    if cnt <= 0 {
        fmt.Printf("ERROR ACC 2\r\n")
        return false, 0, 0, 0
    }
    ok, regXH := read1Byte(LSM303AGR_ACC, OUTX_H_REG_A)
    ok, regXL := read1Byte(LSM303AGR_ACC, OUTX_L_REG_A)
    ok, regYH := read1Byte(LSM303AGR_ACC, OUTY_H_REG_A)
    ok, regYL := read1Byte(LSM303AGR_ACC, OUTY_L_REG_A)
    ok, regZH := read1Byte(LSM303AGR_ACC, OUTZ_H_REG_A)
    ok, regZL := read1Byte(LSM303AGR_ACC, OUTZ_L_REG_A)
    datX := int16(uint16(regXH)<<8 + uint16(regXL))
    datY := int16(uint16(regYH)<<8 + uint16(regYL))
    datZ := int16(uint16(regZH)<<8 + uint16(regZL))
    return true, datX, datY, datZ
}
main.goの差分

上記の mb20lsm303.go のお隣に置いてある main.go の追加差分が以下です。初期化関数 InitAccNormal1Hz()を呼び出したあと、ループの中でReadACCData()しています。

//冒頭略
    opt := false
    time.Sleep(time.Millisecond * 100)
    InitAccNormal1Hz()
//途中略
        success, jX, jY, jZ := ReadACCData()
        if success {
            fmt.Printf("Acc Data: %d %d %d\r\n", jX, jY, jZ)
        } else {
            fmt.Printf("ERROR: reading Acc Data\r\n")
        }
        time.Sleep(time.Second * 2)
    }
}
実機実行結果

micro:bit V2機をUSB接続後、以下でビルド&フラッシュ書き込み(書き込み後、即実行)です。通常、tinygoの接続先は自動で検出されます。

$ tinygo flash -target=microbit-v2

USBシリアルに接続したTeratermProで得た出力を以下に掲げます。前回までの出力が残っているので、今回追加した加速度センサの結果のところに線を引きました。

なお、micro:bit V2の場合、ボードのLED面(表面)を上向きに置くとZ軸が上を向く方角のようです。地球重力を観察した場合、下向きの力なのでマイナスの値が読める筈。なお、+32767が+2Gなので地球重力+1Gは16384くらいの値になると予想。ただし、初期設定で10bit Normalモードを指定しているので、下6ビットには値が入らず(つまり64の倍数値しかとれない)のハズ。

ACCresult

まあ、こんなもんかい。micro:bitは部品がデコボコしているので、微妙に傾いてるし。

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

GoにいればGoに従え(19) TinyGo、スピーカを鳴らす、micro:bit v2 へ進む