MicroPythonを使ってみる(その4)&エレキ素人が何か考える(その7):DAコンバーター


MicroPythonとエレキ素人のコラボ(若干こじつけ)

MicroPythonを用いて、Wio TerminalのDAコンバーター経由で正弦波をつくり、オシロスコープで観察してみる。

Wio Terminal

本家サイトはこちらである。後ほどオシロスコープで波形を観察するので、ピン配置を下記に記す。

ピン11:DAC0(DAコンバーター)、ピン6:GNDとをオシロスコープにつなげる。

MicroPython環境

Wio Terminalでは、本家サイトのArduPyというMicroPythonの環境がある。その手順に従い、ArduPy FirmwareをWio Terminalに入れる。プログラム作成やWio Terminalへの書き込みに関しては、他のIDEを使っても良い。今回は、MicroPythonで有名どころのThonnyを利用した。

正弦波を作り出すソースコード

ここにMicroPythonでDACを扱うコードがあったので、そのまま使おうとしたが、DMA転送によりDACを実現するwrite_timed()という関数が、Wio Terminalに存在しなかった。

>>> from machine import DAC
>>> help(DAC)
object <class 'DAC'> is of type type
  write -- <function>
  resolution -- <function>
  reference -- <function>

他にMicroPythonを扱えるボード(ESP32, ESP8266, Seeeduino XIAO)を所持していたが、いずれにもwrite_timed()には存在しなかった。どうも、write_timed()が存在するのはpyboardのみらしい(執筆時点)。

sleep_us()で実現

そこで、write()とsleep_us()を用いて、ソフトウェア的に無理やり実現する。下記コードとなる。

import time
import math
from machine import DAC, Pin

freq = 100
num = 100
ary = list(range(num))
for i in range(num):
  ary[i]=int(4095*(math.sin(2*math.pi*i/num)+1)/2)
dac = DAC(Pin(11))
while 1:
  for i in range(num):
    dac.write(ary[i])
    time.sleep_us(int(1000000/(num*freq)))

上記コードでは、sin値を整数値化(0-1)し、100Hz(freq)、1周期を100分割(num)して出力している。Wio Terminal DACの分解能は10bit(=4096)であり、分割されたポイントごとの値を事前に作成しておき(配列ary)、freqに従って、アナログ出力(write)する。4096をwriteすると、0Vが出力されたので、最大値を4095としている。

検証の前に

time.sleep_us()の精度が気になるところ。そこで、次のようなコードで確認。

import time
start = time.ticks_us()
time.sleep_us(1)       # 1,10,100,100と変化させる。sleep_ms()にも置き換える。
end = time.ticks_us()
print(str(end-start) + " ticks")
sleep_us() 1 10 100 1000
ticks 26 36 126 1026
sleep_ms() 1 10 100 1000
ticks 1029 10028 100030 1000029

これらから、sleepの確からしさは、1 ms以上と思われる。ここでは、テストなので、100 us以上を考慮した。

検証

今回はオシロスコープとして、pokitMeter(スイッチサイエンスさんで購入)を利用。オシロスコープとWio Terminalとの接続は下記状況。

結果

100Hz(freq)、分割数100(num)と設定した結果(sleep:100us)


ソフトウェア処理の限界か、100Hzに程遠く、62.9Hzと表示(赤枠)。このオシロスコープでは、周波数解析も可能、下記のとおりの結果。

ピークは68.226Hz。

100Hz(freq)、分割数50(num)と設定(sleep:200us)


77.7Hzと表示。分割数を減らしたので、若干、波がデジタルチックになってる。

100Hz(freq)、分割数25(num)と設定(sleep:400us)


87.8Hzと表示。波がひどくなってきたが、sleepの回数が減ったため、周波数が100Hzに近づいてきている。

50Hz(freq)、分割数100(num)と設定(sleep:200us)


31.9Hzと表示。

25Hz(freq)、分割数100(num)と設定(sleep:400us)


22.5Hzと表示。

10Hz(freq)、分割数100(num)と設定(sleep:1000us = 1ms)


9.5Hzと表示。

5Hz(freq)、分割数100(num)と設定(sleep:2ms)


4.9Hzと表示。ここまで来ると精度が高くなっている。

最後に

ソフトウェア処理の限界が一部垣間見える。DMAを利用しないとダメか。