Windows PCにPython、FT232H、MCP3004の組み合わせでアナログ信号処理
GPIOボードFT232HとACコンバータMCP3004の組み合わせ。
BLINKA使用
※ラズパイの記事や、古い作法しか見つけられなかったため、メモとして残す。
※書いてる人は普段は電気/電子回路やらない人です。
FT232Hについて
秋月:https://akizukidenshi.com/catalog/g/gM-08942/
本家:https://learn.adafruit.com/adafruit-ft232h-breakout
USB接続でGPIO入出力ポートを設けるモジュール。
単純なデジタル信号だけでなく、I2CとSPI、2種のシリアルフォーマットも利用できる。
FT232HとCircuitPython、BLINKAのインストールについては本記事では省略
↓ adafruitの「setup」に倣った。
https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h/setup
MCP3004 について
秋月:https://akizukidenshi.com/catalog/g/gI-11987/
製品説明書:https://akizukidenshi.com/download/ds/microchip/mcp3008.pdf
10bit X 4チャンネル、SPIシリアル出力のADコンバーター。
姉弟製品に2チャンネルのMCP3002や8チャンネルのMCP3008がある。
※シリアル出力ということは信号線が1本ということ、「10bitだから10ポート」ではない。
- 5V 電源での最大サンプルレート 200 ksps / 3Vでは100ksps程度。
- 最大クロックは1~3MHzあたり(?)
- サンプリングが実用的クロックは(使用環境次第で)10kHz程度まで下がる(説明書のp22)
- ※高レートほど消費電力が増えるような?
FT232Hへの接続
とにかく7~14番はすべて繋いでしまえ! (※厳密には12番はアナログ入力のグランドですが、ここではアナログ信号の電源もFT232Hからとってる前提。)
・電源V_DDはFT232Hの5V、(3.3Vでも可のはず)
・参照電圧V_REFは電源と同じ、
・クロックは当然接続必須だろう。
・チップセレクトはどういうものかよくわからないがCircuitPython側で必須っぽい。FT232HのD5に繋いだ。
・SerialDataOutは、今回は入力信号だけなので繋がなくてもよいのか?とか思たけど、これ繋がないと動作しない感じだった。
↓ SPIのSCLK、MOSI、MISOについてはBlinkaで指定されているから迷うこともない。
※CSチップセレクトについて、恐らく(実態と違うかもしれないがコンセプト的には)、複数のSPI/I2Cデバイスでクロック等を共有し、CSで処理対象を切り替えるといった使い方をする。のかな(?)
CircuitPythonのMCP3XXXシリーズのバンドルを利用
ヘルパーというのかドライバーというのかしらないけど、要するに必要なものはすでに用意されているということ。
https://github.com/adafruit/Adafruit_CircuitPython_MCP3xxx/tree/df768ac18242e15077d96dd4aa6fc714de5c9133/adafruit_mcp3xxx
> C:\**\python.exe -m pip install adafruit-circuitpython-mcp3xxx
サンプルコード
MCP3004の0番ポート(1番ピン)にアナログ信号を入力する場合のサンプルです。
#!python3
import os
os.environ['BLINKA_FT232H'] = '1' #Setting Environmental Variable
import board
import busio
import digitalio
import adafruit_mcp3xxx.mcp3004 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn
## https://github.com/adafruit/Adafruit_CircuitPython_MCP3xxx/blob/df768ac18242e15077d96dd4aa6fc714de5c9133/adafruit_mcp3xxx/mcp3004.py
## ( https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h/spi )
## create library object using our Bus SPI port
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
# create the cs (chip select)
cs = digitalio.DigitalInOut(board.D5)
# create the mcp object
VR=5.0 ## 3.3
mcp = MCP.MCP3004(spi, cs, ref_voltage=VR )
# create an analog input channel on pin 0
chan = AnalogIn(mcp, MCP.P0)
print("Raw ADC Value: %d / (Max%d) "%( chan.value>>6, 2**10) )
print("ADC Voltage: %g / (Max%g) V"%(chan.voltage, VR) )
※ ADコンバータMCP3004の分解能は10bitですが、PythonAPI上(MCP.MCP3004の中)で16bitに換算された値がchan.valueに格納されてます。
上のサンプルでは6ビットシフトして10bitに戻した値を表示しています。
ロジアナ
なんか妙に遅いので
ロジックアナライザで信号みてみました。
黄緑色チャンネル/橙色6角形が MISO(MPC3008の出力側)
ADの値は 509 = 0111111101 (値が一個ずれてるのはクロックの設定がまずいのかな)
0CHで非差動
(青色チャネル/黄緑6角形 MOSIの「1」2個はStart信号1と非差動の1で、直後の「0」3個がCH番号です。)
1個の値取得に3バイト分24単位ほど通信するようですね。
SPIクロック2MHz弱で作動している模様。cs0._pin.mpsse_gpio._controller.frequency の値2000000と一致。(?)
24 / 2M = 12 マイクロ秒 くらい。
ただし......
↑ このように CS が落ちてからと、CS 上がるまでのタイムラグが長い。
全体で0.8ミリ秒くらいかかってます。
ということは1チャンネルのデータ取得を反復したときに1000Hz強くらいのサンプリングレートになる。
遅いのこの部分か。
↑ 2 データ続けて取得した場合