第77回でビルドしたNucleo-F401RE用MicroPython、Pyboard用のpybモジュールを搭載(第78回)。pybモジュールはいろいろ強力な機能を搭載。その一つがタイマ駆動のADサンプリング機能です。Pyboard上では2チャンネルを210kHzでサンプリングできると。結構速いんでないかい。
※「MicroPython的午睡」投稿順 Indexはこちら
MicroPythonのソフトウエアループの中でADコンバータを読み取っていては、サンプリング速度も大したことはなく、またソフトウエアのループなのでサンプリング時刻も頼りありません。そこでタイマ割り込み利用を考えますが、MicroPython上でタイマ割り込みを定義し、そのコールバック関数でAD読み取りをするのは、速度的にはやっぱり大したことできないんでないかい。たぶん10kHzくらいか?上限測ったわけでないケド。
しかし、pybモジュールには、Timerオブジェクトを直接渡して「よきに計らってくれる」 ADC読み出し関数 read_timed ありです。以下そのドキュメントへのリンクです。
上記ドキュメントによれば、ADC2チャンネル測定で、210kHzでオーバランなしのサンプリングができた(pyboardで)、215kHzでは欠落があったとのこと。MicroPythonでの処理としては出色の速さでないの。F401REは、Pyboardの半分しかメモリを積んでいませんが、クロック周波数は上回ります。ちょっとしたアナログ波形のキャプチャもMicroPythonでできそう。ホントか?
ただ、この関数「ブロッキング」です。バッファが一杯になるまでサンプリングに専念。連続処理ができるわけでないです。ごもっとも。
今回実験に使ったMicroPythonコード
いつものとおりエラーなど何も考えてない実験用コードが以下に。
バッファサイズは後の処理を考えて4096点としてあります。バッファはuarray.arrayのH型(符合無ハーフワード)。ADCは12ビットのハズなので読み取り値をそのまま保持可能。
ADコンバータはA1ピンを入力とし、タイマ4(16ビットのアップダウン可能)をサンプリング用のタイマとしました。設定したサンプリング周波数は控えめに10kHzです。
なお、STM32F401REは多数のタイマを搭載してますが、MicroPythonがどのタイマをどう使っているのか調べてないので(いいかげんな)、適当(ロシアンルーレット方式ともいう)で4番としてます。後で調べないと。
バッファが一杯になったら、オンチップFlashのストレージにテキストで書き出してます。ただし、実際にやってみるとテキスト書き出し、ひどく時間がかかってよくない予感がします。他の方法にした方が良いかもしれません。
#STM32 ADC with Timer import pyb import machine import time import uarray def saveBuffer(buf, bufsiz): with open('/flash/adcData.txt', 'w') as fw: for i in range(bufsiz): fw.write(str(buf[i])) fw.write("\n") def main(): print("Start ADC sampling test.") bufsiz = 4096 buf = uarray.array("H", [0] * bufsiz) # H means unsigned Half word. adc = pyb.ADC(machine.Pin.board.A1) tim = pyb.Timer(4, freq=10000) adc.read_timed(buf, tim) saveBuffer(buf, bufsiz) print("End of test.") if __name__ == "__main__": main()
実験の準備と実行
今回、以下の別シリーズでNucleo-F446RE用に作成した「アナログフロントエンド」もどきをF401REに転用してます。
信号電圧を1.65V中心まで持ち上げた後ボルテージフォロワしている回路です。今回、実験用の入力信号の生成には、Digilent Analog Discovery2を使っているので、不要だったかもしれないです。
入力信号の波形が以下に。440Hz、オフセット0V、振幅100mV設定の正弦波であります。これがAFEもどきによりオフセット1.65Vに持ち上げられてA1端子に印加されまする。
一方、MicroPythonコードの方は、いつものようにThonny IDEから書き込み、そして実行します。このバージョンのMicroPythonの場合、内蔵Flash上のストレージは /flash として見えました。Flash書き込みはかなり遅いのでいやな感じですが、処理が終われば測定結果を格納した adcData.txt ができてます(Filesウインドウは自動更新されないので、手動で右クリックからリフレッシュする必要がありました。)
マイコン側のストレージ上のファイルは右クリックからPC側にダウンロードできるのでPC側に取得します。
取り出したファイルの内容は以下のような12ビット範囲の生のAD読み出し整数値が1行1データでならんだものです。
1928 1933 1941 1957 1979 2009 2045 2080 2109
これにFFTかけて、本当に440Hzの信号なのか調べてみようと思います。これにはScilab使わせてもらいます。以下の別シリーズ投稿でFFTのグラフを描けるようにしてあります。なお、上記のファイルをそのままScilabのfscanfMat()関数で読み取ると4096行x1列の配列になるのですが、以下の自作関数は1行x4096列対応なので、読み取った後転置してます。
手習ひデジタル信号処理(60) Scilab、FFT表示用関数「とりあえず版」追加
まずは、素の時間波形(最初の200点)を観察してみます。Y軸はADCの生の値、横軸はサンプル数の成り行き(タイマ指定のサンプリング周波数10kHz)
まあ、SIN波には見えるわな。
FFT(サンプリング周波数10kHz、ハミング窓指定)の結果は以下に。
だいたい440Hz付近なんでないの。ツッコミどころがありそうだが。