はじめてNerves(10) I2C デバイス INA226 で電流・電圧・電力を測ってみる (1/3)

今回は直流の電流や電圧を測る回路とソフトウェアを作ってみます。計測する本体には Raspberry Pi と BeagleBone Green を使ってみました。センサとの I/F は I2C です。今回は計測センサとそのボードの使い方、さらにI2Cの動作について説明します。プログラミングは次回以降に説明します。なので驚くべきことに、この記事は Elixir や Nerves とは関係ありません。

続きはこちら。

- [はじめてNerves(11) I2C デバイス INA226 で電流・電圧・電力を測ってみる (2/3)](https://qiita.com/kikuyuta/items/dd1c76059454fbfd3957)
- [はじめてNerves(12) I2C デバイス INA226 で電流・電圧・電力を測ってみる (3/3)](https://qiita.com/kikuyuta/items/7cf9ff993671b770d10c)

# はじめに
ハードウェア小物を色々扱ってると電流なり電圧なりさらには電力なりを計測したくなります。今回は知人に「ラズパイの消費電力を計測したい」というお悩みを聞いたのがきっかけで作ってみました。

元のリクエストがラズパイの消費電力ということでしたので、より一般にコンピュータボードに電源が供給される直流電源の電流と電圧を計測することにします。ですのでここでの話はラズパイの電力に限らず直流の電流・電圧を計測するならなんにでも応用が効きます。


## 注意１
この記事で用いるセンサボードは保護回路等が入っていないそうです。配線ミス等で容易に回路を破壊します。場合によっては焼けて火傷をしたり火災を起こす可能性もあります。ハードウェアに自信のある方のみにオススメします。またハードウェアに慣れている方も通電する前には回路が正しいか十分にチェックを行って下さい。

## 注意2
計測対象が直流と言っても短い時間で電流・電圧が変化するような場合には使えません。センサで検出ができるための十分な安定度が必要です。電源の場合でいうと、脈流になってないような十分に平滑されていてリップル成分が小さくないと正しい計測はできません。

今回使うセンサはデフォルトで電流・電圧を計測するのにそれぞれ1.1ms程度かかりますし、最速でもそれぞれ140μsかかります。変化が起こるような場合は、これらの変換時間を参考にして計測に適しているかどうかを判断して下さい。

# ハードウェア

この節では、電流・電圧とその他の機能を持つセンサチップの紹介、およびそのチップを基板にした商品、さらにそれをRaspberry Pi や BeagleBone に接続する方法を述べます。

## センサ
電力を直接計測するのではなく、電流と電圧とを計測してその積で電力を求めます。

TI から [INA226 というセンサチップ](https://www.tij.co.jp/product/jp/INA226) が出ています。これは基本は電圧計測のチップで、入力がアナログマルチプレクサで2回路あります。まず、この一方をそのまま使って電圧計測します。そして、電流を測りたい回路に直列にシャント抵抗と呼ばれる値の小さな抵抗を挿入して、もう一方の入力でそこに起こる電圧降下を計測して電流を計測します。以下のブロック図で内部のスイッチが V 側に倒れているときが電圧を、I 側に倒れているときが電流を測る状態です。

![INA226block](https://www.tij.co.jp/ds_dgm/images/fbd_sbos547a.gif "INA226のブロック図")

### 計測点
ちなみに細かい話になりますが、上のブロック図にあるように、シャント抵抗は電源側でも接地側でも計測はできます。私は負荷の接地側にシャント抵抗を入れたくないので、この記事ではこのブロック図の点線側の配線を採用しています。さらに、電圧の計測は電源装置側ではなく負荷にかかる値を見たいので、VBUSピンは負荷の電源側のシャント抵抗を挟まない点に接続しています。

## センサ基板
このチップを搭載したボードが [Strawberry Linux](https://strawberry-linux.com/) から販売されていますので、それを使ってみました。電流計測ボードには[計測可能な最大電流と計測精度とによっていくつか種類](https://strawberry-linux.com/pub/currentmeasure.pdf)があります。今回は

- 電流だけでなく電圧も測れる（電力を算出したいため）
- 値を I2C で取り出すことができる
- 非絶縁と絶縁との両タイプがある

という観点で [INA226PRC](https://strawberry-linux.com/catalog/items?code=12226) （非絶縁）と [INA226PRCiso](https://strawberry-linux.com/catalog/items?code=10226) （絶縁）を使いました。なお、最後の観点は、測りたい対象と計測マシンとが同一の接地をしている場合とそうでない場合があるためです。

### 非絶縁型センサボード
先に非絶縁型の方について述べます。こちらの方が安いのでお手軽です。しかしチップの電源の接地側と計測する対象の接地側とが接続されてないとならないという制限があります[^Ground]。そうでない場合は後で述べる絶縁型のボードを使う必要があります。

[^Ground]: 正確には「電圧を測りたい対象の低い側の電圧とセンサチップの接地側が接続されてないとならない」です。

測りたい対象との配線は [INA226PRCモジュール説明書](https://strawberry-linux.com/pub/ina226prc-manual.pdf) の全体配線図を参考にして下さい。

私は以下のように作成しました。これは Raspberry Pi Zero W が、自分の消費電力を自分で計測するような構成になってます。

![IMG_0060.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/34cead34-5c49-6bc1-eb6d-a2bd93db2510.jpeg)

INA226PRC 基板への接続は以下のようにしています。

- 左下が USB のメスコネクタです。計測対象のラズパイに使ってたACアダプタが使えるようにしてます
- 左上がラズパイの電源につなげる線です。
- 右側がラズパイの I2C インタフェースにつなげる線です。今回は Grove コネクタを使用しました。

![ina226prc.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/659d2a46-0fdb-8296-d88d-42fa37bb460a.jpeg)

基板の左側のピンはそれぞれ以下のように接続しています。

- V- (GND): ACアダプタの接地側、およびラズパイの電源の接地側（0V 側、ラズパイの pin 6）
- ISENSE-: ラズパイの電源の＋側（5V側、pin 6）、および基板の V+
- ISENSE+: ACアダプタの＋側（5V側）
- V+: 基板の ISENSE-

基板の右側のピンは I2C インタフェースに接続します。それぞれ以下のように接続しています。

- VS: ラズパイの 3.3V 電源 (pin 1)
- SCL: ラズパイの I2C の SCL (pin 5)
- SDA: ラズパイの I2C の SDA (pin 3)
- AL: 接続せず
- GND: ラズパイの GND (pin 6)

あと、基板内で一部のランドを半田でショートしてあります。これはI2Cのアドレスを決めるためです。この回路では 0b01000000 (=0x40 =64) になっています。詳しくは後述します。
![jumper.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/d2a5d8a5-0670-b887-b9b5-ac1a02ba1a0f.jpeg)


### 絶縁型センサボード
次に絶縁型の方について述べます。こちらはチップの回路（電源やI2Cインタフェース）が計測対象と電気的に絶縁されており、非絶縁型センサボードのような制約がありません。ただし、こちらの基板の方が価格が高いです。

測りたい対象との配線は [INA226PRCisoモジュール説明書](https://strawberry-linux.com/pub/ina226prciso-manual.pdf) の全体配線図を参考にして下さい。

私は以下のように作成しました。これは BeagleBone Green (BBG) が Raspberry Pi 4B (RPi4) の消費電力を計測するような構成になってます。この回路はオレンジ色の破線で電気的に絶縁されてます。ですので、BBG の回路と RPi4 の回路とで接地線を共通にするとかは考えなくて良いです。

![IMG_0134.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/8b3d23a9-5e94-34c2-1e32-2703a39e1269.jpeg)

INA226PRCiso 基板への接続は以下のようにしています。

- 左下が USB のメスコネクタです。これは先程のUSBコネクタと同じもので、ラズパイ4ではなくラズパイ3に使ってたACアダプタが使えるようにしてます。
- 左上がラズパイの電源につなげる線です。
- 右側がラズパイの I2C インタフェースにつなげる線です。こちらも Grove コネクタを使用しました。

![IMG_0133.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/762b3ba8-938c-4776-6ffb-d1a2abe8b3a5.jpeg)

基板の左側のピンはそれぞれ以下のように接続しています。この INA226PRCiso 基板の接続は先程の INA226PRC 基板での接続と同様です。

- V- (GND): ACアダプタの接地側、およびラズパイの電源の接地側（0V 側、ラズパイの pin 6）
- ISENSE-: ラズパイの電源の＋側（5V側、pin 6）、および基板の V+
- ISENSE+: ACアダプタの＋側（5V側）
- V+: 基板の ISENSE-

基板の右側のピンは I2C インタフェースに接続します。それぞれ以下のように接続しています。この INA226PRCiso の I2C 接続は先程の INA226PRC と **まるで異なる** ので注意が必要です。

- GND: Grove の GND（ラズパイの場合は pin 6）
- SDA: Grove の I2C の SDA（ラズパイの場合は pin 3）
- SCL: Grove の I2C の SCL（ラズパイの場合は pin 5）
- VDD: Grove の 3.3V（ラズパイの場合は pin 1）
- PDIF: 接続せず

あと、I2Cのアドレスを決めるため基板内で一部のランドを半田でショートしてあります。この回路では先ほどとはずらして 0b01000001 (==0x41 ==65) にしています。これも詳しくは後述します。

![jumper.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/aa1324f3-6973-5648-36b3-9c979848bfb4.jpeg)

さらにもう一箇所、PDIF ピンの処理が必要です。これは基板上にショート用のランドがあります。

![jumper2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/91c0ca1e-94f3-c0cd-dcd7-b4b59b2c0d2c.jpeg)

これを以下のようにハンダでショートすればOKです。PDIF がオープンのままだと INA226 へ電源を供給している DC-DC コンバータが on/off を繰り返してしまって電源がふらついてしまい、正しい計測ができません。

![jumper3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/e09dad8b-e721-619c-e712-09cca5929fde.jpeg)

#### ADM3260の日本語マニュアルの間違いについて
このADM3260のPDIFの信号の扱いについては英語のマニュアルと日本語のマニュアルの記述が違ってます（2021.03.10 現在）。

- [英語版マニュアル](https://www.analog.com/media/en/technical-documentation/data-sheets/adm3260.pdf)
 - Power Disable. When PDIS is tied to VIN, the power supply enters low power standby mode. When PDIS is tied to GNDP, the power converter is active.
- [日本語版マニュアル](https://www.analog.com/media/jp/technical-documentation/data-sheets/ADM3260_jp.pdf)
 - 電源ディスエーブル。PDIS を VIN に接続すると、電源は低消費電力のスタンバイ・モードになります。PDIS を GNDISO に接続すると、電源コンバータがアクティブになります。

この「電源コンバータを動かすときに接続する先」となってる GNDP と GNDISO は、2種類ある接地ピンです。電気的に回路が2つに分離しているので接地も2種類あります。GNDP と GNDISO はそれぞれ、1次側（電源供給側）と2次側（1次側と分離されてる絶縁側）の接地を示しています。

これについては **英語版が正しく日本語版が間違い** です[^manual]。今回使った基板 INA226PRCiso も英語版のマニュアルに則して1次側の GNDP に接続されていました。自分で回路を作る方は十分に注意して下さい。何かと原文に当たるほうが良いですね。

[^manual]: これ英語版をベースに日本語版に翻訳したのでしょうから、こんな間違いは起こりにくそうなものです。ここから推測ですが、もともとは英語版も間違っていたのではないでしょうか。それの翻訳をしたのが残っていて、英語版は後で修正されたけど日本語版には反映されていないのかと想像してます。英語版が Rev. E で日本語版が Rev. 0 とだけあって、ドキュメントの履歴に関する記載がほとんどないのでこれ以上はわからないですが。

# I2C プログラミング
INA226 は I2C でアクセスできます。この記事では基本的な使い方を記述します。

## I2C アドレス
INA226 の I2C スレーブアドレスは電源ON時のピンの状態で16通りが選択できます。以下のように A0 ピンと A1 ピンとを GND, VS, SDA, SCL のどれかに接続しておくとアドレスが決まります。

|A1 |A0 |アドレス|
|:-:|:-:|:-:|
|GND|GND|0b01000000|
|GND|VS |0b01000001|
|GND|SDA|0b01000010|
|GND|SCL|0b01000011|
|VS |GND|0b01000100|
|VS |VS |0b01000101|
|VS |SDA|0b01000110|
|VS |SCL|0b01000111|
|SDA|GND|0b01001000|
|SDA|VS |0b01001001|
|SDA|SDA|0b01001010|
|SDA|SCL|0b01001011|
|SCL|GND|0b01001100|
|SCL|VS |0b01001101|
|SCL|SDA|0b01001110|
|SCL|SCL|0b01001111|

これにより、別のI/Oとのアドレスのバッテングを回避しやすくなっています。さらに他に I2C のデバイスがなければ、ひとつの I2C バスに最大で16個の INA226 を接続することが可能になってます。

なお、INA226PRC / INA226PRCiso 基板上ではシルク印刷とピンとが以下の対応になってます。

- 1: VS
- G: GND
- C: SCL
- D: SDA

### スレーブアドレスの設定例 (0x40)
非絶縁型の INA226PRC 基板でさきほど以下のようにハンダ付けしました。

![jumper.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/d2a5d8a5-0670-b887-b9b5-ac1a02ba1a0f.jpeg)

これは A1 と A0 とを GND に接続することに相当しています。このためスレーブアドレスが 0b01000000 になってます。

### スレーブアドレスの設定例 (0x41)
絶縁型の INA226PRCiso 基板ではさきほど以下のようにハンダ付けしてました。

![jumper.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/aa1324f3-6973-5648-36b3-9c979848bfb4.jpeg)

写真が見にくいですが、A0 側を非絶縁型のボードとは違うランドにはんだ付けしてショートしています。これは A1 を GND に A0 を VS に接続することに相当しています。このためスレーブアドレスが 0b01000001 になってます。

## 初期化（レジスタ0）
レジスタ0 の 16bit を設定するとセンサの動作を制御できます。まず遊んでみようという場合には何も書き込まずにデフォルト値のままでも大丈夫です。

- D15: 1を入れるとハードウェアリセットしたのと同じ状態になる
- D14〜D12: 機能は割当たっておらず 100 に固定
- D11〜D09: 平均値を出すサンプリング数
 - デフォルトは 000 でサンプリング数が1（つまり平均を求めず計測ごとに値を出力する）
 - 111 にすると 1024 回計測して、その平均値にする
- D08〜D06: 電圧計測側のサンプリング時間
 - デフォルトは 100 で、1.1msごとに計測する
- D05〜D03: 電流計測側のサンプリング時間
 - デフォルトは 100 で、1.1msごとに計測する
- D02〜D00: 動作モード
 - デフォルトは 111 で、電流と電圧とを交互に計測する

これのレジスタ0は読み出すこともできて、デフォルトの場合は上の 0b0100000100100111 (== 0x4127) になります。ハードウェア・ソフトウェアを作って一番最初はレジスタ0を読んでみてこの値が見えるか確認しましょう。

## 電流用計測値（レジスタ1）
レジスタ1を読み出すと電流の計測値がわかります。正確に言うと、これは電圧を計測した結果です。シャント抵抗での電圧降下を計測するように回路が組んであるので電流に比例した電圧を計測することになります。

これは16bitの2の補数表現になってます。LSB 1bitが 2.5μV に相当してます。INA226PRC 基板や INA226PRCiso 基板では 0.025Ωのシャント抵抗を使っています。よってオームの法則 V = IR より、1bitが $2.5μV/0.025Ω=0.1mA$ の大きさに相当します。正負の計測が可能ですのでどっち向きの電流も計測できます。

なおこのレジスタ1は読み出し専用です。

### シャント抵抗の熱容量について
値の最大は 0x7fff で $2.5μV\times (2^{15}-1) = 81.9175mV$ です。つまり -80mV〜+80mV より若干広い範囲を計測します。シャントに0.025Ωの抵抗を使った場合は最大で 3A 強を測ることができます。

この抵抗を使った場合に、計測の最大値に近い電流を流しすと 0.27W 程度の発熱をします。これは普通に売ってる抵抗の容量 1/4W を超えます。抵抗が発熱に耐えられるように十分に大きな容量の抵抗を用いて下さい。あと、抵抗器が発熱して温度が上がると抵抗値も上がり計測誤差が増えます。その意味でも余裕のある容量の抵抗を用いて温度変化が小さくなるようにすると良いでしょう。

例えば先程のシャント抵抗でINA226の計測限界まで図ろうとすると、シャント抵抗での消費電力は 0.25W を超えます。ですので 1/4W を超える容量の抵抗であることが必須です。そして誤差のことを考慮するなら 1/2W よりも、より大きな 1W 以上の抵抗を用いるほうが良いでしょう。

## 電圧用計測値（レジスタ2）
電圧を測るレジスタはMSBが0で残りの15bitが値です[^2s-complement]。レジスタ1と異なり負の値は測れません。LSB 1ビットが1.25mVに相当します。最大値は 0x7fff で 40.96V 程度になります。

[^2s-complement]: レジスタ1に合わせて考えると、レジスタ1同様の2の補数表現だけども負の値は測れない… という解釈でも結構です。

なおこのレジスタ2も読み出し専用です。

## その他のレジスタ
レジスタ1とレジスタ2だけで電流・電圧が計測できます。この他にいくつか機能があるので簡単に紹介します。

### 電流計測の補正（レジスタ4〜レジスタ5）
シャント抵抗の抵抗値には若干の誤差があります。1%の誤差の抵抗は、抵抗としては高精度な方です。しかしながら計測に使うと、電圧を読んだ値を電流に換算したときに最大1%の誤差を含むことになります。

これを補正するためにソフトウェアで補正しても良いですし、INA226内部にハードウェアによる補正用の乗算ができるようになってますのでこれを使うのもありです。レジスタ5に補正用の値を入れておくとレジスタ4に補正された値が入ります。2048 が倍率1.0を表現しますので、$R_4=R_1\times R_5/2048$ の計算がハードウェアで行われます。

実際に補正する場合には、別途正確な電流計を用意してそれぞれの計測値から倍率を求めることになります。ただしこれは面倒ですので、簡単な実験に使うなら 1% の誤差は許容範囲でしょう。

この他、シャント抵抗との関係でレジスタ1には直ちに読めるようなきれいな値にならないような場合に、レジスタ5に適切な値を入れておくことでレジスタ4を直接読めるような値になるように仕掛けることも可能です。

例えばシャント抵抗に2mΩを使うとレジスタ1のLSB 1bitは $2.5μV/0.002Ω=1.25mA$ となります。この値が100になっても125mAとはすぐには読み取れません。ここでレジスタ5に2560を入れおくと、レジスタ1が100の場合にレジスタ4に125と出てくるので直接 mA 単位で読むことが可能になります。

なお、レジスタ4は読み出し専用、レジスタ5は読み書き可能です。

### 電力の計算（レジスタ3）
さらに電力の計算も INA226 内部で計算できるようになっており、レジスタ2とレジスタ4の積を20000で割った商がレジスタ3に残ります。$R_3 = R_2\times R_4/20000 = R_2\times R_1\times R_5/2048 /20000$ となります。

例えば、補正をせずにレジスタ1とレジスタ2の積だけ欲しい場合はレジスタ4に 40960 (==0xa000) を入れておけば $R_3 = R_2\times R_1/1000$ となり、ソフトウェアで計算しなくても積が計算できます。レジスタ4のデフォルト値は0ですので、値を入れないとレジスタ3の値は常に0になります。

なお、レジスタ3は読み出し専用です。

### アラートの設定（レジスタ6〜レジスタ7）
INA226には、一定の値を仕掛けておいて、それを逸脱するとアラートピンが反応する機能があります。アラートピンを GPIO の入力に接続しておけば CPU に割込をかけることができます。

レジスタ6ではどの条件でアラートを立てるかを決めます。過大電流、過小電流、過大電圧、過小電圧、過大電力、などなど。レジスタ7にはアラートを判断する比較のための値を入れておきます。

なお、レジスタ6もレジスタ7も読み書き可能です。

### メーカ番号、デバイス番号、リビジョン番号（レジスタ254〜レジスタ255）
レジスタ254にはメーカ番号 0x5449 が入っています。

レジスタ255の上位12ビットにはデバイスIDが、下位4ビットにはリビジョン番号が入っています。INA226のリビジョン0の場合は 0x2260 です。

レジスタ255もレジスタ256も読み出し専用です。

# まとめ
今回は直流回路の電流と電圧を計測するセンサINA226と、それを搭載したボード INA226PRC/INA226PRCiso のご紹介、ボードコンピュータの電源の消費電力を計測する回路の構成、INA226のI2Cインタフェースの動作について記載しました。

ここで力尽きたので Elixir/Nerves によるプログラミングは次回にします。Elixir をお使いにならない方はここでさようならです。アルケミストの方々は次回を楽しみにしていて下さい。

# 参考文献
- [はじめてNerves(11) I2C デバイス INA226 で電流・電圧・電力を測ってみる (2/3)](https://qiita.com/kikuyuta/items/dd1c76059454fbfd3957)
- [はじめてNerves(12) I2C デバイス INA226 で電流・電圧・電力を測ってみる (3/3)](https://qiita.com/kikuyuta/items/7cf9ff993671b770d10c)
- [はじめてNerves(0) ElixirによるIoTフレームワークNervesがとにかく動くようになるためのリンク集](https://qiita.com/kikuyuta/items/9dee85c32004c8e827e7)
- [Texas Instruments INA226](https://www.tij.co.jp/product/jp/INA226)
- [Analog Devices ADM3260](https://www.analog.com/jp/products/adm3260.html)
 - [英語版マニュアル](https://www.analog.com/media/en/technical-documentation/data-sheets/adm3260.pdf)
 - [日本語版マニュアル（間違いあり、本文参照）](https://www.analog.com/media/jp/technical-documentation/data-sheets/ADM3260_jp.pdf)
- [Strawberry Linux](https://strawberry-linux.com/)
 - [Strawberry Linux 製 INA226PRC](https://strawberry-linux.com/catalog/items?code=12226)
 - [Strawberry Linux 製 INA226PRCiso](https://strawberry-linux.com/catalog/items?code=10226)
- [ラズパイのピン配列](https://pinout.xyz)