AD変換/ESP32-WROOM-32E/Arduino IDE (Debian11.4.0)

2022/08/06


AD変換

電源を電池とした使い方を検討しているが、電池の交換時期を知らせてほしいと思っている。
ESP32にはAD変換が内蔵しているそうなので、電池の電圧を測定する方法を調べてみよう。
知りたいこと
ESP32 Series Datasheet 、esp32_technical_reference_manual_enおよび ESP-IDF Programming Guide Analog to Digital Converter (ADC) によると ADコンバータはSAR (Successive Approximation Register:逐次比較型) ADCが2つあるらしい。
ADコンバータ
 入力端子 ADC1(8ch) : GPIO32-39
ADC2(10ch): GPIO0,2,4,GPIO12-15,GOIO25-GPIO27
GOIO25はGPIOの間違いか?
GPIO0,2,15はストラップピンだから自由に使えない。WROVERは0,2,4,15が外部で使用中。 ADC2モジュールはWiFiでも使うので、ADC2には制限がある。
 基準電圧1.1V(内蔵) 精度はどのくらいか? 個体差はどこかで修正できるのか?
基準電圧は1000[mV]から1200[mV]にばらつくそうだ。
 測定範囲入力0〜1[V]程度
入力が1Vを超えるときはADC Attenuationを設定
ADC_ATTEN_DB_0 100mV-950mV
ADC_ATTEN_DB_2_5 100mV-1250mV
ADC_ATTEN_DB_6 150mV-1750mV
ADC_ATTEN_DB_11 150mV-2450mV  なんだろうこの半端な11dBは?
アッテネータをつけるのはいいが、アッテネータを11dBにすると非線形性がでてくるとか。
 分解能12bit
ハードウェア上は9-12bitに設定可能
 直線性・誤差DNL(微分非線形誤差) -7〜+7LSB, INL(積分非線形誤差)-12〜+12LSB
測定条件 WiFi,Blootooth OFF
Missing Codeが発生するし(下位3ビットはあてにならない?)、変換特性自体に12LSBの誤差(3.6ビット相当)、分解能12ビットと言っているが実質8ビットじゃないのか?
100mV未満は0,オフセットがある。入力1[V]で飽和? 基準電圧未満でフルビット0xFFFになるのか?
 変換レート(Max)RTC controller 200ksps(5uS)
DIG controller 2Msps(500nS)
 入力インピーダンス ESP-WROOM-02 Datasheetには記載なし。
Electrical CharacteristicsにLogical levelとWi-Fi Radioはあるがアナログ的なことは記載がない。(この会社、電気の基礎ができていないのでは?)

ESP32 Series Datasheetより
ADC
ADC

ESP-IDE Programming Guideより
ADC
「基準電圧は1100mVだけど、個体差があるよ」ってどういうことよ?
しかも、0[V]付近は不感地帯があるし。

ESP32-WROOM-32EにはGPIO37,38がない。
GPIO0,13,21,22,TXD0,RXD0はすでに使用中






ADC
1 GNDGND 38
2 3V3(電源)IO23(GPIO23) 37
3 EN(使用時H)IO22(GPIO22)I2C0SCL使用中 36
4 SENSOR_VP(GPIO36,ADC1_CH0)TXD0(GPIO1)開発環境使用中 35
5 SENSOR_VN(GPIO39,ADC1_CH3)RXD0(GPIO3)開発環境使用中 34
6 IO34(GPIO34,ADC1_CH6)IO21(GPIO21)I2C0SDA使用中 33
7 IO35(GPIO35,ADC1_CH7)NC 32
8 IO32(GPIO32,ADC1_CH4)IO19(GPIO19) 31
9 IO33(GPIO33,ADC1_CH5)IO18(GPIO18) 30
10 IO25(GPIO25,ADC2_CH8)IO5 (GPIO15)29
SDIOスレーブのタイミングを決定
11 IO26(GPIO26,ADC2_CH9)IO17(GPIO17) 28
12 IO27(GPIO27,ADC2_CH7)IO16(GPIO16)LED(R)使用中 27
13 IO14(GPIO14,ADC2_CH6)IO4 (GPIO4 ,ADC2_CH0) 26
14 IO12(GPIO12,ADC2_CH5) 内部LDO電圧を設定IO0 (GPIO0, ADC2_CH1)BOOT使用中 25
 
15 GND16 IO13
(GPIO13,ADC2_CH4)
17-22
NC
23 IO15
(GPIO15,ADC2_CH3)
ブート時のログをU0TXDへ出力
(H:ログあり,L:ログなし)
24 IO2
(GPIO2,ADC2_CH2)
Download Boot時はL

スケッチ例

ソフトウェア
 どのレジスタに何をセットすればよい?スケッチ例を参考にする。どこかのスケッチを参照する。
 AD変換関数はあるのか?スケッチ例にあるのでは?
多チャンネル化できるのか?

幸いなことにスケッチ例があったので参考にする。
スケッチ例 AnalogRead.ino kohacraftのblog  ESP32のADCでキャリブレーションされた精度の良い電圧値を取得する方法より抜粋

"pin 2"とあるが、GPIO2だろうか?
流石に2番ピン(EN)はないよな。それともどこかの製品のピン番号だろうか?
DHT20のときも困ったが、「ピン番号」なのか「GPIO番号」なのか明示してほしい。
(基本はGPIOなのだろうか?)
アッテネータの設定が記載されていない。
デフォルトのままで使うのならよいが、どうだろうか?
pinModeの設定がないけど、このスケッチ例大丈夫なのか?
#define AD_PIN 34
#define N 2000
void setup() {
  Serial.begin(115200);
  delay(100);
  analogSetAttenuation(ADC_6db);  //ATT -6dB
  pinMode(AD_PIN, ANALOG);
}

void loop() {
  long adMillivoltTemp = 0;
  for ( int i = 0 ; i < N ; i++ )
  {
      adMillivoltTemp += (long)analogReadMilliVolts(AD_PIN);
  }
  float adMillivolt = (float)((double)adMillivoltTemp / (double)N); //mV Average
  Serial.printf("%d[mV]\n", (int)(adMillivolt+0.5) );
}
アッテネータを6dBに設定している。非線形性の問題があるので、これがよいかもしれない。

つかってみよう

IO2,(ADC2_CH2),IO15(ADC_CH3)を使ってみよう。
Ni-MH電池2本に抵抗をつないで、電池1コ分の電圧と電池2コ分(全体)の電圧を測定してみる。測定レンジが2.4[V]となるとアッテネータは11dBになる。
正確な電圧がわからないのがちょっとイヤだが、電池が放電していくようすがわかればよいことにする。
測定結果はデータベースに保存させる。----WiFiをOFFにして電圧を測定、WiFiをONにしてデータベースに接続ということになる。WiFi使用時の電圧を知りたいのだが、ムリだろうか?


つかってみた

電池の電圧を測定した。データベースからグラフにする手順は別の機会に話そう。
8:30から14:30まで6時間にわたりほぼ1分間隔で電池の電圧を測定した。
13:00で終了でよかったのだが、放置していたので1時間30分ほど過放電してしまった。
描画したグラフが途中で切れているが、間違いではない。
9:56から10:39、12:32から12:43はマイクロコントローラとデータベースとの接続が切れていたため、データが欠落している。

わかったこと

つかってみてわかったことがいくつかある。
  1. 入力インピーダンスはかなり大きい。
    電池とADコンバータ(ADC2_CH2,CH3)の間に電流計(30μAフルスケール,最小目盛0.5μA)を接続したが、針1本分も動かなかった。
    電源2.4[V],入力電流が0.5[μA]であれば抵抗分は4.8[MΩ]になる。電流はこれより小さいので、入力抵抗は4.8[MΩ]より大きい。入力容量は測定していない。

  2. GPIO2,GPIO15,GPIO12は使わないのが吉
    IO2(ADC2_CH2)がプルアップされているとプログラムの書き込みができない。プログラムダウンロード時に「/tty/USB0がみつからない」と言われる。
    プログラム書き込み前にIO2(ADC2_CH2)を開放またはプルダウンまたは開放すると解決する。

    ESP32 DatasheetによるとGPIO2,GPIO15はストラッピングピンである。
    ストラッピングピンはADC2と共用しているものがあるので注意。
    IO2(GPIO2,ADC2_CH2)はDownload Boot時に0(L)でなければならない。デフォルトでプルダウンされているので開放時はL扱いになる。プルアップするとDownload Bootできない。
    IO15(GPIO,MTDO,ADC2_CH3)はブート時のログの有無を決める。ブート時ログをU0TXDに出力するときはHにする。デフォルトはプルアップされているので開放時はH扱いになる。プルダウンするとブート時ログをU0TXDに出力しない。
    IO0(GPIO0,BOOT,ADC2_CH1) プログラム書き込みに使用
    IO12(GPIO12,MTDI,ADC2_CH5) 内部LDOの電圧を3.3Vまたは1.8Vのどちらかを選択
    IO5(GPIO5) SDIOスレーブのタイミングを決定

  3. WiFiを使うとADCが使えない。
    前述にあったとおりだが、「どのように使えないか」がわからなかった。
    WiFi.begin()でWiFiを使うと、 analogRead()もanalogReadMilliVolts()も0になる。雑音が多いとかランダムな値になるとかではない。
    WiFi.disconnect(true)でWiFiを止めるとAD変換ができる。
    WiFiを切断するとデータベースとの通信ができない。データベースとの通信を再開すると以前に使用していたセッションが残っていて、いろいろと問題になる。

  4. 非線形性が問題
    ウワサの非線形性について気になったので、電池の放電特性とは別に、ADコンバータの特性を測定した。
    ADC入出力特性

    AD変換値analogRead()の代わりにanalogReadMiliVolts()関数を検討する。
    工場出荷段階で校正されているらしいが、正確な値がほしければ使用する前に補正が必要らしい。
    入力電圧Viが0.5[V]未満では電圧の測定ができていない。AD変換値(analogRead())が0だった区間なので、どうしようもない。
    入力電圧Viが0.5[V]以上3.1[V]以下であれば直線性は改善されている。入力電圧Viより40[mV]程度多めに表示されるが、近似式を見ると一次式で近似できている。
    電池の電圧を測定する程度には使えそうだ。
    ADC入出力特性 ADC入出力特性


[結論]

どちらかというとデータベースの問題

マイクロコントローラESP32とデータベースの接続が切れた件であるが、WiFiのON/OFF、データベースの接続/切断が原因になっている。
10:00ころにデータベースとの接続に問題が発生し、原因を調査したがよくわからなかった。10:40にESP32とデータベースを再起動した結果、記録を再開した。12:40ころに再びデータベースとの接続に問題が発生した。ESP32はそのままとし、データベースのみを再起動し、記録を再開できることを確認した。
  1. WiFiを切断する方法
    WiFi.disconnect()の引数はtrueにする。
    WiFi.disconnect(true);//disconnect(),disconnect(false)はダメらしい
    ....
    WiFi.begin(ssid,password);//WiFiに再接続
    
  2. データベースを切断するタイミングが問題
    conn.execute(sql); conn.close(); WiFi.disconnect(true);
    のように連続して処理をすると、データがデータベースに記録されないときがある。記録されるときもある。
    conn.execute(sql); delay(xxxx); conn.close(); WiFi.disconnect(true);
    のようにconn.execute(sql)を実行した後、conn.state()を確認したが、0(no error)だった。 直ちにconn.close()を実行すると、conn.exe()が実行途中でデータベースを切断することになり、データが記録されない。
    遅延時間100mSにするとデータを失う頻度は減るが、皆無ではない。
    遅延時間500mSにするとデータの欠落はなくなった。 何かのフラグを確認するのが正しいと思うが、該当するフラグが見つからない。 接続するデータベースの応答速度に依存はずだが、遅延時間の最適値は確かめていない。

  3. データベースが切断できていない
    conn.close();WiFi.disconnect(true);でデータベースは切断できたと思っいたが、そうではないらしい。
    (WiFiに接続)-(PostgreSQLへ接続)のたびに新しいセッションをつくっているらしい。
    PostgreSQL側でプロセスを見ると
    ps aux|grep postgres
    simplepgsql

  4. 定時計測ができていない。
    遅延時間60秒をdelay(60000)として1分間隔で電圧を測定しようと思ったが、1分間隔でない。
    WiFiやデータベースの接続時間が一定でないので、前回測定からの待機時間は60〜70秒の間になっている。

[参考]
ESP32 Series Datasheet (https://espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf)

ESP-IDF Programming Guide
Analog to Digital Converter (ADC)
(https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/adc.html)


ラジオペンチ ESP32のアナログポートの特性調査-入力感度特性( http://radiopench.blog96.fc2.com/blog-entry-1034.html)

kohacraftのblog ESP32のADCでキャリブレーションされた精度の良い電圧値を取得する方法 ( https://kohacraft.com/archives/202202091047.html)

kohacraftのblog ESP32-DevKitCのDeepSleepが結構電流を消費しているので原因を調べてみた( https://kohacraft.com/archives/202104231107.html)

ESP32を電池2本くらいで動作させるための電源回路(昇降圧DCDCコンバータ)を作りました( https://kohacraft.com/archives/202104041320.html)

Lang-ship ESP32のArduino Core analogRead()関数検証( https://lang-ship.com/blog/work/esp32-arduino-core-analogread/)

mgo-tec電子工作 ESP32 の Wi-Fi のみ OFF および温度・湿度・気圧センサー BME280 の再調整など( https://www.mgo-tec.com/blog-entry-wifi-off-bme280-readjust-esp32.html)

知的好奇心 for IoT ESP8266やESP32でDeep SleepをWiFiの電波が混んでいる場所で使うときは、接続や送信でタイムアウト処理を行いDeep Sleepを実行する前にWiFiの接続を切る必要がある( https://intellectualcuriosity.hatenablog.com/entry/2021/03/31/194625)

ボクにもわかる電子工作のブログ 8か月以上の長期間動作を確認! 超省エネIoTセンサESP32-WROOM-32( https://bokunimo.net/blog/esp/21/)