GoにいればGoに従え(20) TinyGo、MICの値を読み取る、micro:bit v2

Joseph Halfmoon

前回はBBC micro:bit v2搭載のスピーカ(というよりブザーですが)を鳴らしてみました。今回はオンボード搭載のマイクロフォンの瞬時値を読み取ってみます。音声波形として読むためには正確なサンプリング周期で連続読み取りが必要ですが、今回のはある瞬間の1点の出力を読んでいるだけ。音声には程遠いです。

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

micro:bit v2のオンボードMIC

BBC micro:bit v2には、オンボードにMEMSマイクロフォンが搭載されています。micro:bit v2の回路図をみると以下が分かります。

    1. nRF52833の端子P0.20が RUN_MIC信号となっている。これがマイク電源であり、かつマイクに電源が入っていることを知らせるためのマイク横のLEDを点灯させる。
    2. MICの出力は、1μFのコンデンサを介してMIC_IN信号に接続している。MIC_IN信号は抵抗で無負荷100mVくらいの電圧になるようにバイアスされている。
    3. MIC_IN信号は、nRF52833の端子P0.05/AIN3 に接続しているのでここに現れる電圧をADCで読み取れる

さて、いつもお世話になっておりますTinyGoの以下のページには、例によってマイクロフォン関係の記述がありませぬ。

machine > microbit

これは「例によって」上記ページが micro:bit v1 の端子ベースで書かれているため(v1にはMEMSマイクの搭載なし)と想像されます(そのくせv2の記述も一部混じっていて混乱気味。)

しかし、TinyGoのインストールディレクトリの奥に隠れている以下のファイルを参照すれば、ちゃんと端子名が割り当てられており、TinyGoからも使用できそうなことが分かります。

board_microbit-v2.go

端子名は以下のようになっています。

    • MIC、MIC_IN信号に接続
    • MIC_LED、RUN_MIC信号に接続

MIC_LEDはMICの横のLEDの点灯だけ?に思えるお名前ですが、これをHighにしないとMICそのものに電源が供給されず、また、MIC出力もバイアスされません。Highにしてからどのくらい待ったら良いの?というのはMEMSマイクのデータシート読まないとダメですが、今回は手抜きで読んでません。どうせ手動(キー)でMIC電源のON/OFFしているので、たっぷり時間がとれとるだろ~ということで。

今回作成の実験用コード

今回作成の実験用コードも通例にもれず2ファイル構成です。プロジェクト・フォルダ内に以下2ファイルが並置されてます。

    1. main.go
    2. mbmic.go

VScodeでmbmic.goの編集しているところが以下に。

goMIC_EC4

まず、マイクの制御用のメソッドをまとめた mbmic.go ファイルが以下に。

// micro-bit v2 only
package main

import (
    "machine"
)

var mic machine.ADC

func InitADCforMIC() {
    machine.InitADC()
    mic = machine.ADC{Pin: machine.MIC}
    mic.Configure(machine.ADCConfig{})
    machine.MIC_LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
}

func ReadMIC() uint16 {
    micLEV := mic.Get()
    return (micLEV >> 4)
}

func EnableMIC() {
    machine.MIC_LED.High()
}

func DisalbeMIC() {
    machine.MIC_LED.Low()
}

つづいて上記のmbmic.go内のメソッドを呼んでマイクの値を読み取る main.go が以下に。なお、MICのON/OFFは、micro:bit表面のAボタンを押すとON、Bボタンを押すとOFFということにしてあります。

package main

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

var pat = 0

func main() {
    var micL uint16

    InitADCforMIC()
    DisalbeMIC()

    keyA := machine.BUTTONA
    keyB := machine.BUTTONB
    keyA.Configure(machine.PinConfig{Mode: machine.PinInput})
    keyB.Configure(machine.PinConfig{Mode: machine.PinInput})
    keyA.SetInterrupt(machine.PinFalling, func(machine.Pin) {
        pat = 1
    })
    keyB.SetInterrupt(machine.PinFalling, func(machine.Pin) {
        pat = 0
    })

    for {
        if pat == 1 {
            EnableMIC()
            micL = ReadMIC()
            fmt.Printf("MIC: %d\r\n", micL)
        } else {
            DisalbeMIC()
        }
        time.Sleep(time.Second * 1)
    }
}

結果は標準出力へ文字列で垂れ流しです。毎秒1回しか測定しないので、たまたまの測定タイミングにかかるように「あ~」とか大声張り上げてないとひっかかりませぬ。

実験結果

以下は標準出力にたれ流されてきたMICのレベルです。無音時90くらいの値が観測される感じです。音が入力されると以下のように大きな値が読めることも、Results

逆に40とか50とか小さな値が読めることもあります。振動波形なのでたまたま無音時と同じような数値が読めるかもです。「うるさい」とか「静か」とかを判定するには適当なサンプル数でRMS的な値でも計算するのが良いかと思います(やってないけど。)まあ、MICがピクピクしているのは分かるようになったのでいいか。

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

GoにいればGoに従え(21) TinyGo、乱数発生器よみとり、micro:bit v2 へ進む