LoginSignup
1

More than 3 years have passed since last update.

ESP32 と MCP3008 で SPI の勉強

Last updated at Posted at 2020-07-26

ESP32 を使って、 SPI の基本的な動作を確認します。
ここで接続するデバイスとして、 10 bit x 8 チャンネルの ADコンバータ MCP3008 が手元にあったのでそれを使いました。

環境

  • Arduino 1.8.10 for Linux
  • esp32 by Espressif System Version 1.0.3
  • WEMOS LOLIN32

接続

IMG_20200726_155656044.jpg

IMG_20200726_155512981.jpg

信号名 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 設定

データシートから、転送に必要な設定を読んでみます。

image.png

  • 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に接続した時の値です。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1