はじめに

Raspberry Pi にはアナログ入力がないので、電圧のような連続した値を読むには外付けのADコンバータ が要ります。ここで使う MCP3425 は、差動入力・16ビットまで対応の小さなADCで、I2C 2本の線でつなげます。

この石を使ううえでの肝は、ゲインや分解能といった設定が、コンフィギュレーションレジスタに書き込む1バイトにすべて詰まっているという点です。逆に言えば、この8ビットに何を立てるかさえ決まれば、あとは値を読むだけ。まずはラズパイ側でI2Cを有効にしておいてください。

Raspberry PiとMCP3425の配線

今回は動作確認が目的なので、センサは使わず、分圧抵抗でつくった一定のアナログ電圧を読ませます。3.3Vはラズパイから取り、10kΩ2本で半分に分けているので、Vin+には約1.65Vが現れます。

分圧抵抗でつくったアナログ電圧

MCP3425は差動入力ですが、話を簡単にするためVin−をGNDに落とし、Vin+だけを使います。使ったのはRaspberry Pi Zero WHですが、I2Cが使えれば他のラズパイでも同じです。

配線は次のとおりです。

Raspberry PiとMCP3425の配線

MCP3425役割Raspberry Pi接続先ラズパイ物理ピン
1Vin+分圧抵抗へ
2VssGND6番
3SCLGPIO35番
4SDAGPIO23番
5Vdd+3.3V1番
6Vin−GND

MCP3425(SOT23-6)各ピンの役割

ラズパイ側のI2Cは、SDAがGPIO2、SCLがGPIO3に割り当てられています。ピンヘッダの物理位置と信号名は取り違えやすいので、下のGPIO配置図で確認しながら結線すると安心です。

Raspberry PiのGPIO配置

MCP3425が認識されているか確認する

配線ができたら、i2cdetect でラズパイからMCP3425が見えているかを確かめます。正しくつながっていれば、アドレス0x68が表示されます。

$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

もしアドレスが出てこないときは、まずラズパイを再起動してみてください。MCP3425はVin+とVin−がどちらも未接続だとアドレスを返さないことがあるので、入力側の結線も合わせて見直します。

差動入力とはどう読むか

MCP3425は差動入力なので、読み取る電圧はVin+とVin−の差になります。

V_IN = V_IN+ − V_IN−

入力範囲はGNDを基準にプラスマイナス約2Vまでです。今回はVin−をGNDに落として0Vとしているので、差はそのままVin+の電圧、つまり約1.65Vになります。内部では、この差動電圧がゲイン付きのアンプ(PGA)を通ってから16ビットのΔΣ型ADCに入る、という構成です。

MCP3425の内部ブロック図

コンフィギュレーションレジスタに1バイトを書く

MCP3425の設定は、コンフィギュレーションレジスタと呼ばれる8ビットのレジスタに集約されています。ゲイン・分解能・変換モードといった項目が、この1バイトのどのビットを立てるかで決まります。今回の設定を組み立てると10011000(16進で0x98)になり、これがそのままI2Cで書き込む値になります。

コンフィギュレーションレジスタ=10011000。各ビットの意味

ビットごとに、上位から順に見ていきます。まずbit7はRDY(データレディフラグ)で、これはワンショット変換のときに使うものですが、今回は連続変換モードなので1にします。続くbit6とbit5はチャネル選択用ですが、MCP3425はチャネルが1つしかないので使われず00です。

bit4は変換モードで、1が連続変換、0がワンショットです。今回はずっと読み続けたいので連続変換の1にします。

bit4動作
1連続変換モード。変換を継続的に行い続ける
0ワンショット変換モード。1回変換したら低消費電力のスタンバイに入る

bit3とbit2は分解能とサンプリングレートを決めます。ここはトレードオフで、分解能を上げるほど1秒あたりに取れる回数は減ります。今回は16ビット・15SPSにしたいので10を書きます。

bit3/2分解能サンプリングレート
1016bit15 SPS
0114bit60 SPS
0012bit240 SPS

最後のbit1とbit0は入力ゲイン(PGA)です。アナログ電圧が小さいときに増幅して読めるようにする機能ですが、今回は等倍でよいので00(1倍)にします。

bit1/0ゲイン
001倍
012倍
104倍
118倍

こうして上位から並べると1 00 1 10 00、詰めて10011000になります。

Pythonで電圧を読む

あとはI2Cで先ほどの10011000を書き込み、変換結果を読み出すだけです。MCP3425は上位バイトと下位バイトが入れ替わって届くのでswap16で並べ替え、値は2の補数の符号付き16ビットなのでsign16で10進に直しています。

import smbus
import time
i2c = smbus.SMBus(1)
addr=0x68
config = 0b10011000
Vref=2.048

i2c.write_byte(addr, config) #16bit
time.sleep(0.2)

def swap16(x):
    return (((x << 8) & 0xFF00) | ((x >> 8) & 0x00FF))

def sign16(x):
    return ( -(x & 0b1000000000000000) | (x & 0b0111111111111111) )

while True:
    data = i2c.read_word_data(addr, config)
    raw = swap16(int(hex(data), 16))
    raw_s = sign16(raw)
    volts = round((Vref * raw_s / 32767), 4)
    print(volts)
    time.sleep(1)

実行すると1.6055Vと表示されました。テスターでの実測は1.657Vだったので0.05Vほどの差はありますが、分圧抵抗の誤差も乗っていることを考えれば、動作確認としては十分でしょう。

参考サイト

関連記事

I2CでのADC読み取りに慣れたら、別のADCや、ラズパイでの計測・GPIO工作にも広げてみてください。