Interfacing INA219 Board with micropython

I needed a solution to monitor both current and voltage for my battery powered microcontroller projects.

The gotcha was in the measured input being above the Vcc of the microcontroller.

I found INA219 based boards to be suitable. Except there was no library for micropython (which I use for quick prototyping and generally get things done).

While I was testing the board I found that there was some misleading information regarding measuring negative current. Unlike many internet sources the chip is indeed capable measuring the current in both direction. This makes it perfect to monitor charge and discharge of a ~12V battery.

Here is the micropython code (ESP32 board, but should work with others):

from machine import I2C, Pin
""" 
INA219 Power Monitor interface.
Copyright GPL3.0 sergei.nz.
https://www.ti.com/lit/ds/symlink/ina219.pdf
"""

MAX_CURRENT = 3.2 # Amps
CURRENT_LSB = MAX_CURRENT/(2**15)
R_SHUNT = 0.1 # Ohms
CALIBRATION = int(0.04096 / (CURRENT_LSB * R_SHUNT))

CONF_R = 0x00
SHUNT_V_R = 0x01
BUS_V_R = 0x02
POWER_R = 0x03
CURRENT_R = 0x04
CALIBRATION_R = 0x05

ADDRESS = 0x40

SDA = Pin(21)
SCL = Pin(22)
FREQ = 400000

i2c = I2C(sda=SDA,scl=SCL,freq=FREQ)
i2c.writeto_mem(ADDRESS, CALIBRATION_R ,(CALIBRATION).to_bytes(2, 'big'))


def read_current():
    raw_current = int.from_bytes(i2c.readfrom_mem(ADDRESS, SHUNT_V_R, 2), 'big')
    if raw_current >> 15:
        raw_current -= 2**16
    return raw_current * CURRENT_LSB


def read_voltage():
    return (int.from_bytes(i2c.readfrom_mem(ADDRESS, BUS_V_R, 2), 'big') >> 3) * 0.004

The tricky bit is the calibration, you can read voltage without any calibration, but to make sense for current you will need to set the calibration register (0x05) to a specific value.

The calibration formula can be found here. It is present in the code above as well, all you need to do is define your shunt value (in Ohms) and maximum current you wish to measure (in Amps). Obviously there are limitations that are described in the documentation.

I haven’t implemented read_power(), but it should be straight forward to do.

Leave a Reply

Your email address will not be published. Required fields are marked *