I2C接続、12bit 4ch、PGA付きと便利なTI製ADS1015を使用した制作例をよく見かけます。
ここでは自分の制作に使用するにあたり調べたことをメモします。
TI ADS1015について
CT(カレントトランス)を使った電力計の制作を考えていたのですが、CTの出力電圧はモノにもよりますが計測値0.1A(≒10W)で出力電圧33mVなどと小さく、また交流出力のため負電圧への対応が必要であり信号の扱いがやや面倒です。ADS1015は、そんな要件に適したデバイスです。
ADS1015の主な特徴は以下の通りです。
- 12bit分解能のA/Dコンバータが4ch (差動入力で2ch)
- I2Cでマイコンとデジタル接続が可能
- 設定ピンの接続先を変えることでI2CデバイスIDを4種類に変更できる→一つのI2Cインターフェースに対して最大4つ接続可能
- PGA (プログラマブル・ゲイン・アンプ)が内蔵されていて、微小信号を外付け部品なしに増幅して取り込める
- 最大サンプリングレートは3300サンプル/sec
PGAがなくてもオペアンプで増幅回路を組めば済む話ですが、私の経験上素人が特に微小な信号を扱う回路を組むとノイズであったり誤差であったりと余計な壁に当たる可能性が高く、ワンチップで完結しているADS1015は魅力的です。
兄弟製品としてADS1115という16bit分解能の製品もありますが、こちらは最大サンプリングが860サンプル/secとなり、アプリケーションを選ぶ感じです。
国内では秋月電子がモジュール化した製品(adafruit製の互換製品?)を扱っていますね。
ADS1015使用 PGA機能搭載12bitADコンバーター: 半導体 秋月電子通商-電子部品・ネット通販
ハードウェア構成
今回は以下で試しました。いずれも秋月電子で手に入ります。
AE-ATMEGA328-MINIはArduino Pro Mini互換基板で、I2Cは基板シルクでA4, A5のピンです。ジャンパJ2, J3が接続された状態(プルアップされた状態)にします。
ADS1015基板側でもジャンパをショートさせればプルアップ抵抗を有効にできるようですが、マスター側でやるのがスジだと思います。
測定する電圧源は単三乾電池(エネループ)とし、A0、A1に接続します。将来的に交流で出力されるCTの信号を受け取りたいので差動入力を選択しています。
I2CでADS1015を設定し、結果を読み出す
Arduinoの場合、便利なライブラリを使うことで非常に簡単にデータを得られます。しかしデバイス専用ライブラリは便利な反面、細かな設定であったり機能の詳細を隠蔽してしまうため、ちょっと凝ったことをしようと思ったとたん融通が利かなくなるうえ、覚えた知識の応用も難しくなります。
今回はI2Cこそライブラリの力を借りますが、ADS1015との通信は直接プログラムすることにします。
サンプリングモードの設定
ADS1015は、動作設定をConfiguration registerに書き込むことで設定します。プログラムの手順としては以下です。
- 対象のデバイスIDに対してI2C通信を開始する
- 0x01を送信して、書き込み先をConfiguration registerに設定する
- Configuration registerの内容を、上位8bit、下位8bitの順番に送信する
- I2C通信を終了する
Configuration register (16bit)各bitの意味は以下の通りです。
幅広い設定が可能なので詳細はデータシートを見てください。以下は概要です。
Field | 内容 |
OS | ReadかWriteかで意味が異なってきます。シングルショットの時は1を書くとサンプリング開始です。連続変換ならどちらでもOK ("No effect"です) |
MUX | 入力チャネルの選択、および動作モード(シングルエンド又は差動入力)の切り替えを行います。デフォルト000でA0とA1ピンでの差動入力で動作します |
PGA | プログラマブル・ゲイン・アンプのゲインを設定します。デフォルトは010で±2.048Vです |
MODE | 連続変換かシングルショットかを選択します。0で連続変換です |
DR | サンプリング周期を設定します。デフォルトは100で1600サンプル/秒です |
COMP_MODE | 内部コンパレータの設定を行います。割愛。 |
COMP_POL | 内部コンパレータの設定を行います。割愛。 |
COMP_LAT | 内部コンパレータの設定を行います。割愛。 |
COMP_QUE | 内部コンパレータの設定を行います。割愛。 |
今回の例では以下としました。
データの読み出し
Configuration registerに適切な設定を行えば、ADS1015は指定した周期でサンプリングを行い、データを逐次Conversion registerに書き込みます。これの読み出し手順は以下です。
- 対象のデバイスIDに対してI2C通信を開始する
- 0x00を送信して、I2C通信で読み取るレジスタのアドレスをConfiguration registerに設定する
- 送信を終了する
- 上位8bit、下位8bitの順にデータを読み取る
- 上位8bitのデータを8bit分ビットシフトさせて、下位8bit分のデータと足し合わせることで結果を得る
Conversion registerは以下の通りで、12bitのデータが上位詰めで格納されています。
12bitのデータを一度に読み出せないため、8bitずつ読み取ったデータを以下手順で処理します。
一度読み出し先のアドレス0x00を設定しさえすれば、チャネル設定を変更しない限りステップ4~5を繰り返すことで最新のデータを読み出すことができます。
ところで、ADS1015は4chのADコンバータではありますが、内部マルチプレクサで回路を切り替えているだけでADCコア自体は1個しか搭載されていません。Configレジスタでチャネルを指定して、変換したデータを読み取るというプロセスなので、3300サンプル/秒は1chあたりの最大サンプリングです。チャネル変更→読み出しには複数回のI2C通信を行う必要があるので、4chすべてを読み出す場合の最大サンプル数はかなり少なくなるでしょう。このあたりは安いオシロスコープと似たような作りですね。
サンプルプログラム
上記設定の動作確認を以下プログラムで行いました。A0~A1間の電位差を計測し、シリアル通信で電圧出力を行います。I2C通信および内部での変換処理を1サイクル実行する時間も併せて計測し出力します。
#include <Wire.h> #define ADS1015_ADRS 0x48 // Device I2C ID int data, data_L, data_H; // For receiving data from ADS1015 unsigned long t, t1; // For time measurement float voltage; // For output void setup() { Serial.begin(9600); // Start serial communication, 9600bps Wire.begin(); // Start I2C communication Wire.setClock(400000); // Set I2C data rate to 400kHz Wire.beginTransmission(ADS1015_ADRS); Wire.write(0x01); //Set target register, Config register Wire.write(B00000010); //Upper byte Wire.write(B11100011); //Lower byte Wire.endTransmission(); Serial.println("Init done"); Wire.beginTransmission(ADS1015_ADRS); Wire.write(0x00); // Set target register, Data register Wire.endTransmission(); } void loop() { t1 = micros(); Wire.requestFrom(ADS1015_ADRS,2); while(Wire.available()){ data_H = Wire.read(); data_L = Wire.read(); } data_H = data_H << 8; data = data_H + data_L; voltage = data * (4.094/32767); t = micros() - t1; // Get acquisition time in micro sec Serial.print("V="); Serial.print(voltage); Serial.print(" Acquisition time(us)="); Serial.println(t); delay(500); }
結果は以下の通りです。
1回の読み出し・データ処理で120μ秒程度かかっています。
実は、最初に試したときは1回の処理で600μSec程度かかっていました。ADS1015の最大サンプリングは3300サンプル/秒のため、1読み出しあたり約300μSecを超えてしまうと最大サンプリングでデータを読み取れなくなってしまいます。I2Cの通信速度を最高速の400kHzに変更(デフォルトは100kHz)したり、読み取るレジスタの指定を毎回行わない(一度指定すれば何度でも繰り返し読めることに後で気づきました)などの改善で120μ秒まで短縮しています。
最後の電圧変換するFloatの演算をある程度サンプリングした後に行うなど処理の工夫でまだ改善できるはずですが、とりあえずこれでADS1015の設定とデータ読み取りはできたので先に進むこととします。