ESP32の内蔵ADC(A/Dコンバータ)を何も考えずに使うと精度が出ない。注意点をまとめた。
ESP32のADCには少々クセあり
MicroPythonでESP32内蔵ADC読み値をマルチメータの測定値と比較して比例係数で電圧に変換しようとしたが上手く行かず、変だなと思って調べていたところ公式サイトのフォーラムを見つけた。
上記サイトにはESP32内蔵ADCを実測した人がちょっと残念な形をしたグラフをupしている。そのグラフによると入力電圧が小さい時に読み値が0に張り付いてしまうような挙動が見られ、つまりESP32内蔵ADCの読み値は単純に比例係数掛けただけでは電圧に変換出来ないことが分かった。
基準電圧のキャリブレーション値と電圧変換API
更に調べてみるとESP32内蔵ADCの精度改善に関する解説が公式ドキュメントに見つかった。
このドキュメントには、ESP32が持っている基準電圧の公称値は1100mVだが実際には1000mV〜1200mVの範囲でバラツキがあり、2018年以降に製造されたESP32にはチップ内のeFuseと呼ばれる領域にキャリブレーション値が書き込まれているとの記述が。そして電圧値への変換は、一次式y = coeff_a * x + coeff_b(xはADCの読み値)によって行うとも記載されており、APIが用意されているとある。ただそれ以上の詳しい事は書かれておらず、具体的な所はAPI関数のソースを追っかけないと分からなかった。このあたり、一次式の係数などについて調べた内容は別記事にまとめてある。
ADCの読み値を電圧に変換するサンプルプログラム
IDF開発環境と一緒にインストールされるサンプルプログラムにはADCの電圧変換APIを使った物がある。細かい事は置いといて、とにかくサンプルプログラムを動かしてみた。
このサンプルプログラムにはADCから値を読み出して電圧へ変換する一連の動作が書かれている。IDFがインストールされていれば、以下の一連のコマンドでIDFでビルド・フラッシュ書込み・実行までを一気に出来る。
cd /path/to/idf/
source export.sh
cd examples/peripherals/adc
make flash monitor
注意点は2点。
- makeコマンドを実行する前にsource export.shを実行すること
- ビルド開始時にプロジェクト設定メニューが立ち上がるが、何もせずにqを押して終了させればOK
ADC読み値と変換後のmV値の対が表示される
上記プログラムはデフォルトでGPIO34を読みに行くので、プログラムの動作中にGPIO34に0〜1Vの電圧を印加して測定を行う。上の例のようにプロジェクトのフォルダでmake monitorを実行するか、picocomなどのシリアルターミナルを115.2kbpsで繋げばOK。すると、ADCの読み値(Raw:)を基準電圧のキャリブレーション値を使って変換した電圧値(Voltage:)の対が表示される。
Raw: 1187 Voltage: 360mV
Raw: 1191 Voltage: 361mV
Raw: 1193 Voltage: 361mV
:
マルチメータを当ててプログラムから出力される電圧値と比較すると、0V付近でなければ値はほぼ一致している感じで変換はうまく行っている印象。
プログラムでADCの読み値を電圧に変換するためのAPI
上記サンプルプログラムでは、esp_adc_cal_raw_to_voltageというAPI関数を呼び出すことによってADCの読み値をmV単位の電圧に変換している。
Arduinoなら同様のAPIが使える。公式GitHubに置かれているesp_adc_cal.hの中にesp_adc_cal_raw_to_voltage関数のプロトタイプ宣言があり、IDFと同じ作法でOK。
しかしMicroPythonではこのAPIに相当する物は現時点で用意されておらず、自前で変換を行う以外に方法は無さそうだ。
まとめ
ESP32のADCを使う際に電圧値を取得したい場合は変換が必須だ。IDFとArduinoではADCの読み値を電圧に変換するためのAPIが用意されているが、MicroPythonでは自前で対応が必要。というわけでMicroPythonについては別記事にまとめた。
コメント