ロジックアナライザでI2C 信号を見ると

INA226 と arduino の I2C 信号をロジックアナライザで見てみました。

コードは前回と同じものです。1秒ごとに4つのデータをゲットしています。

1

トリガは、SDA にかけました。Hi から Low になって信号が行くようです。

まず、I2C アドレス0x40 のレジスタ 0x02 を投げて、値が帰ってくる流れが見えます。読み出しには、1.7ms ほどかかっていることがわかりました。ビットの信号は、4us 程度のようです。SDAでビットが立っているのを判別しているようです。

 

たとえば、最初は INA226_REG_BUSVOLTAGE  (0x02) を読み出しているようで、値は16進数で 0x0E9E が帰ってきています。10進数では、3742 でこれに1.25 を掛けたものが mV になるので、4677.5 mV = 4.6775V ということですね。精度は、0.1mV ということです。

 

I2C のリアルタイムな生データを見るのは今回が初めてです。なかなか、IC同士で通話している感じがおもしろいですね。

1000分の1,2秒で、データを読み取っていて、0 と 1 の Hi と Low の信号のやり取りでそれをやっているというのが目で見えてわかりやすいです。ロジックアナライザって偉い存在ですね。

 

▼まとめ

・INA226 と arduino の I2C 信号を見てみた

・SDA の LOW にトリガーをかけて採取。

・スレーブアドレス+データ領域を指定すると、対応するスレーブから値が帰ってくる

・SCL にビットデータが流れ、SDA にデータ流れる感じ。両方ともHi になった部分が ビットが立つ感じ。

・ビット のHi になる時間は、4us ほど。

・1つのレジスタの読み出しには、1.7ms ほどかかる。

・呼び出しから応答までの間隔は、1ms ほど。0.7ms でデータをやり取りしている。合計で1.7ms

・安物のロジックアナライザでも十分現象を観察できた。

INA226 を arduino nano で

もう1月も終わりですね。なんだか速く月日が経つような気がします。

さて、今日は 先日作った INA226 の電流電圧センサーを I2C で arduino nano クローンにて計測してみました。

前回の調査で見つけた、ポーランドのサイトにいいチュートリアルがありました。

Korneliusz Jarzębskiのサイト
Dwukierunkowy cyfrowy czujnik prądu/mocy INA226

github
Arduino-INA226
https://github.com/jarzebski/Arduino-INA226

このGitHub のsimple のソースにライブラリを配置し、

./INA226_simple
├── INA226.cpp
├── INA226.h
└── INA226_simple.ino

INA226.cpp の記述を以下に変更。25mR のシャント抵抗の設定をします。

#include "INA226.h"
::
void setup() 
{
::
  // Calibrate INA226. Rshunt = 0.025 ohm, Max excepted current = 4A
  ina.calibrate(0.025, 1);
::

配線は以下のようにしました。ちょっとわかりにくいですが、Arduino の A5(SCL) と A4(SDA) をつないで、GND と 3.3V を VSS に入れます。あとは、負荷を電流計測にハイサイド側に付ける感じです。

arduino_ina226

シリアル通信を開くと、以下のようになっています。

Initialize INA226
-----------------------------------------------
Mode:                  Shunt and Bus, Continuous
Samples average:       1 sample
Bus conversion time:   1.100ms
Shunt conversion time: 1.100ms
Max possible current:  3.28 A
Max current:           3.28 A
Max shunt voltage:     0.08 V
Max power:             117.96 W
-----------------------------------------------
Bus voltage:   4.67875 V
Bus power:     0.01250 W
Shunt voltage: 0.00007 V
Shunt current: 0.00300 A

Bus voltage:   4.68125 V
Bus power:     0.01250 W
Shunt voltage: 0.00007 V
Shunt current: 0.00300 A

Bus voltage:   4.67750 V
Bus power:     0.01250 W
Shunt voltage: 0.00007 V
Shunt current: 0.00300 A

PC からのUSB 電圧は4.67V 程度のようです。3mA で12.5mW ということがわかりました。ちゃんと計測できているようですね。

arduino だと装備からLCDなどに出す用途で使えそうですね。データをどこかに飛ばすものであれば、ESP8266 が良さそうです。

 

IC 回路の電圧は3.3V でも5V でもOKです。LEDの負荷を arduino の 3.3V から取って計測してみると以下のようになりました。

Initialize INA226
-----------------------------------------------
Mode:                  Shunt and Bus, Continuous
Samples average:       1 sample
Bus conversion time:   1.100ms
Shunt conversion time: 1.100ms
Max possible current:  3.28 A
Max current:           3.28 A
Max shunt voltage:     0.08 V
Max power:             117.96 W
-----------------------------------------------
Bus voltage:   3.26875 V
Bus power:     0.00500 W
Shunt voltage: 0.00004 V
Shunt current: 0.00150 A

Bus voltage:   3.27000 V
Bus power:     0.00500 W
Shunt voltage: 0.00004 V
Shunt current: 0.00150 A

Bus voltage:   3.26875 V
Bus power:     0.00500 W
Shunt voltage: 0.00004 V
Shunt current: 0.00160 A

 

ちょっとコードを追加して、レジスターの値を取ってみました。

Initialize INA226
-----------------------------------------------
Mode:                  Shunt and Bus, Continuous
Samples average:       1 sample
Bus conversion time:   1.100ms
Shunt conversion time: 1.100ms
Max possible current:  3.28 A
Max current:           3.28 A
Max shunt voltage:     0.08 V
Max power:             117.96 W
-----------------------------------------------
INA226_REG_CONFIG          (0x00):16679 ---
INA226_REG_SHUNTVOLTAGE    (0x01):30 ---
INA226_REG_BUSVOLTAGE      (0x02):3749 ---
INA226_REG_POWER           (0x03):5 ---
INA226_REG_CURRENT         (0x04):30 ---
INA226_REG_CALIBRATION     (0x05):2048 ---
-----------------------------------------------
Bus voltage:   4.68250 V
Bus power:     0.01250 W
Shunt voltage: 0.00007 V
Shunt current: 0.00300 A

レジスター値は10進です。アベレージの回数とかも定数があるので便利ですね。

精度は、0.1mA  のようですね。PCB のあまり部分で作ったモジュールでも結構遊べました。あと、小さなパーツの半田付けの練習にもなりました。

 

▼参考サイト

http://denshi-kousaku.fan.coocan.jp/report030.html

 

▼まとめ

・ライブラリ便利!

・INA226 モジュールを使って、arduino で i2c にて電流電圧を簡単に取れる

・精度は、シャント抵抗次第で、0.025R だと0.1mA(100μA) の精度になるようです

・GND はIC回路と共通で測定で、電圧を測定する場合は、IC の VBUS 8pin に計測電圧をかける

・LSB とは一般的には、最下位ビットのことで、least significant bit の頭文字。

・これの分解能力は16ビットなので、0.025R だと電流は0.1mA で電圧は 1.25mV

・とりあえず、十分な精度です。

INA226 を RasPi の ruby でi2c

PCB が組みあがったのですが、これを RasPi で i2c するサンプルをググってみたら、いくつかありました。

RasPi は、i2c が使えるようにモジュールをロードしておきました。RasPi でi2c は初めて使います。無事に出来るでしょうか?

# lsmod
Module                  Size  Used by
★i2c_dev                 6027  0 
cfg80211              386508  0 
rfkill                 16651  1 cfg80211
rpcsec_gss_krb5        20958  0 
nfsd                  263569  2 
snd_bcm2835            18649  0 
snd_pcm                73475  1 snd_bcm2835
snd_seq                53078  0 
snd_seq_device          5628  1 snd_seq
snd_timer              17784  2 snd_pcm,snd_seq
snd                    51038  5 snd_bcm2835,snd_timer,snd_pcm,snd_seq,snd_seq_device
★i2c_bcm2708             4990  0 
joydev                  8879  0 
spi_bcm2708             5137  0 
evdev                   9950  2 
uio_pdrv_genirq         2958  0 
uio                     8119  1 uio_pdrv_genirq

 

先輩たちがサンプルコードは書いているはずなので、探したところ、python でやるのとか、ruby でやるのとかがすぐ見つかりました。

とりあえず、動作確認したいので以下のサイトのコードを参考に必要な部分だけ使わせてもらいました。

Rabbit Note

BeagleBone Black で作るロギング機能付き電力計 (ソフト編)

BeagleBone Black(BBBと略するようです)での環境ですが、大変参考になりました。

使わせていただいたコードは最下部に付けておきます。で、配線は写真のようにちょっと雑ですが配線。負荷には、ちっさいファンをつけてみました。

SingleShot0023 スレーブアドレスは、何も設定しないと、0x40 が設定されるようです。

# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --  

 

プログラムを起動すると、以下のようになります。

# ./test.ruby
--------- 2016/01/25, 01:33:22
4.78125 V
151 mA
0.29 W
--------- 2016/01/25, 01:33:22
4.78125 V
151 mA
0.289 W
--------- 2016/01/25, 01:33:23
4.78875 V
152 mA
0.291 W
--------- 2016/01/25, 01:33:23
4.7875 V
151 mA
0.29 W
--------- 2016/01/25, 01:33:24
4.7875 V
150 mA
0.289 W
--------- 2016/01/25, 01:33:24
4.7875 V
151 mA
0.29 W
--------- 2016/01/25, 01:33:25
4.79 V
152 mA
0.292 W

負荷にLED を点けてみると、以下のようです。

# ./test.ruby 
--------- 2016/01/25, 01:35:31
4.88 V
2 mA
0.005 W
--------- 2016/01/25, 01:35:31
4.88 V
2 mA
0.005 W
--------- 2016/01/25, 01:35:31
4.9125 V
2 mA
0.005 W
--------- 2016/01/25, 01:35:32
4.91375 V
2 mA
0.005 W
--------- 2016/01/25, 01:35:32
4.91375 V
2 mA
0.005 W

 

まだあまりちゃんと理解していませんが、内部のレジスタの ox05 に、キャリブレーションする設定値を入れるようです。

以下の C のサンプルコードから、シャント抵抗に0.025R を使っている場合は、以下のように計算した16進数を入れればよいようです。書き込むとき、以下のコードでは、リトルエンディアンに変換していました。

https://github.com/jarzebski/Arduino-INA226/blob/master/INA226.cpp

0.025Ω = 0.00512/(0.025*0.0001)=2048 = 0x08 0x00

 

0x05 の補正レジスタを見てみると、

# i2cget -y 1 0x40 0x05 w

0x0008

という値が帰ってきました。

 

さて、そんな感じでとりあえずコードは以下のようにしてみました。

#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
 
IOCTL_I2C_SLAVE = 0x0703
 
# Script for power meter using the following parts
# - Power Meter module (IC: INA226)

# # i2cdetect -y 1
#      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
# 00:          -- -- -- -- -- -- -- -- -- -- -- -- --
# 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 70: -- -- -- -- -- -- -- --

class PowerSenseor
  def initialize(i2c_bus=1, dev_addr=0x40)
    @i2c = File.open(sprintf('/dev/i2c-%d', i2c_bus), 'rb+')
    @i2c.ioctl(IOCTL_I2C_SLAVE, dev_addr)

    @dev_addr = dev_addr
    @v_val = 0
    @c_val = 0
    @p_val = 0

    # shunt resistor = 0.002Ω = 0.00512/(0.002*0.001)=2560 = 0x0a 0x00
    #                  0.025Ω = 0.00512/(0.025*0.0001)=2048 = 0x08 0x00
    #   内部レジスタ[0x04] (Current) = 内部レジスタ[0x01]×内部レジスタ[0x05] / 2048
    exec_cmd("i2cset -y 1 0x#{dev_addr.to_s(16)} 0x05 0x08 0x00 i")
    # conversion time = 332us, number of average = 16
    exec_cmd("i2cset -y 1 0x#{dev_addr.to_s(16)} 0x00 0x04 0x97 i")
  end

  def sense
    # i2cset/i2cget は 10ms オーダーの時間を消費するのでここでは使用しない 
    @i2c.write(0x02)
    @v_val = conver_signed(@i2c.read(2))

    # 0x04 電流レジスタ
    @i2c.write(0x04)
    @c_val = conver_signed(@i2c.read(2))

    # 0x03 Powerレジスタ
    @i2c.write(0x03)
    @p_val = conver_signed(@i2c.read(2))
  end

  def conver_signed(bytes)
    # convert endian
    return bytes.unpack('n').pack('S').unpack('s')[0].abs
  end

  def get_voltage
    return calc_voltage(@v_val)
  end

  def get_current
    return calc_current(@c_val)
  end

  def get_power
    return calc_power(@p_val)
  end

  def exec_cmd(cmd)
    val=`#{cmd} 2> /dev/null`
    raise StandardError, "FAIL: #{cmd}" unless $?.success?
    return val
  end

  def calc_voltage(v_val)
    return v_val * 1.25 / 1000.0
  end

  # 0x04 電流レジスタ
  def calc_current(c_val)
    return c_val / 10
  end

  # 0x03 Powerレジスタ
  def calc_power(p_val)
    # return p_val * 0.025
    return p_val * 0.001
  end
end

require 'optparse'
params = ARGV.getopts('lq')

data_list = []

Signal.trap(:INT){
  if params['l'] then
    printf("time,voltage,current,power\n")
    data_list.each{|data|
      printf("%10d,%.3f,%.3f,%.3f\n", data[0], data[1], data[2], data[3])
    }
  end
  exit(0)
}

sensor = PowerSenseor.new
require "date"

start_time = Time.now
i = 0
while true
  sensor.sense
  v = sensor.get_voltage
  c = sensor.get_current
  p = sensor.get_power

  dt = DateTime.now
  print "--------- "
  print(dt.strftime("%Y/%m/%d, %H:%M:%S"), "\n")

  print v
  print " V\n"
  print c
  print " mA\n"
  print p
  print " W\n"

  if ((i & 0x7F) == 0) then

  else
    sleep 0.5
  end
  i = (i & 0xff) + 1
end

 

▼まとめ

・0x05 にシャント抵抗値を入れた補正値を書き込む

・書き込む最は、16進をリトルエンディアンにして書き込む

・0x04 はPowerレジスタで、0x04 は電流レジスタ。

・LSB ってなに?

・ちっこい今使っているファンは、150mA くらい使っていて0.3W ほど

・c のサンプルはすぐに見つからなかったけども、どうんな感じになるんだろう?

・自分で作ったハードが動いてうれしぃ!

・レジスタって、どういう回路なの? どういう仕組みで覚えているんだろう?

INA226 電流センサーの I2C ボードを作った

小さな部品も大きく見えるようになって、作業しやすくなったのでPCB の半田付けを再開しました。

今回は、電流センサーの INA226 です。

b

回路図は、チュートリアルを参考に上記のようにしました。

a

ブレッドボードをまたぐ4ピッチ幅にしてあります。プリントに出すPCB のあまり部分に無理やり作ったので少し窮屈です。

3

こんな感じでテープで固定しつつ半田付け。小さいですが、モニターで見れるので問題なしです。

2

以下、作業ステップ。

SingleShot0007

フラックスをつけます。 SingleShot0008

半田小手の先にちょっと半田を付けて位置決め。ブリッジしても気にしない。 SingleShot0011

ブリッジを小手を当てて取ります。 SingleShot0012

こんな感じで、ブリッジを除去。 SingleShot0013

フラックスを麺棒で掃除。 SingleShot0014

反対側もつけて、チェック。 SingleShot0015

シャント抵抗もつけて、ピンヘッダーを付けてとりあえず本日終了。 SingleShot0021 裏側も小さな抵抗とコンデンサーを付けています。

 

かなりマイクロスコープがあるおかげで作業がしやすくなりました。必須ですね。これは。

300円のmicroSD の 8GB も来たのでラズパイで I2C してみます。品質はどうでしょうかね?

こんなに、ぼやけた印字でしたっけ?なんか偽造品の臭いがしますが、、、、

SingleShot0022

あとで、手持ちの本物と比べてみますか。