初めてのRaspberry Pi Pico ㉜ CircuitpythonでMCP3304


 マイクロチップのMCP3304は13ビットA-Dコンバータです。最上位は符号ビットなので、-4096~+4095までの分解能がある12ビットADCです。インターフェースはSPIバスで、転送速度は最大2.1MHz(5V)です。動作電圧は5Vが推奨されていますが、3.3Vでも動きました。

MCP3304のおもなスペック

  • ビット数 13
  • チャネル数 8(シングルエンド)、4(差動)
  • 基準電圧 内蔵なし、端子あり
  • 変換速度 100ksps(5V時)
  • インターフェース SPI(モード0,0および1,1)、クロック最大2.1MHz(5V時)
  • 動作電圧 4.5(2.7)~5.5V
  • ピン数 16ピンDIP

接続

MCP3304の端子 Picoの端子(GPIO) 名称
1 ch0 - -
2 ch1 - -
3 ch2 - -
4 ch3 - -
5 ch4 - -
6 ch5 - -
7 ch6 - -
8 ch7 - -
9 DGND GND GND
10 /CS GP8 GP8
11 Din GP3 MOSI SPI0 TX
12 Dout GP4 MISO SPI0 RX
13 CLK GP2 SPI0 SCK
14 AGND GND GND
15 Vref 3V3 3.3V
16 Vdd 3V3 3.3V

 ch0-ch1差動入力には、電池駆動の簡易電源TL431の出力をつないでいます。約2.5Vです。

プログラム

 コマンドを送るフォマットは次のとおりです。
  Startbit チャネル指定4バイト
 例えば、差動ch0-ch1であれば、
  0000
です。最後のチャネル指定ビットD0がMCP3304へ送られるタイミングで、約1ビットおいて、NULLビットに引き続き、
  Sign D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
のA-D変換結果データが、MCP3304からPicoへ送られてきます。
 SPIは基本8ビット単位なので、LSBのD0から前にさかのぼって、8ビット単位で送るべきデータを整理します。差動ch0-ch1の場合です。
  x x x x 1 0 0 0 0 x x x x x x x x x x x x x x x
 SPIは、クロックを送り続けないとデータはやってきません。上記のxはダミーなので、0でも1でもかまいません。ただし、最初の4ビットのいずれかを'1'にすると、Startbitと解釈されるかもしれないので、'0'にします。'0'でもクロックは発生します。したがって、ここでは、ch0-ch1差動のデータは、次のようにしました。
  0x08 0x00 0xff

 本プログラムは、差動入力だけを対象にしています。

チャネル指定 1バイト目 2バイト目 3バイト目
ch0 = IN+ ch1 = IN- 0b00001000 0b00000000 0xff
ch2 = IN+ ch3 = IN- 0b00001001 0b00000000 0xff
ch4 = IN+ ch5 = IN- 0b00001010 0b00000000 0xff
ch6 = IN+ ch7 = IN- 0b00001011 0b00000000 0xff

 3バイト送ったので、読み出したデータは3バイトです。1バイト目はごみなので捨てます。2バイト目は上位桁Sign D11 D10 D9 D8が右詰めで入っています。3バイト目は、D7 D6 D5 D4 D3 D2 D1 D0です。
 Signビットを見て符号をつけます。
 12ビットのデータなので、Vrefの3.3Vをかけ、4096で割って電圧を求めます。Vrefは、できるだけ正確にテスタで測った値を記入しておきます。

from board import *
import busio
import time
import digitalio

print('\n  start\n')

spi = busio.SPI(GP2, GP3, GP4)  # SPI0BUS clock MOSI MISO
while not spi.try_lock():
    pass
spi.configure(baudrate=1_000_000, phase=0, polarity=0)

cs = digitalio.DigitalInOut(GP8)
cs.direction = digitalio.Direction.OUTPUT
cs.value = 1

def readADC():
    result = bytearray(3)
    cs.value = 0
    spi.write_readinto(bytearray([0x08,0x00,0xff]), result)  # cho-ch1
    cs.value = 1
    temp = (result[1] & 0b00011111) << 8 | result[2]
    Volts = -(temp & 0b1000000000000) | (temp & 0b0111111111111)
    #print(result[0], result[1], result[2])
    #print(bin(Volts))
    return(Volts)

while 1:
    print(str(readADC()*3.3/4096) + 'V')
    time.sleep(3.14)

 ch0-ch1を読み取っているところです。