稼働中

Raspberry Pi Pico(d_23)INA219 双方向電流センサ

INA219 DC Current Monitor (I2C)

INA219は双方向電流/電力モニタです。I2C通信で制御します。INA219モジュールのシャント抵抗は0.1Ω(R100)です。プログラムゲイン(PGA)を±320mVにすれば3.2Aまでの測定できます。Raspberry Pi PicoでINA219モジュールの動作確認をしました。
※micro:bitの記事e_45からRaspberry Pi Picoで使えるように追記、修正等をしました。

外観

INA219モジュールの外観写真です。(以後はINA219と記載します)
Vin+とVin-間にR100(0.1Ω)のシャント抵抗(Rsh)が搭載されています。この電圧をAD変換して電流値を測ります。
INA219モジュールのプリントパターンA0やA1をはんだで接続(電源電圧になる)させることで、INA219のスレーブアドレスを変更できます。
写真のままの開放状態なら0x40、A0なら0x41、A1なら0x44、A0とA1両方なら0x45になります。詳細はINA219のデータシートを参照ください。
INA219モジュール

接続例

INA219の電源電圧は2.7V~5.5VなのでRaspberry Pi Picoと接続できます。
I2C通信にはI2C1のSDA(GP10)SCL(GP11)を使いました。電流測定動作を確認するために、外部電源5Vに負荷抵抗1.5kΩを接続しています。
INA219 接続図
接続出来たらI2Cデバイスのスレーブアドレスを調べてみます。
ThonnyのShellで確認しました。
INA219のスレーブアドレスは以下のように64(0x40)でした。


>>> from machine import I2C,Pin
>>> i2c = I2C(1, scl=Pin(11), sda=Pin(10), freq=400_000)
>>> i2c.scan()
[64]
>>> 

INA219の説明

データシートから抜粋してINA219の説明します。
INA219のレジスタは下図のように0x00~0x05にConfiguration、Shunt Voltage、Bus Voltage、Power、Current、Calibration名のレジスタがあります。
Configuration RegisterはBus Voltage RangeやPGA(gain and range)、ADC Settings、Operating Modeを設定します。
デフォルト値は0x399fで、バス電圧~32V、GAIN/8 Range±320 mV、ADCは12 bit、Modeはcontinuousです。
ADC Settingsには2~128サンプリング平均の設定もあります。※詳細はデータシートを参照ください。
リセットすると、Configurationはデフォルトの設定(0x399f)になります。Power、Current、Calibrationのレジスタは消去されます。そのため、リセット後はCalibration値の書き込みが必要です。
INA219 レジスタマップ
※ TIのINA219データシートから抜粋

Calibration値は以下の式で計算します。
データシートのTypical Applicationに、R SHUNT = 2 mΩ、Maximum expected load current = 15 Aの例があります。
Current LSBを計算すると
>>> 15/(2**15)*10**6
457.7637
Current LSB=457.78 µA/bitとなるのですが、例ではround upして1mA/bitになっています。
そのため、
Cal=0.04096/(1mAx2mΩ)=0.04096/(1/1000*2/1000)=20480(‘0x5000’)となり、Calibration Registerには’0x5000’を設定しています。
INA219 計算式
※ TIのINA219データシートから抜粋

Current Registerの値は下式(4)で算出されます。
電流値はCurrent RegisterにCurrent LSBを掛けて算出するので、Current LSB値を大きく丸めても大丈夫なようです。
ちなみに、Current LSB=458で計算すると、Cal=44716’0xaeac’になります。この数値を書込んでも問題ないと思います。
INA219 計算式
Shunt voltage、Bus voltageは各レジスタ値に、各々10uV、4mVを掛け算して算出します。
Shunt voltage = Shunt voltage Register x 10uV
Bus voltage = Bus voltage Register x 4mV

Shunt Voltage RegisterはPGAの設定によって符号ビットが変わります。
例えば、PGA = /8なら16bit符号付きデータ、PGA = /1なら13bit符号付きデータになります。
Bus Voltage Registerは[3:15]の13bitデータになります。

Powerは(3)式のPower_LSBをPowerレジスタ値に掛け算して算出します。
※その他の詳細はデータシートを参照ください。
INA219 計算式5
※TIのデータシートより抜粋

スクリプト

INA219のスクリプトは以下のようにしました。
configurationをデフォルト(0x399f)の設定からバス電圧レンジを16Vに変更し0x199fで設定しました。
Calibrationなどはmax_expect_current=1.5A、Rsh=0.1Ωで計算しています。

以下の値や測定値を表示しています。
configurationの値を表示
Shunt Voltageの符号ビット
Shunt Voltage
Bus Voltage
Shunt Voltage + Bus Voltage
current(I)
power
I^2*R
リセット後のconfiguration
current
リセット解除後のconfiguration
current

※開発環境はThonnyです。ThonnyでMicroPythonをRaspberry Pi Pico with RP2040にインストールして使っています。
※Raspberry Pi Pico単独で動作させるには’main.py’としてRaspberry Pi Picoにuploadして使います。


pico_INA219_test_02b.py
#!/usr/bin/env python
# -*- coding: utf-8 -*
from machine import I2C,Pin
import time
# INA219 current power monitor
#slave address hex(64)='0x40'  A1,A0=0,0
i2c = I2C(1, scl=Pin(11), sda=Pin(10), freq=400_000)
addr=0x40
# register map 各レジスタのアドレス
Cfg=0x00 # configuration R/W    設定が必要
Vsh=0x01 # shunt voltage R signed
Vbs=0x02 # bus voltage   R [3:15] 13bit 読出し注意
Pow=0x03 # power         R
Cur=0x04 # current       R signed
Cal=0x05 # calibration   R/W    設定が必要

Vsh_LSB=10*10**-6   #Shunt voltage LSB 10uV fixed
Bus_LSB= 4*10**-3   #Bus   voltage LSB 4mV  fixed

# Input Data
# MaxCurrent Rsh-ohm
IMAX=1.5    # max_expect_current
Rsh=0.1     # shunt register ohm
# config set data
RST='0'
BRNG='0'    # 16V(0)32V(1)
PGA='11'    # PG1|PG0  ±40mV(00)80mV(01)160mV(10)320mV(11) program gain
BADC='0011' # default 12bit 532us(0011) 8times(1011)16times(1100)128times(1111)
SADC='0011' # default 12bit 532us(0011)
MODE='111'  # Shunt&Bus-continue(111) triggered(011) Power-down(000)

config='0b'+RST+'0'+BRNG+PGA+BADC+SADC+MODE
config=int(config)
print('{:#018b}'.format(config),hex(config))
#config=0x399F #0b_0011_1001_1001_1111 R/W 32V Default
#config=0x199f #0b_0001_1001_1001_1111 R/W 16V
#config=0x1ddf #0b_0001_1101_1101_1111 R/W 16V 8samples ave

# PGの値から符号ビットを特定する
PG='0b'+PGA
s_bit=int(PG)+13
print('Vsh_SIGN_bit=',s_bit)

# Calc
Cur_LSB=IMAX/2**15              #(2)式
Pow_LSB=20*Cur_LSB              #(3)式

CAL=int(0.04096/(Cur_LSB*Rsh))  #(1)式

# read register
def r_reg(reg):
    buf=bytearray(1)
    buf[0]=reg
    i2c.writeto(addr,buf)
    r_dat=i2c.readfrom(addr,2)      # |MSB|LSB|  2byte
    # 8bit*2 >> 16bit
    dat=r_dat[0]<<8 | r_dat[1]      # 2bytes 16bitデータにする
    return dat

# 符号計算
def sig(dat,num):
    if dat >= (2**(num-1)):
        dat=dat-(2**num)
    return dat

# write register
def w_reg(reg,dat):
    buf=bytearray(3)        # pointer MSByte LSByte の3bytes
    buf[0]=reg
    buf[1]=(dat>>8 & 0xff)  # MSB 16bit wo shift site 8bit
    buf[2]=(dat & 0xff)     # LSB 
    #print('w_reg=',hex(pointer),hex(dat),buf)
    i2c.writeto(addr,buf)
    time.sleep_us(10)

# config-regi data
def read_Cfg():
    r_dat=r_reg(Cfg)
    d_PRN(r_dat)

# 16bit bin format
def d_PRN(dat):
    print('{:#018b}'.format(dat),hex(dat))

# RST: Reset Bit
def RST_set(RST='0'):
    global config
    RST='0b'+RST
    config=(config & 0x7fff)| (int(RST) <<15) #reset bit change
    w_reg(Cfg,config)  
    # calibrate set  リセット後は必要
    w_reg(Cal,CAL)
    time.sleep_ms(10)
    return config

## main
# config set
w_reg(Cfg,config)
# calibrate set
w_reg(Cal,CAL)

# シャント電圧測定 シャント電圧レジスタ*10uV
vsh=sig(r_reg(Vsh),s_bit)*Vsh_LSB*10**6 # uA signed  PGA/?bit
print('Vsh(uV)=',vsh)

# バス電圧測定 バス電圧レジスタ*4mV
vbs=(r_reg(Vbs)>>3)*Bus_LSB*1000    # mV Vbs 13bit
print('Vbus(mV)=',vbs)

## calculation
# 電源電圧算出
vcc=(vsh/1000) + vbs
print('Vcc=Vsh+Vbs(mV)=',vcc)

# 電流値算出 current reg*Cur_LSB
cur=sig(r_reg(Cur),16)*Cur_LSB*1000 # mA signed 16bit
print('I(mA)=',cur)

# 電力算出 パワーレジスタ*Pow_LSB
pow=(r_reg(Pow))*Pow_LSB*1000 # mW
print('Pow(mW)=',pow)

# 電力を別計算してみるI^2*R
mW=(cur/1000)**2*1500*1000  # W=I^2R R_load=1.5k
print('I^2R mW=',mW)

# Reset 動作を確認
print('')
print('RST-1 リセット')
dat=RST_set('1')
read_Cfg()

# 電流値算出
cur=sig(r_reg(Cur),16)*Cur_LSB*1000 # mA signed 16bit
print('I(mA)=',cur)

print('RST-0 解除')
dat=RST_set('0')
read_Cfg()

# 電流値算出
cur=sig(r_reg(Cur),16)*Cur_LSB*1000 # mA signed 16bit
print('I(mA)=',cur)

関数 部分説明

■Configuration Registerに設定する値は、BRNG=’0’等をセットして
config=’0b’+RST+’0’+BRNG+PGA+BADC+SADC+MODE
config=int(config)
で与えています。
■PGの値からShunt Voltage Registerの符号ビットを
PG=’0b’+PGA
s_bit=int(PG)+13
で決めています。
■sig(dat,num)
符号計算値を返します。
dat:符号計算をするデータ
num:ビット数
■w_reg(reg,dat)
registerに2バイトデータを書き込みます。
reg:registerのアドレス
dat:書き込む2bytes(16bit)データ
■r_reg(reg)
registerの値を返します。2bytesデータです。
reg:registerのアドレス
■read_Cfg()
Configuration Registerの値を表示します。
■RST_set(RST=’0′)
Configuration Registerのリセットビットを操作します。
‘1’でリセットします。’0’で解除します。

実行結果

結果は以下のようになりました。※Thonnyのshellに表示されます。
電圧5V、負荷1.5kΩの電流を測定しました。測定できているようです。
リセット動作も確認できました。


>>> %Run -c $EDITOR_CONTENT
0b0001100110011111 0x199f   # configuration値
Vsh_SIGN_bit= 16            # 符号ビット
Vsh(uV)= 310.0001           # Shunt Voltage
Vbus(mV)= 4904.001          # Bus Voltage
Vcc=Vsh+Vbs(mV)= 5214.0     # Shunt Voltage + Bus Voltage
I(mA)= 3.387451             # current 5V/1.5kΩ = 3.33mA
Pow(mW)= 16.47949           # power 
I^2R mW= 17.21224           # power

RST-1 リセット
0b0011100110011111 0x399f   # リセットでデフォルトに戻る
I(mA)= 3.02124
RST-0 解除
0b0001100110011111 0x199f   # 設定値に戻る
I(mA)= 3.112793
>>> 

まとめ

Raspberry Pi PicoでINA219を使ってD/A変換ができました。