ESP32 を使って、 SPI の基本的な動作を確認します。
ここで接続するデバイスとして、 10 bit x 8 チャンネルの ADコンバータ MCP3008 が手元にあったのでそれを使いました。
環境
- Arduino 1.8.10 for Linux
- esp32 by Espressif System Version 1.0.3
- WEMOS LOLIN32
接続
信号名 | MCP3008 PIN | MCP3008 信号名 | ケーブル | ESP32 GPIO | ESP32 信号名 |
---|---|---|---|---|---|
VDD | 16 | VDD | オレンジ | 3V3 | 3V3 |
15 | VREF | VDD | |||
14 | AGND | DGNDに接続 | |||
SCK | 13 | CLK | 黄色 | IO18 | VSPCLK |
MISO | 12 | DOUT | 紫 | IO19 | VSPIQ |
MOSI | 11 | DIN | 灰 | IO23 | VSPID |
CS | 10 | CS/SHDN | 緑 | IO5 | VSPICS0 |
GND | 9 | DGND | 黒 | GND | GND |
MCP3008 はアナログ入力ポートが CH0 〜 CH7 の 8チャンネルあります。それぞれ 10 bit の分解能で AD 変換を行い、SPIでマイコンなどに取り込むことができます。テストのため、CH0 に 1kΩの抵抗をつけて、VDDにつないでみました。
MCP3008 の SPI 設定
データシートから、転送に必要な設定を読んでみます。
- MSBFIRST (LSBFIRST転送もMSBFIRST転送の後に行われる)
- アイドリングHIGH/LOW両対応
- 転送タイミング クロックの立ち上がりエッジ (2020/08/23:「立ち下がり」と記述していたのを修正しました)
- クロックスピード 10kHz以上,最高1.35MHz (VDD=2.7V時)
スタートビットとして1ビット送信しますが、SPIライブラリは8ビット単位での送信です。そのために前に7ビットの0を入れて転送します。
それに続く8 bit において以下のようにデータが送受信されます。
bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
---|---|---|---|---|---|---|---|
SGL/DIFF | D2 | D1 | D0 | ? | 0 | B9 | B8 |
ここで、bit7~bit4はMCP3008への入力です。SGL/DIFFは シングルエンド入力と作動入力のビットです。1ならシングルエンド、0なら作動入力となります。
今回はシングルエンド入力を使います。その場合、D2/D1/D0 はチャンネル指定、CH0なら D2=0,D1=0,D0=0。CH1ならD2=0,D1=0,D0=1。
bit2〜bit0 はMCP3008からの出力です。bit2 が常に0,B9およびB8で10bitのAD変換値のうちの上位2ビットとなります。
更に続く 8 bit において、以下のようにMCP3008から続くB7〜B0の残り8ビットが出力されます。
bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
---|---|---|---|---|---|---|---|
B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
この転送が終わってもCS信号がLow出会った場合には、以下の 7bit がMSBFIRST転送として行われます。
B1 | B2 | B3 | B4 | B5 | B6 | B7 |
SPI の転送モード
Mode | CPOL(クロック極性) | CPHA(クロック位相) |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
2 | 1 | 0 |
3 | 1 | 1 |
クロック極性は 0:アイドルLo パルスHigh 1:アイドルHigh パルスLo
クロック位相は 0:パルス先端で転送 1:パルス後端で転送
なので MCP3008 は SPI の モード 0 または モード 3 を使用することになります。
ESP32 のSPI設定
ESP32 は VSPI、HSPI の2つの SPIチャンネルがありますが、SPIライブラリだとVSPIの方が使われるそうです。
更に、 SPI のポート割当は変更可能なようですが、今回はデフォルトの設定を使っています。
速度は SPISettings パラメータで設定します。 今回は 1000000 と設定することで、最大 1MHz で駆動することになります。
コード
#include <SPI.h>
#define SS 5
float Vref = 3.3 ;
SPISettings settings(1000000,MSBFIRST,SPI_MODE1);
void setup() {
pinMode(SS, OUTPUT);
Serial.begin(115200);
SPI.begin();
}
void loop(){
byte single = 1 << 7; // Single...1 /Diff...0
byte channel = 0;
byte buffer1 = single | ( channel << 4 ) ;
byte buffer2 = 0 ;
float volt;
unsigned int getdata;
SPI.beginTransaction(settings);
digitalWrite(SS, LOW);
SPI.transfer( 0b00000001); // Start bit
buffer1 = SPI.transfer(buffer1); // CH0 singleEnd
buffer2 = SPI.transfer(buffer2);
digitalWrite(SS, HIGH);
SPI.endTransaction();
getdata = ((buffer1 & 0x03) *256) + buffer2;
volt = getdata*Vref /1024;
Serial.print( getdata );
Serial.println( ": " +String(volt,3) + "V");
delay(1000);
delay(1000);
}
実行結果
1023: 3.297V
1023: 3.297V
1023: 3.297V
7: 0.023V
23: 0.074V
0: 0.000V
0: 0.000V
0: 0.000V
154: 0.496V
1023: 3.297V
1023: 3.297V
1023: 3.297V
1023: 3.297V
1023: 3.297V
1023: 3.297V
・
・
・
CH0 に接続した抵抗を、VDDからGNDに繋ぎ変え、再度VDDに接続した時の値です。