chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

TinyGoのloop速度を確認ー>MEMSマイクからのPDM信号を引っこ抜く

以下のプログラムをビルドしてRP2040(RPi Pico)上で走らせてみた。GP13をL/Hするプログラムなのだが、これを走らせた状態でオシロで波形を観察

package main

import(
	"machine"
)
func main(){
	led := machine.GP13
	led.Configure(machine.PinConfig{Mode: machine.PinOutput})
	for{
		led.High()
		led.Low()
	}
}

この結果、出力される波形は周期38nsで周波数は26.32MHzであった。さすがはコンパイル型言語。高速にループが回っている。これをベースにMEMS MICに2MHzぐらいでCLKを与えて、取りこぼしなくPDM形式のデジタル音声データをマイコンに取り込んでデータ分析したい。
■追記
上記のように、えらく早いと書いたが、どうも上記のプログラムはハングしていて、システムクロックが漏れている波形を取ってしまっているようであった。多分まもとに動いていないと思われる。なぜ素のループにするとハング(らしき状態)に陥るのか不明だが、watch dogか何かで怒られているのだろうか。
■追記
Goはgo routineが基本らしくて、長時間回り続けるプログラムを書いた時に、go routineのディスパッチャというのか、スイッチャというのか、そっちに定期的の戻る様にしないといけないのではないかと推測(あまりそういう情報がないので)
で、以下の様にソースを修正すると動くには動いた。

package main

import(
        "machine"
        "time"
)

func main(){
        led := machine.GP13
        led.Configure(machine.PinConfig{Mode: machine.PinOutput})
        //var val int
        //var count int
        //count = 1

        go func(){
           for {
             led.High()
             led.Low()
             time.Sleep(-1)
           }
        }()
        for {
             println(".")
             time.Sleep(100 * time.Millisecond)
        }
}

go routineで実装しているのでオーバーヘッドがあるのかもしれませんが、上記サンプルの場合、1ループにかかる時間が186ns、周波数で言うと、5.376MHzでした。システムクロックが120MHzだと思うので、結構遅くなっていますね*1・・
なお上記だとクロックが高速すぎて仕様を満たさないので、waitのつもりで、time.Sleep(nn * time.Nanosecond)を加えると、Sleep関数のオーバーヘッドが大きすぎるのか今度は遅くなりすぎる。for文で自作WAITを入れてもどうも思うようには動かない。なぜか分からず。
いろいろ思ったようには動かない局面に出くわしたが、どうにかこうにかMEMS MICのDSMを直接ひっこぬくソフトができた。ソースは以下。8000サンプル分を加工せず1ビットで抜き取るプログラムです。1ビットの情報表すのに配列の1要素につかっている。。強引というかなんというか。。なお、MEMSに与えているCLKは1MHzとはなっておらず、925.9KHz。これ以上のチューニングは困難

package main

import(
	"machine"
	"time"
)

    
var signal[8000] uint8

var led = machine.GP13
var clk = machine.GP15
var dat = machine.GP14

func my_wait()(uint32){

    var count uint32
    count = 0
    for j:=0; j<=0x0D; j++ {   // 2 :1.82MHz  // FF:NG  F: 925KHz
            led.High()
    }
    led.Low()
    return count
}

func capture()(uint32){

    var index uint16
    var count uint32

    index = 0

    for z :=0 ; z < 0xffffff ; z++ {

               clk.High()
               count = my_wait()
               clk.Low()
               count = my_wait()
               time.Sleep(-1)

    } 
    for {
               clk.High()
               count = my_wait()
               if dat.Get() {
                    signal[index] = 1
               }else{
                    signal[index] = 0
               }
               index += 1
               if index == 7999 {
                   //println("fill")
                   break
               }
               clk.Low()
               count = my_wait()

               time.Sleep(-1)
    } 
    return count
 }


func main(){

    led.Configure(machine.PinConfig{Mode: machine.PinOutput})
    clk.Configure(machine.PinConfig{Mode: machine.PinOutput})
    dat.Configure(machine.PinConfig{Mode: machine.PinInput})


    var count uint32 
    for{
        println("val...");
        println("----------------------------------------------");
        for j:=0 ; j<8000/32; j++ {
           for i:=0 ; i<32; i++ {
                print(signal[j*16 + i]); 
                print(" ");
           }
           println("");
        }
        println("");
        println("----------------------------------------------");
        time.Sleep(1 * time.Millisecond)
        go capture()
        println(count);
   }
}

スマフォアプリを使って、500Hzの音を発生させてMEMSからの出力が取得できた。得られたデータに対して、加算(Σ)やフィルタ演算をやって、本当に500Hzの波形が表れるのかを確認する

*1:速度最適化等は設定していないので、最適化を働かせるとさらに早くなるかも