ESP32のSPI接続でMCP3208から高速AD変換を試してみました。

#ESP32のSPI接続でMCP3208からAD変換実験

##初めてQiitaへ投稿
初めて投稿させて頂きます。既出極まりない内容ですが、自分用のメモとしての初投稿です。ご容赦願います。

##ESP32のSPI設定
HSPIを使用し、端子設定はごく一般的なSPI設定です。

* CLK	32
* MISO	33
* MOSI	25
* SS	26 (chip select) Low Active

SPIクロック：4MHzで設定
SPIモード：Mode0 : POL=0,PHA=0　 (0,0)モード・・・データを立ち上がりエッジでサンプリング、立下りでシフトするモード

AD終了後、即時次のADを呼んだ時にどのくらいのレートでESP32から読めるのかを確認してみました。また、その時の波形も併せて載せておきます。

```c:sample.ino
#include <SPI.h>

#define SPI1_CLK  32
#define SPI1_MISO 33
#define SPI1_MOSI 25
#define SPI1_SS   26

#define SPI_CLK 4000000

SPIClass SPI1(HSPI);
SPISettings spiSettings = SPISettings(SPI_CLK, SPI_MSBFIRST, SPI_MODE0);//0,0

void setup() {
  Serial.begin(115200);
  SPI1.begin(SPI1_CLK, SPI1_MISO, SPI1_MOSI, SPI1_SS);
  pinMode(SPI1_SS, OUTPUT);
  pinMode(SPI1_CLK, OUTPUT);
  pinMode(SPI1_MISO, INPUT);
  pinMode(SPI1_MOSI, OUTPUT);
  digitalWrite(SPI1_SS, HIGH) ;
  SPI1.beginTransaction(spiSettings);
}

void loop() {
  byte channel = 0;
  Serial.println(adc_read(0));
  //delay(1);
}

int adc_read(uint8_t channel) {
  digitalWrite(SPI1_SS, LOW);
  SPI1.transfer(0x06 | channel>>2);//bit7-3:dummy, bit2:start, bit1:single,bit0:D2
  uint8_t dh = SPI1.transfer((channel & 0x03) << 6);//D1,D0,X,Null,B11-B8
  uint8_t dl = SPI1.transfer(0x00);//B7-B0
  digitalWrite(SPI1_SS, HIGH);
  return ((dh & 0xF) << 8 | dl); //get 12bits data
}
```

##MCP3208へのアナログ入力
アナログ入力としては、可変抵抗で 0Vから3.3Vまで振った場合、デジタル出力は12ビットなので、0～4095になります。ただし、0V近辺および3.3V近辺では既にクリッピングされた感じでした。正確には測定していません。

##波形1 クロックとMISOの波形
MCP3208のデータシートでは、5bitでチャンネル指定、1bitのダミーと1bitのNullのあと、12bitのAD出力データがMSB firstで通信される事になるため、全部で19bitのクロックが必要になります。（下記仕様の波形から、SPIモードは 0,0と確認）
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266665/6c5f7100-c719-556c-b394-712ca36cad34.png)

ただ、ESP32の標準SPIライブラリでは、バイト単位での送受信に限られるため、頭に5bitのダミーのデータ（0）を入れて、全部で24bit（3バイト）にして通信することになります。19bitで送信する方法は調査不足かもしれません。

（ちなみに、ESP8266では、通常のSPIライブラリでは無いライブラリを用いて、19bitで通信することは出来ました。そのライブラリをESP32で試しては居ません。https://github.com/MetalPhreak/ESP8266_SPI_Driver 中のspi_transaction()関数を利用）

6bit目にStartビットとして'H'を送るまでのクロックは無視されるので、通信的には問題なしです。
MOSIの１バイト目で、Start bitと、Single指定と、Channel番号のD2を指定しています。Channel番号の下位ビットは2バイト目のbit7,bit6で送っています。データ送信と受信はSPIの場合は同時です。。

下記が3バイト(24bit)のCLKと、MISO信号です。2バイト目のbit3-0と3バイト目のb7-0がAD変換結果の12bitデータとなります。
![esp32-mcp3208-clk-miso.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266665/13161489-054d-c5db-4314-bd68c0cedcca.png)
 
##波形2 Delay無しで回した時の サンプリング周期の確認
AD終了後、すぐ次のループに入る処理を行った場合、サンプリング間の周期は、約520usec（サンプリング周期は 1.9kHz）になりました。Delay無しで繰り返しているにも関わらず、以前ESP8266で取った時の272us（Serial.printlnあり）より遅い理由は分かりません。クロック速度はESP8266の時も 4MHzでしたのでクロックの差は無し。Dummyのクロック5発分は、ESP8266の時には不要だったので、今回の方が少し不利ですが、それ以上の差がある。ライブラリの違いかもしれません。
![2a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266665/1b7d5930-216c-e24a-2a77-4919385512d0.png)
ちなみに、Serial.printlnを止めれば、短縮されますが、波形を取り忘れました（汗）

##Arduino IDEのシリアルプロッタでのAD出力確認
少しDelayを入れて（波形を取りやすくするために10msを入れました）、 Analog入力を0V～3.3Vの可変VRを動かして、AD結果を波形にしたものがこれです。電圧が0手前、3.3V手前の時に、AD結果として既にクリップされていますが、正確な電圧範囲は測定していません。
 <img width="682" alt="3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266665/1fd1778b-5330-2ac5-9ecb-8110fc91a954.png">

とりあえず、Qiita初投稿はここまでです。
次はこの値を Bluetoothで送り、別のESP32で受信した値でサーボモーターを回す予定です。