Picoには12ビット4チャネルのA-Dコンバータが内蔵されています。もし4チャネル分足りなかったら、という想定で外部にICを追加します。
MCP3204のおもなスペック
- ビット数 12
- チャネル数 4(シングルエンド)、2(疑似差動)
- 基準電圧 内蔵なし、端子あり
- 変換速度 100ksps(5V時)
- インターフェース SPI(モード0,0および1,1)、クロック1.6MHz(5V時)、0.8MHz(2.7V時)
- 動作電圧 2.7~5.5V
- ピン数 14ピンDIP
接続
MCP3204の端子 | Picoの端子(GPIO) | 名称 |
---|---|---|
1 ch0 | - | - |
2 ch1 | - | - |
3 ch2 | - | - |
4 ch3 | - | - |
5 NC | - | - |
6 NC | - | - |
7 DGND | GND | GND |
8 /CS | GP5 | SPI0 CSn |
9 Din | GP3 | MOSI SPI0 Tx |
10 Dout | GP4 | MISO SPI0 RX |
11 CLK | GP2 | SPI0 SCK |
12 AGND | GND | GND |
13 Vref | 3V3 | 3.3V |
14 Vdd | 3V3 | 3.3V |
入力のch0には、電池駆動の簡易電源TL431の出力をつないでいます。約2.5Vです。ch1はGND、ch2は3.3Vの電源、ch3はGNDにつないで結果をみます。 |
プログラムmcp3204.c
フォルダはmcp3204としました。CMakeLists.txtは省略します。17回以前を参考にしてください。
チャネルは、シングルエンドのch0、ch1、ch2、ch3、ch0-ch1の疑似差動のIN+/IN-、ch0-ch1の疑似差動のIN-/IN+、ch2-ch3の疑似差動のIN+/IN-、ch2-ch3の疑似差動のIN-/IN+から選択します。
チャネルの指定は、下の表の左の4ビットで行います。
Single/Diff | D2 | D1 | D0 | 入力のタイプ | チャネル |
---|---|---|---|---|---|
1 | x | 0 | 0 | シングルエンド | ch0 |
1 | x | 0 | 1 | シングルエンド | ch1 |
1 | x | 1 | 0 | シングルエンド | ch2 |
1 | x | 1 | 1 | シングルエンド | ch3 |
0 | x | 0 | 0 | 疑似差動 | ch0=IN+、ch1=IN- |
0 | x | 0 | 1 | 疑似差動 | ch0=IN-、ch1=IN+ |
0 | x | 1 | 0 | 疑似差動 | ch2=IN+、ch3=IN- |
0 | x | 1 | 1 | 疑似差動 | ch2=IN-、ch3=IN+ |
コマンドを送るフォマットは次のとおりです(送るのはPicoで、送られてくるのもPicoです)。
Startbit チャネル指定4バイト
例えば、シングルエンドch0であれば、
1 1x00
シングルエンドch1であれば、
1 1x01
です。最後のチャネル指定ビットD0がMCP3204へ送られるタイミングで、約1ビットおいて、NULLビットに引き続き、
D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
のA-D変換結果データが、MCP3204からPicoへ送られてきます。
SPIは基本8ビット単位なので、LSBのD0から前にさかのぼって、8ビット単位で送るべきデータを整理します。シングルエンドch0の場合です。
x x x x x x 1 1 x
0 0 x x x x x x
x x x x x x x x
SPIはクロックを送り続けないとデータはやってきません。上記のxはダミーなので、0でも1でもかまいません。したがって、ここでは、ch0のデータは、次のようにしました。
0b00000110
0x00
0xff
本プログラムは、疑似差動入力に対応していません。したがって、チャネルの指定で変化するのは2バイト目だけです。
3バイト送ったので、読み出したデータは3バイトです。1バイト目はごみなので捨てます。2バイト目は上位桁D11 D10 D9 D8
が右詰めで入っています。3バイト目は、D7 D6 D5 D4 D3 D2 D1 D0
です。
12ビットのデータなので、Vrefの3.3Vをかけ、4096で割って電圧を求めます。Vrefは、できるだけ正確にテスタで測った値を記入しておきます。
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
# include <stdio.h>
# include <string.h>
# include "pico/stdlib.h"
# include "hardware/spi.h"
# define PIN_MISO 4
# define PIN_CS 5
# define PIN_SCK 2
# define PIN_MOSI 3
# define SPI_PORT spi0
static float Vref = 3.30;
static inline void cs_select() {
asm volatile("nop \n nop \n nop");
gpio_put(PIN_CS, 0); // Active low
asm volatile("nop \n nop \n nop");
}
static inline void cs_deselect() {
asm volatile("nop \n nop \n nop");
gpio_put(PIN_CS, 1);
asm volatile("nop \n nop \n nop");
}
void setup_SPI(){
// This example will use SPI0 at 0.5MHz.
spi_init(SPI_PORT, 500 * 1000);
gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);
gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);
gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);
// Chip select is active-low, so we'll initialise it to a driven-high state
gpio_init(PIN_CS);
gpio_set_dir(PIN_CS, GPIO_OUT);
gpio_put(PIN_CS, 1);
}
int readADC(uint8_t ch){
uint8_t writeData[] = {0b00000110, 0x00, 0xff};
switch(ch){
case 0:
writeData[1] = 0b00000000;
break;
case 1:
writeData[1] = 0b01000000;
break;
case 2:
writeData[1] = 0b10000000;
break;
case 3:
writeData[1] = 0b11000000;
}
// printf("\n %0b %0b %0b\n",writeData[0],writeData[1],writeData[2]);
uint8_t buffer[3];
cs_select();
sleep_ms(1);
spi_write_read_blocking(SPI_PORT, writeData, buffer, 3);
sleep_ms(1);
cs_deselect();
return (buffer[1] & 0x0f) << 8 | buffer[2];
}
int main() {
stdio_init_all();
printf("\nHello, MCP3204 Reading raw data from registers via SPI...\n");
setup_SPI();
for (uint8_t i=0; i<4; i++){
printf("ch%d is %.4fV\n", i, Vref * readADC(i) / 4096);
}
return 0;
}