From 33e075583fb862f8703b5076fe98f16574297a2c Mon Sep 17 00:00:00 2001 From: Jean-Michel Mercier Date: Sat, 16 Mar 2019 21:30:38 +0100 Subject: [PATCH 1/9] - Fix values for _CONFIG_BADCRES and add missing values - Add properties (get & set) for config register and config fields break-up --- adafruit_ina219.py | 77 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/adafruit_ina219.py b/adafruit_ina219.py index a465ae5..21b4a95 100644 --- a/adafruit_ina219.py +++ b/adafruit_ina219.py @@ -58,22 +58,33 @@ _CONFIG_RESET = const(0x8000) # Reset Bit _CONFIG_BVOLTAGERANGE_MASK = const(0x2000) # Bus Voltage Range Mask +_CONFIG_BVOLTAGERANGE_LSB = const(13) # Bus Voltage Range LSB position _CONFIG_BVOLTAGERANGE_16V = const(0x0000) # 0-16V Range _CONFIG_BVOLTAGERANGE_32V = const(0x2000) # 0-32V Range _CONFIG_GAIN_MASK = const(0x1800) # Gain Mask +_CONFIG_GAIN_LSB = const(11) # Gain LSB position _CONFIG_GAIN_1_40MV = const(0x0000) # Gain 1, 40mV Range _CONFIG_GAIN_2_80MV = const(0x0800) # Gain 2, 80mV Range _CONFIG_GAIN_4_160MV = const(0x1000) # Gain 4, 160mV Range _CONFIG_GAIN_8_320MV = const(0x1800) # Gain 8, 320mV Range _CONFIG_BADCRES_MASK = const(0x0780) # Bus ADC Resolution Mask -_CONFIG_BADCRES_9BIT = const(0x0080) # 9-bit bus res = 0..511 -_CONFIG_BADCRES_10BIT = const(0x0100) # 10-bit bus res = 0..1023 -_CONFIG_BADCRES_11BIT = const(0x0200) # 11-bit bus res = 0..2047 -_CONFIG_BADCRES_12BIT = const(0x0400) # 12-bit bus res = 0..4097 +_CONFIG_BADCRES_LSB = const(7) # Bus ADC Resolution LSB position +_CONFIG_BADCRES_9BIT = const(0x0000) # 9-bit bus res = 0..511 +_CONFIG_BADCRES_10BIT = const(0x0080) # 10-bit bus res = 0..1023 +_CONFIG_BADCRES_11BIT = const(0x0100) # 11-bit bus res = 0..2047 +_CONFIG_BADCRES_12BIT = const(0x0180) # 12-bit bus res = 0..4097 +_CONFIG_BADCRES_12BIT_2S_1060US = const(0x0480) # 2 x 12-bit bus samples averaged together +_CONFIG_BADCRES_12BIT_4S_2130US = const(0x0500) # 4 x 12-bit bus samples averaged together +_CONFIG_BADCRES_12BIT_8S_4260US = const(0x0580) # 8 x 12-bit bus samples averaged together +_CONFIG_BADCRES_12BIT_16S_8510US = const(0x0600) # 16 x 12-bit bus samples averaged together +_CONFIG_BADCRES_12BIT_32S_17MS = const(0x0680) # 32 x 12-bit bus samples averaged together +_CONFIG_BADCRES_12BIT_64S_34MS = const(0x0700) # 64 x 12-bit bus samples averaged together +_CONFIG_BADCRES_12BIT_128S_69MS = const(0x0780) # 128 x 12-bit bus samples averaged together _CONFIG_SADCRES_MASK = const(0x0078) # Shunt ADC Resolution and Averaging Mask +_CONFIG_SADCRES_LSB = const(3) # Shunt ADC Resolution and Averaging LSB position _CONFIG_SADCRES_9BIT_1S_84US = const(0x0000) # 1 x 9-bit shunt sample _CONFIG_SADCRES_10BIT_1S_148US = const(0x0008) # 1 x 10-bit shunt sample _CONFIG_SADCRES_11BIT_1S_276US = const(0x0010) # 1 x 11-bit shunt sample @@ -87,6 +98,7 @@ _CONFIG_SADCRES_12BIT_128S_69MS = const(0x0078) # 128 x 12-bit shunt samples averaged together _CONFIG_MODE_MASK = const(0x0007) # Operating Mode Mask +_CONFIG_MODE_LSB = const(0) # Operating Mode LSB position _CONFIG_MODE_POWERDOWN = const(0x0000) _CONFIG_MODE_SVOLT_TRIGGERED = const(0x0001) _CONFIG_MODE_BVOLT_TRIGGERED = const(0x0002) @@ -147,6 +159,63 @@ def _read_register(self, reg): value = (buf[1] << 8) | (buf[2]) return value + @property + def config(self): + return self._read_register(_REG_CONFIG) + + @config.setter + def config(self,value): + self._write_register(_REG_CONFIG,value) + + @property + def reset(self): + self._write_register(_REG_CONFIG,_CONFIG_RESET) + + @property + def bus_voltage_range(self): + return (self.config & _CONFIG_BVOLTAGERANGE_MASK) >> _CONFIG_BVOLTAGERANGE_LSB + + @bus_voltage_range.setter + def bus_voltage_range(self,value): + value = (value << _CONFIG_BVOLTAGERANGE_LSB) & _CONFIG_BVOLTAGERANGE_MASK + self.config = value | (self.config & ~_CONFIG_BVOLTAGERANGE_MASK) + + @property + def gain(self): + return (self.config & _CONFIG_GAIN_MASK) >> _CONFIG_GAIN_LSB + + @gain.setter + def gain(self,value): + value = (value << _CONFIG_GAIN_LSB) & _CONFIG_GAIN_MASK + self.config = value | (self.config & ~_CONFIG_GAIN_MASK) + + @property + def bus_adc_res(self): + return (self.config & _CONFIG_BADCRES_MASK) >> _CONFIG_BADCRES_LSB + + @bus_adc_res.setter + def bus_adc_res(self,value): + value = (value << _CONFIG_BADCRES_LSB) & _CONFIG_BADCRES_MASK + self.config = value | (self.config & ~_CONFIG_BADCRES_MASK) + + @property + def shunt_adc_res(self): + return (self.config & _CONFIG_SADCRES_MASK) >> _CONFIG_SADCRES_LSB + + @shunt_adc_res.setter + def shunt_adc_res(self,value): + value = (value << _CONFIG_SADCRES_LSB) & _CONFIG_SADCRES_MASK + self.config = value | (self.config & ~_CONFIG_SADCRES_MASK) + + @property + def mode(self): + return (self.config & _CONFIG_MODE_MASK) >> _CONFIG_MODE_LSB + + @mode.setter + def mode(self,value): + value = (value << _CONFIG_MODE_LSB) & _CONFIG_MODE_MASK + self.config = value | (self.config & ~_CONFIG_MODE_MASK) + @property def shunt_voltage(self): """The shunt voltage (between V+ and V-) in Volts (so +-.327V)""" From ee35938aafd597d931eec45f776fb2347d5a0cbb Mon Sep 17 00:00:00 2001 From: Jean-Michel Mercier Date: Sat, 16 Mar 2019 21:33:11 +0100 Subject: [PATCH 2/9] Update sample to use new properties and clean-up printed output (align values) --- examples/ina219_simpletest.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/ina219_simpletest.py b/examples/ina219_simpletest.py index fb95269..ccb226c 100644 --- a/examples/ina219_simpletest.py +++ b/examples/ina219_simpletest.py @@ -9,13 +9,22 @@ ina219 = adafruit_ina219.INA219(i2c_bus) +# change configuration to use 32 samples averaging for both bus voltage and shunt voltage +ina219.bus_adc_res = 0x0D # BADCRES_12BIT_32S_17MS +ina219.shunt_adc_res = 0x0D # SADCRES_12BIT_32S_17MS +ina219.bus_voltage_range = 0 # BVOLTAGERANGE_16V + print("ina219 test") while True: - print("Bus Voltage: {} V".format(ina219.bus_voltage)) - print("Shunt Voltage: {} mV".format(ina219.shunt_voltage / 1000)) - print("Load Voltage: {} V".format(ina219.bus_voltage + ina219.shunt_voltage)) - print("Current: {} mA".format(ina219.current)) + bus_voltage = ina219.bus_voltage + shunt_voltage = ina219.shunt_voltage + current = ina219.current + + print("PSU Voltage: {:6.3f} V".format(bus_voltage + shunt_voltage)) + print("Shunt Voltage: {:9.6f} V".format(shunt_voltage)) + print("Load Voltage: {:6.3f} V".format(bus_voltage)) + print("Current: {:9.6f} A".format(current/1000)) print("") time.sleep(2) From bb439c197680604e9e7f955c6ef2f534a760d190 Mon Sep 17 00:00:00 2001 From: Jean-Michel Mercier Date: Sat, 16 Mar 2019 23:44:40 +0100 Subject: [PATCH 3/9] fix pylint errors --- adafruit_ina219.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/adafruit_ina219.py b/adafruit_ina219.py index 21b4a95..da8fe17 100644 --- a/adafruit_ina219.py +++ b/adafruit_ina219.py @@ -161,61 +161,68 @@ def _read_register(self, reg): @property def config(self): + """read/write to configuration register - see datasheet for values""" return self._read_register(_REG_CONFIG) - + @config.setter - def config(self,value): - self._write_register(_REG_CONFIG,value) + def config(self, value): + self._write_register(_REG_CONFIG, value) @property def reset(self): - self._write_register(_REG_CONFIG,_CONFIG_RESET) + """reset the device""" + self._write_register(_REG_CONFIG, _CONFIG_RESET) @property def bus_voltage_range(self): + """read/write the Bus Voltage Range field of the configuration register""" return (self.config & _CONFIG_BVOLTAGERANGE_MASK) >> _CONFIG_BVOLTAGERANGE_LSB @bus_voltage_range.setter - def bus_voltage_range(self,value): + def bus_voltage_range(self, value): value = (value << _CONFIG_BVOLTAGERANGE_LSB) & _CONFIG_BVOLTAGERANGE_MASK self.config = value | (self.config & ~_CONFIG_BVOLTAGERANGE_MASK) @property def gain(self): + """read/write the Gain field of the configuration register""" return (self.config & _CONFIG_GAIN_MASK) >> _CONFIG_GAIN_LSB @gain.setter - def gain(self,value): + def gain(self, value): value = (value << _CONFIG_GAIN_LSB) & _CONFIG_GAIN_MASK self.config = value | (self.config & ~_CONFIG_GAIN_MASK) @property def bus_adc_res(self): + """read/write the Bus ADC Resolution/Averaging field fo the configuration register""" return (self.config & _CONFIG_BADCRES_MASK) >> _CONFIG_BADCRES_LSB @bus_adc_res.setter - def bus_adc_res(self,value): + def bus_adc_res(self, value): value = (value << _CONFIG_BADCRES_LSB) & _CONFIG_BADCRES_MASK self.config = value | (self.config & ~_CONFIG_BADCRES_MASK) @property def shunt_adc_res(self): + """read/write the Shunt ADC Resolution/Averaging field fo the configuration register""" return (self.config & _CONFIG_SADCRES_MASK) >> _CONFIG_SADCRES_LSB @shunt_adc_res.setter - def shunt_adc_res(self,value): + def shunt_adc_res(self, value): value = (value << _CONFIG_SADCRES_LSB) & _CONFIG_SADCRES_MASK self.config = value | (self.config & ~_CONFIG_SADCRES_MASK) @property def mode(self): + """read/write the Mode field fo the configuration register""" return (self.config & _CONFIG_MODE_MASK) >> _CONFIG_MODE_LSB @mode.setter - def mode(self,value): + def mode(self, value): value = (value << _CONFIG_MODE_LSB) & _CONFIG_MODE_MASK self.config = value | (self.config & ~_CONFIG_MODE_MASK) - + @property def shunt_voltage(self): """The shunt voltage (between V+ and V-) in Volts (so +-.327V)""" From 8ecba9fc361266f9d1771771987658befe68439a Mon Sep 17 00:00:00 2001 From: Jean-Michel Mercier Date: Sat, 16 Mar 2019 23:48:59 +0100 Subject: [PATCH 4/9] add 1 comment --- examples/ina219_simpletest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/ina219_simpletest.py b/examples/ina219_simpletest.py index ccb226c..aed6a97 100644 --- a/examples/ina219_simpletest.py +++ b/examples/ina219_simpletest.py @@ -21,6 +21,7 @@ shunt_voltage = ina219.shunt_voltage current = ina219.current + # INA219 measure bus voltage on the load side. So power supply voltage = busVoltage+shuntVoltage print("PSU Voltage: {:6.3f} V".format(bus_voltage + shunt_voltage)) print("Shunt Voltage: {:9.6f} V".format(shunt_voltage)) print("Load Voltage: {:6.3f} V".format(bus_voltage)) From c024b6a58508117e7090a190612d24d10d70012d Mon Sep 17 00:00:00 2001 From: Jean-Michel Mercier Date: Sun, 17 Mar 2019 18:17:06 +0100 Subject: [PATCH 5/9] Clean-up and improvements - Change internals to use adafruit_register for register and bit-field read/write - Updated table of constants, fix BusADCResolution values, add new values - Add new properties to access registers (advanced API) - Update ina219_simpletest to show some usage of the new properties --- adafruit_ina219.py | 315 ++++++++++++++++------------------ examples/ina219_simpletest.py | 40 +++-- 2 files changed, 171 insertions(+), 184 deletions(-) diff --git a/adafruit_ina219.py b/adafruit_ina219.py index da8fe17..f8bb59f 100644 --- a/adafruit_ina219.py +++ b/adafruit_ina219.py @@ -46,83 +46,77 @@ from micropython import const from adafruit_bus_device.i2c_device import I2CDevice +from adafruit_register.i2c_struct import ROUnaryStruct, UnaryStruct +from adafruit_register.i2c_bits import ROBits, RWBits +from adafruit_register.i2c_bit import ROBit + __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_INA219.git" # Bits # pylint: disable=bad-whitespace -_READ = const(0x01) +# pylint: disable=too-few-public-methods # Config Register (R/W) -_REG_CONFIG = const(0x00) -_CONFIG_RESET = const(0x8000) # Reset Bit - -_CONFIG_BVOLTAGERANGE_MASK = const(0x2000) # Bus Voltage Range Mask -_CONFIG_BVOLTAGERANGE_LSB = const(13) # Bus Voltage Range LSB position -_CONFIG_BVOLTAGERANGE_16V = const(0x0000) # 0-16V Range -_CONFIG_BVOLTAGERANGE_32V = const(0x2000) # 0-32V Range - -_CONFIG_GAIN_MASK = const(0x1800) # Gain Mask -_CONFIG_GAIN_LSB = const(11) # Gain LSB position -_CONFIG_GAIN_1_40MV = const(0x0000) # Gain 1, 40mV Range -_CONFIG_GAIN_2_80MV = const(0x0800) # Gain 2, 80mV Range -_CONFIG_GAIN_4_160MV = const(0x1000) # Gain 4, 160mV Range -_CONFIG_GAIN_8_320MV = const(0x1800) # Gain 8, 320mV Range - -_CONFIG_BADCRES_MASK = const(0x0780) # Bus ADC Resolution Mask -_CONFIG_BADCRES_LSB = const(7) # Bus ADC Resolution LSB position -_CONFIG_BADCRES_9BIT = const(0x0000) # 9-bit bus res = 0..511 -_CONFIG_BADCRES_10BIT = const(0x0080) # 10-bit bus res = 0..1023 -_CONFIG_BADCRES_11BIT = const(0x0100) # 11-bit bus res = 0..2047 -_CONFIG_BADCRES_12BIT = const(0x0180) # 12-bit bus res = 0..4097 -_CONFIG_BADCRES_12BIT_2S_1060US = const(0x0480) # 2 x 12-bit bus samples averaged together -_CONFIG_BADCRES_12BIT_4S_2130US = const(0x0500) # 4 x 12-bit bus samples averaged together -_CONFIG_BADCRES_12BIT_8S_4260US = const(0x0580) # 8 x 12-bit bus samples averaged together -_CONFIG_BADCRES_12BIT_16S_8510US = const(0x0600) # 16 x 12-bit bus samples averaged together -_CONFIG_BADCRES_12BIT_32S_17MS = const(0x0680) # 32 x 12-bit bus samples averaged together -_CONFIG_BADCRES_12BIT_64S_34MS = const(0x0700) # 64 x 12-bit bus samples averaged together -_CONFIG_BADCRES_12BIT_128S_69MS = const(0x0780) # 128 x 12-bit bus samples averaged together - -_CONFIG_SADCRES_MASK = const(0x0078) # Shunt ADC Resolution and Averaging Mask -_CONFIG_SADCRES_LSB = const(3) # Shunt ADC Resolution and Averaging LSB position -_CONFIG_SADCRES_9BIT_1S_84US = const(0x0000) # 1 x 9-bit shunt sample -_CONFIG_SADCRES_10BIT_1S_148US = const(0x0008) # 1 x 10-bit shunt sample -_CONFIG_SADCRES_11BIT_1S_276US = const(0x0010) # 1 x 11-bit shunt sample -_CONFIG_SADCRES_12BIT_1S_532US = const(0x0018) # 1 x 12-bit shunt sample -_CONFIG_SADCRES_12BIT_2S_1060US = const(0x0048) # 2 x 12-bit shunt samples averaged together -_CONFIG_SADCRES_12BIT_4S_2130US = const(0x0050) # 4 x 12-bit shunt samples averaged together -_CONFIG_SADCRES_12BIT_8S_4260US = const(0x0058) # 8 x 12-bit shunt samples averaged together -_CONFIG_SADCRES_12BIT_16S_8510US = const(0x0060) # 16 x 12-bit shunt samples averaged together -_CONFIG_SADCRES_12BIT_32S_17MS = const(0x0068) # 32 x 12-bit shunt samples averaged together -_CONFIG_SADCRES_12BIT_64S_34MS = const(0x0070) # 64 x 12-bit shunt samples averaged together -_CONFIG_SADCRES_12BIT_128S_69MS = const(0x0078) # 128 x 12-bit shunt samples averaged together - -_CONFIG_MODE_MASK = const(0x0007) # Operating Mode Mask -_CONFIG_MODE_LSB = const(0) # Operating Mode LSB position -_CONFIG_MODE_POWERDOWN = const(0x0000) -_CONFIG_MODE_SVOLT_TRIGGERED = const(0x0001) -_CONFIG_MODE_BVOLT_TRIGGERED = const(0x0002) -_CONFIG_MODE_SANDBVOLT_TRIGGERED = const(0x0003) -_CONFIG_MODE_ADCOFF = const(0x0004) -_CONFIG_MODE_SVOLT_CONTINUOUS = const(0x0005) -_CONFIG_MODE_BVOLT_CONTINUOUS = const(0x0006) -_CONFIG_MODE_SANDBVOLT_CONTINUOUS = const(0x0007) +_REG_CONFIG = const(0x00) + +class Reset: + """Constants for ``reset``""" + RESET = const(0x01) # write RESET to reset + +class BusVoltageRange: + """Constants for ``bus_voltage_range``""" + RANGE_16V = const(0x00) # set bus voltage range to 16V + RANGE_32V = const(0x01) # set bus voltage range to 32V (default) + +class Gain: + """Constants for ``gain``""" + DIV_1_40MV = const(0x00) # shunt prog. gain set to 1, 40 mV range + DIV_2_80MV = const(0x01) # shunt prog. gain set to /2, 80 mV range + DIV_4_160MV = const(0x02) # shunt prog. gain set to /4, 160 mV range + DIV_8_320MV = const(0x03) # shunt prog. gain set to /8, 320 mV range + +class ADCResolution: + """Constants for ``bus_adc_resolution`` or ``shunt_adc_resolution``""" + ADCRES_9BIT_1S = const(0x00) # 9bit, 1 sample, 84us + ADCRES_10BIT_1S = const(0x01) # 10bit, 1 sample, 148us + ADCRES_11BIT_1S = const(0x02) # 11 bit, 1 sample, 276us + ADCRES_12BIT_1S = const(0x03) # 12 bit, 1 sample, 532us + ADCRES_12BIT_2S = const(0x09) # 12 bit, 2 samples, 1.06ms + ADCRES_12BIT_4S = const(0x0A) # 12 bit, 4 samples, 2.13ms + ADCRES_12BIT_8S = const(0x0B) # 12bit, 8 samples, 4.26ms + ADCRES_12BIT_16S = const(0x0C) # 12bit, 16 samples, 8.51ms + ADCRES_12BIT_32S = const(0x0D) # 12bit, 32 samples, 17.02ms + ADCRES_12BIT_64S = const(0x0E) # 12bit, 64 samples, 34.05ms + ADCRES_12BIT_128S = const(0x0F) # 12bit, 128 samples, 68.10ms + +class Mode: + """Constants for ``mode``""" + POWERDOW = const(0x00) # power down + SVOLT_TRIGGERED = const(0x01) # shunt voltage triggered + BVOLT_TRIGGERED = const(0x02) # bus voltage triggered + SANDBVOLT_TRIGGERED = const(0x03) # shunt and bus voltage triggered + ADCOFF = const(0x04) # ADC off + SVOLT_CONTINUOUS = const(0x05) # shunt voltage continuous + BVOLT_CONTINUOUS = const(0x06) # bus voltage continuous + SANDBVOLT_CONTINUOUS = const(0x07) # shunt and bus voltage continuous # SHUNT VOLTAGE REGISTER (R) -_REG_SHUNTVOLTAGE = const(0x01) +_REG_SHUNTVOLTAGE = const(0x01) # BUS VOLTAGE REGISTER (R) -_REG_BUSVOLTAGE = const(0x02) +_REG_BUSVOLTAGE = const(0x02) # POWER REGISTER (R) -_REG_POWER = const(0x03) +_REG_POWER = const(0x03) # CURRENT REGISTER (R) -_REG_CURRENT = const(0x04) +_REG_CURRENT = const(0x04) # CALIBRATION REGISTER (R/W) -_REG_CALIBRATION = const(0x05) -# pylint: enable=bad-whitespace +_REG_CALIBRATION = const(0x05) +# pylint: enable=too-few-public-methods + def _to_signed(num): if num > 0x7FFF: @@ -131,127 +125,115 @@ def _to_signed(num): class INA219: """Driver for the INA219 current sensor""" + + # Basic API: + + # INA219( i2c_bus, i2c_addr) Create instance of INA219 sensor + # :param i2c_bus The I2C bus the INA219is connected to + # :param i2c_addr (0x40) Address of the INA219 on the bus (default 0x40) + + # shunt_voltage RO : shunt voltage scaled to Volts + # bus_voltage RO : bus voltage (V- to GND) scaled to volts (==load voltage) + # current RO : current through shunt, scaled to mA + # power RO : power consumption of the load, scaled to Watt + # set_calibration_32V_2A() Initialize chip for 32V max and up to 2A (default) + # set_calibration_32V_1A() Initialize chip for 32V max and up to 1A + # set_calibration_16V_400mA() Initialize chip for 16V max and up to 400mA + + # Advanced API: + # config register break-up + # reset WO : Write Reset.RESET to reset the chip (must recalibrate) + # bus_voltage_range RW : Bus Voltage Range field (use BusVoltageRange.XXX constants) + # gain RW : Programmable Gain field (use Gain.XXX constants) + # bus_adc_resolution RW : Bus ADC resolution and averaging modes (ADCResolution.XXX) + # shunt_adc_resolution RW : Shunt ADC resolution and averaging modes (ADCResolution.XXX) + # mode RW : operating modes in config register (use Mode.XXX constants) + + # raw_shunt_voltage RO : Shunt Voltage register (not scaled) + # raw_bus_voltage RO : Bus Voltage field in Bus Voltage register (not scaled) + # conversion_ready RO : Conversion Ready bit in Bus Voltage register + # overflow RO : Math Overflow bit in Bus Voltage register + # raw_power RO : Power register (not scaled) + # raw_current RO : Current register (not scaled) + # calibration RW : calibration register (note: value is cached) + def __init__(self, i2c_bus, addr=0x40): self.i2c_device = I2CDevice(i2c_bus, addr) - self.i2c_addr = addr - # Multiplier in mA used to determine current from raw reading - self._current_lsb = 0 - # Multiplier in W used to determine power from raw reading - self._power_lsb = 0 # Set chip to known config values to start - self._cal_value = 4096 + self._cal_value = 0 + self._current_lsb = 0 + self._power_lsb = 0 self.set_calibration_32V_2A() - def _write_register(self, reg, value): - seq = bytearray([reg, (value >> 8) & 0xFF, value & 0xFF]) - with self.i2c_device as i2c: - i2c.write(seq) - - def _read_register(self, reg): - buf = bytearray(3) - buf[0] = reg - with self.i2c_device as i2c: - i2c.write(buf, end=1, stop=False) - i2c.readinto(buf, start=1) - - value = (buf[1] << 8) | (buf[2]) - return value + # config register break-up + reset = RWBits( 1, _REG_CONFIG, 15, 2, False) + bus_voltage_range = RWBits( 1, _REG_CONFIG, 13, 2, False) + gain = RWBits( 2, _REG_CONFIG, 11, 2, False) + bus_adc_resolution = RWBits( 4, _REG_CONFIG, 7, 2, False) + shunt_adc_resolution = RWBits( 4, _REG_CONFIG, 3, 2, False) + mode = RWBits( 3, _REG_CONFIG, 0, 2, False) - @property - def config(self): - """read/write to configuration register - see datasheet for values""" - return self._read_register(_REG_CONFIG) - - @config.setter - def config(self, value): - self._write_register(_REG_CONFIG, value) + # shunt voltage register + raw_shunt_voltage = ROUnaryStruct(_REG_SHUNTVOLTAGE, ">h") - @property - def reset(self): - """reset the device""" - self._write_register(_REG_CONFIG, _CONFIG_RESET) + #bus voltage register + raw_bus_voltage = ROBits( 12, _REG_BUSVOLTAGE, 3, 2, False) + conversion_ready = ROBit( _REG_BUSVOLTAGE, 1, 2, False) + overflow = ROBit( _REG_BUSVOLTAGE, 0, 2, False) - @property - def bus_voltage_range(self): - """read/write the Bus Voltage Range field of the configuration register""" - return (self.config & _CONFIG_BVOLTAGERANGE_MASK) >> _CONFIG_BVOLTAGERANGE_LSB + # power and current registers + raw_power = ROUnaryStruct(_REG_POWER, ">H") + raw_current = ROUnaryStruct(_REG_CURRENT, ">h") - @bus_voltage_range.setter - def bus_voltage_range(self, value): - value = (value << _CONFIG_BVOLTAGERANGE_LSB) & _CONFIG_BVOLTAGERANGE_MASK - self.config = value | (self.config & ~_CONFIG_BVOLTAGERANGE_MASK) + # calibration register + _raw_calibration = UnaryStruct(_REG_CALIBRATION, ">H") @property - def gain(self): - """read/write the Gain field of the configuration register""" - return (self.config & _CONFIG_GAIN_MASK) >> _CONFIG_GAIN_LSB + def calibration(self): + """Calibration register (cached value)""" + return self._cal_value # return cached value - @gain.setter - def gain(self, value): - value = (value << _CONFIG_GAIN_LSB) & _CONFIG_GAIN_MASK - self.config = value | (self.config & ~_CONFIG_GAIN_MASK) - - @property - def bus_adc_res(self): - """read/write the Bus ADC Resolution/Averaging field fo the configuration register""" - return (self.config & _CONFIG_BADCRES_MASK) >> _CONFIG_BADCRES_LSB - - @bus_adc_res.setter - def bus_adc_res(self, value): - value = (value << _CONFIG_BADCRES_LSB) & _CONFIG_BADCRES_MASK - self.config = value | (self.config & ~_CONFIG_BADCRES_MASK) - - @property - def shunt_adc_res(self): - """read/write the Shunt ADC Resolution/Averaging field fo the configuration register""" - return (self.config & _CONFIG_SADCRES_MASK) >> _CONFIG_SADCRES_LSB - - @shunt_adc_res.setter - def shunt_adc_res(self, value): - value = (value << _CONFIG_SADCRES_LSB) & _CONFIG_SADCRES_MASK - self.config = value | (self.config & ~_CONFIG_SADCRES_MASK) - - @property - def mode(self): - """read/write the Mode field fo the configuration register""" - return (self.config & _CONFIG_MODE_MASK) >> _CONFIG_MODE_LSB - - @mode.setter - def mode(self, value): - value = (value << _CONFIG_MODE_LSB) & _CONFIG_MODE_MASK - self.config = value | (self.config & ~_CONFIG_MODE_MASK) + @calibration.setter + def calibration(self, cal_value): + self._cal_value = cal_value # value is cached for ``current`` and ``power`` properties + self._raw_calibration = self._cal_value @property def shunt_voltage(self): """The shunt voltage (between V+ and V-) in Volts (so +-.327V)""" - value = _to_signed(self._read_register(_REG_SHUNTVOLTAGE)) # The least signficant bit is 10uV which is 0.00001 volts - return value * 0.00001 + return self.raw_shunt_voltage * 0.00001 @property def bus_voltage(self): """The bus voltage (between V- and GND) in Volts""" - raw_voltage = self._read_register(_REG_BUSVOLTAGE) - # Shift to the right 3 to drop CNVR and OVF and multiply by LSB # Each least signficant bit is 4mV - voltage_mv = _to_signed(raw_voltage >> 3) * 4 - return voltage_mv * 0.001 + return self.raw_bus_voltage * 0.004 @property def current(self): """The current through the shunt resistor in milliamps.""" # Sometimes a sharp load will reset the INA219, which will # reset the cal register, meaning CURRENT and POWER will - # not be available ... athis by always setting a cal + # not be available ... always setting a cal # value even if it's an unfortunate extra step - self._write_register(_REG_CALIBRATION, self._cal_value) + self._raw_calibration = self._cal_value + # Now we can safely read the CURRENT register! + return self.raw_current * self._current_lsb + @property + def power(self): + """The power through the load in Watt.""" + # Sometimes a sharp load will reset the INA219, which will + # reset the cal register, meaning CURRENT and POWER will + # not be available ... always setting a cal + # value even if it's an unfortunate extra step + self._raw_calibration = self._cal_value # Now we can safely read the CURRENT register! - raw_current = _to_signed(self._read_register(_REG_CURRENT)) - return raw_current * self._current_lsb + return self.raw_power * self._power_lsb def set_calibration_32V_2A(self): # pylint: disable=invalid-name """Configures to INA219 to be able to measure up to 32V and 2A of current. Counter @@ -325,15 +307,14 @@ def set_calibration_32V_2A(self): # pylint: disable=invalid-name # MaximumPower = 102.4W # Set Calibration register to 'Cal' calculated above - self._write_register(_REG_CALIBRATION, self._cal_value) + self._raw_calibration = self._cal_value # Set Config register to take into account the settings above - config = _CONFIG_BVOLTAGERANGE_32V | \ - _CONFIG_GAIN_8_320MV | \ - _CONFIG_BADCRES_12BIT | \ - _CONFIG_SADCRES_12BIT_1S_532US | \ - _CONFIG_MODE_SANDBVOLT_CONTINUOUS - self._write_register(_REG_CONFIG, config) + self.bus_voltage_range = BusVoltageRange.RANGE_32V + self.gain = Gain.DIV_8_320MV + self.bus_adc_resolution = ADCResolution.ADCRES_12BIT_1S + self.shunt_adc_resolution = ADCResolution.ADCRES_12BIT_1S + self.mode = Mode.SANDBVOLT_CONTINUOUS def set_calibration_32V_1A(self): # pylint: disable=invalid-name """Configures to INA219 to be able to measure up to 32V and 1A of current. Counter overflow @@ -408,15 +389,14 @@ def set_calibration_32V_1A(self): # pylint: disable=invalid-name # MaximumPower = 41.94176W # Set Calibration register to 'Cal' calculated above - self._write_register(_REG_CALIBRATION, self._cal_value) + self._raw_calibration = self._cal_value # Set Config register to take into account the settings above - config = (_CONFIG_BVOLTAGERANGE_32V | - _CONFIG_GAIN_8_320MV | - _CONFIG_BADCRES_12BIT | - _CONFIG_SADCRES_12BIT_1S_532US | - _CONFIG_MODE_SANDBVOLT_CONTINUOUS) - self._write_register(_REG_CONFIG, config) + self.bus_voltage_range = BusVoltageRange.RANGE_32V + self.gain = Gain.DIV_8_320MV + self.bus_adc_resolution = ADCResolution.ADCRES_12BIT_1S + self.shunt_adc_resolution = ADCResolution.ADCRES_12BIT_1S + self.mode = Mode.SANDBVOLT_CONTINUOUS def set_calibration_16V_400mA(self): # pylint: disable=invalid-name """Configures to INA219 to be able to measure up to 16V and 400mA of current. Counter @@ -492,12 +472,11 @@ def set_calibration_16V_400mA(self): # pylint: disable=invalid-name # MaximumPower = 6.4W # Set Calibration register to 'Cal' calculated above - self._write_register(_REG_CALIBRATION, self._cal_value) + self._raw_calibration = self._cal_value # Set Config register to take into account the settings above - config = (_CONFIG_BVOLTAGERANGE_16V | - _CONFIG_GAIN_1_40MV | - _CONFIG_BADCRES_12BIT | - _CONFIG_SADCRES_12BIT_1S_532US | - _CONFIG_MODE_SANDBVOLT_CONTINUOUS) - self._write_register(_REG_CONFIG, config) + self.bus_voltage_range = BusVoltageRange.RANGE_16V + self.gain = Gain.DIV_1_40MV + self.bus_adc_resolution = ADCResolution.ADCRES_12BIT_1S + self.shunt_adc_resolution = ADCResolution.ADCRES_12BIT_1S + self.mode = Mode.SANDBVOLT_CONTINUOUS diff --git a/examples/ina219_simpletest.py b/examples/ina219_simpletest.py index aed6a97..3f7e41d 100644 --- a/examples/ina219_simpletest.py +++ b/examples/ina219_simpletest.py @@ -1,27 +1,35 @@ import time +import board +from adafruit_ina219 import * -from board import SCL, SDA -import busio +i2c_bus = board.I2C() -import adafruit_ina219 - -i2c_bus = busio.I2C(SCL, SDA) - -ina219 = adafruit_ina219.INA219(i2c_bus) - -# change configuration to use 32 samples averaging for both bus voltage and shunt voltage -ina219.bus_adc_res = 0x0D # BADCRES_12BIT_32S_17MS -ina219.shunt_adc_res = 0x0D # SADCRES_12BIT_32S_17MS -ina219.bus_voltage_range = 0 # BVOLTAGERANGE_16V +ina219 = INA219(i2c_bus) print("ina219 test") +# display some of the advanced field (just to test) +print( "Config register:") +print( " bus_voltage_range: 0x%1X" % ina219.bus_voltage_range ) +print( " gain: 0x%1X" % ina219.gain ) +print( " bus_adc_resolution: 0x%1X" % ina219.bus_adc_resolution ) +print( " shunt_adc_resolution: 0x%1X" % ina219.shunt_adc_resolution ) +print( " mode: 0x%1X" % ina219.mode ) +print ("") + +# optional : change configuration to use 32 samples averaging for both bus voltage and shunt voltage +ina219.bus_adc_resolution = ADCResolution.ADCRES_12BIT_32S +ina219.shunt_adc_resolution = ADCResolution.ADCRES_12BIT_32S +# optional : change voltage range to 16V +ina219.bus_voltage_range = BusVoltageRange.RANGE_16V + +# measure and display loop while True: - bus_voltage = ina219.bus_voltage - shunt_voltage = ina219.shunt_voltage - current = ina219.current + bus_voltage = ina219.bus_voltage # voltage on V- (load side) + shunt_voltage = ina219.shunt_voltage # voltage between V+ and V- across the shunt + current = ina219.current # current in mA - # INA219 measure bus voltage on the load side. So power supply voltage = busVoltage+shuntVoltage + # INA219 measure bus voltage on the load side. So PSU voltage = bus_voltage + shunt_voltage print("PSU Voltage: {:6.3f} V".format(bus_voltage + shunt_voltage)) print("Shunt Voltage: {:9.6f} V".format(shunt_voltage)) print("Load Voltage: {:6.3f} V".format(bus_voltage)) From c2e1e32e1bb274d7627c988cdf88f65c9503c2ce Mon Sep 17 00:00:00 2001 From: Jean-Michel Mercier Date: Sun, 17 Mar 2019 18:37:54 +0100 Subject: [PATCH 6/9] Clean-up and improvements - Change internals to use adafruit_register for register and bit-field read/write - Updated table of constants, fix BusADCResolution values, add new values - Add new properties to access registers (advanced API) - Update ina219_simpletest to show some usage of the new properties --- requirements.txt | 1 + setup.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3031961..1629bc4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ Adafruit-Blinka adafruit-circuitpython-busdevice +adafruit-circuitpython-register \ No newline at end of file diff --git a/setup.py b/setup.py index e83fa3c..55efbe3 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,7 @@ author='Adafruit Industries', author_email='circuitpython@adafruit.com', - install_requires=['Adafruit-Blinka', 'adafruit-circuitpython-busdevice'], + install_requires=['Adafruit-Blinka', 'adafruit-circuitpython-busdevice', 'adafruit-circuitpython-register'], # Choose your license license='MIT', From 938995db9e906b7e8ee710ecf5f45ba7b769d115 Mon Sep 17 00:00:00 2001 From: Jean-Michel Mercier Date: Sun, 17 Mar 2019 19:04:58 +0100 Subject: [PATCH 7/9] fixing pylint errors --- examples/ina219_simpletest.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/examples/ina219_simpletest.py b/examples/ina219_simpletest.py index 3f7e41d..d0dbfbe 100644 --- a/examples/ina219_simpletest.py +++ b/examples/ina219_simpletest.py @@ -1,6 +1,9 @@ +"""Sample code and test for adafruit_in219""" + import time import board -from adafruit_ina219 import * +from adafruit_ina219 import ADCResolution, BusVoltageRange, INA219 + i2c_bus = board.I2C() @@ -9,13 +12,13 @@ print("ina219 test") # display some of the advanced field (just to test) -print( "Config register:") -print( " bus_voltage_range: 0x%1X" % ina219.bus_voltage_range ) -print( " gain: 0x%1X" % ina219.gain ) -print( " bus_adc_resolution: 0x%1X" % ina219.bus_adc_resolution ) -print( " shunt_adc_resolution: 0x%1X" % ina219.shunt_adc_resolution ) -print( " mode: 0x%1X" % ina219.mode ) -print ("") +print("Config register:") +print(" bus_voltage_range: 0x%1X" % ina219.bus_voltage_range) +print(" gain: 0x%1X" % ina219.gain) +print(" bus_adc_resolution: 0x%1X" % ina219.bus_adc_resolution) +print(" shunt_adc_resolution: 0x%1X" % ina219.shunt_adc_resolution) +print(" mode: 0x%1X" % ina219.mode) +print("") # optional : change configuration to use 32 samples averaging for both bus voltage and shunt voltage ina219.bus_adc_resolution = ADCResolution.ADCRES_12BIT_32S From 9774ba38327c30e1ed9f43f69840442052003521 Mon Sep 17 00:00:00 2001 From: Jean-Michel Mercier Date: Tue, 19 Mar 2019 19:20:23 +0100 Subject: [PATCH 8/9] Removed useless `class Reset` --- adafruit_ina219.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/adafruit_ina219.py b/adafruit_ina219.py index f8bb59f..5b5466f 100644 --- a/adafruit_ina219.py +++ b/adafruit_ina219.py @@ -60,10 +60,6 @@ # Config Register (R/W) _REG_CONFIG = const(0x00) -class Reset: - """Constants for ``reset``""" - RESET = const(0x01) # write RESET to reset - class BusVoltageRange: """Constants for ``bus_voltage_range``""" RANGE_16V = const(0x00) # set bus voltage range to 16V From 3056c2ca442d8559d152a3f9951fec550052656c Mon Sep 17 00:00:00 2001 From: Barbudor Date: Tue, 19 Mar 2019 21:00:55 +0100 Subject: [PATCH 9/9] removed un-necessary `const()` keyword --- adafruit_ina219.py | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/adafruit_ina219.py b/adafruit_ina219.py index 5b5466f..9886817 100644 --- a/adafruit_ina219.py +++ b/adafruit_ina219.py @@ -62,40 +62,40 @@ class BusVoltageRange: """Constants for ``bus_voltage_range``""" - RANGE_16V = const(0x00) # set bus voltage range to 16V - RANGE_32V = const(0x01) # set bus voltage range to 32V (default) + RANGE_16V = 0x00 # set bus voltage range to 16V + RANGE_32V = 0x01 # set bus voltage range to 32V (default) class Gain: """Constants for ``gain``""" - DIV_1_40MV = const(0x00) # shunt prog. gain set to 1, 40 mV range - DIV_2_80MV = const(0x01) # shunt prog. gain set to /2, 80 mV range - DIV_4_160MV = const(0x02) # shunt prog. gain set to /4, 160 mV range - DIV_8_320MV = const(0x03) # shunt prog. gain set to /8, 320 mV range + DIV_1_40MV = 0x00 # shunt prog. gain set to 1, 40 mV range + DIV_2_80MV = 0x01 # shunt prog. gain set to /2, 80 mV range + DIV_4_160MV = 0x02 # shunt prog. gain set to /4, 160 mV range + DIV_8_320MV = 0x03 # shunt prog. gain set to /8, 320 mV range class ADCResolution: """Constants for ``bus_adc_resolution`` or ``shunt_adc_resolution``""" - ADCRES_9BIT_1S = const(0x00) # 9bit, 1 sample, 84us - ADCRES_10BIT_1S = const(0x01) # 10bit, 1 sample, 148us - ADCRES_11BIT_1S = const(0x02) # 11 bit, 1 sample, 276us - ADCRES_12BIT_1S = const(0x03) # 12 bit, 1 sample, 532us - ADCRES_12BIT_2S = const(0x09) # 12 bit, 2 samples, 1.06ms - ADCRES_12BIT_4S = const(0x0A) # 12 bit, 4 samples, 2.13ms - ADCRES_12BIT_8S = const(0x0B) # 12bit, 8 samples, 4.26ms - ADCRES_12BIT_16S = const(0x0C) # 12bit, 16 samples, 8.51ms - ADCRES_12BIT_32S = const(0x0D) # 12bit, 32 samples, 17.02ms - ADCRES_12BIT_64S = const(0x0E) # 12bit, 64 samples, 34.05ms - ADCRES_12BIT_128S = const(0x0F) # 12bit, 128 samples, 68.10ms + ADCRES_9BIT_1S = 0x00 # 9bit, 1 sample, 84us + ADCRES_10BIT_1S = 0x01 # 10bit, 1 sample, 148us + ADCRES_11BIT_1S = 0x02 # 11 bit, 1 sample, 276us + ADCRES_12BIT_1S = 0x03 # 12 bit, 1 sample, 532us + ADCRES_12BIT_2S = 0x09 # 12 bit, 2 samples, 1.06ms + ADCRES_12BIT_4S = 0x0A # 12 bit, 4 samples, 2.13ms + ADCRES_12BIT_8S = 0x0B # 12bit, 8 samples, 4.26ms + ADCRES_12BIT_16S = 0x0C # 12bit, 16 samples, 8.51ms + ADCRES_12BIT_32S = 0x0D # 12bit, 32 samples, 17.02ms + ADCRES_12BIT_64S = 0x0E # 12bit, 64 samples, 34.05ms + ADCRES_12BIT_128S = 0x0F # 12bit, 128 samples, 68.10ms class Mode: """Constants for ``mode``""" - POWERDOW = const(0x00) # power down - SVOLT_TRIGGERED = const(0x01) # shunt voltage triggered - BVOLT_TRIGGERED = const(0x02) # bus voltage triggered - SANDBVOLT_TRIGGERED = const(0x03) # shunt and bus voltage triggered - ADCOFF = const(0x04) # ADC off - SVOLT_CONTINUOUS = const(0x05) # shunt voltage continuous - BVOLT_CONTINUOUS = const(0x06) # bus voltage continuous - SANDBVOLT_CONTINUOUS = const(0x07) # shunt and bus voltage continuous + POWERDOW = 0x00 # power down + SVOLT_TRIGGERED = 0x01 # shunt voltage triggered + BVOLT_TRIGGERED = 0x02 # bus voltage triggered + SANDBVOLT_TRIGGERED = 0x03 # shunt and bus voltage triggered + ADCOFF = 0x04 # ADC off + SVOLT_CONTINUOUS = 0x05 # shunt voltage continuous + BVOLT_CONTINUOUS = 0x06 # bus voltage continuous + SANDBVOLT_CONTINUOUS = 0x07 # shunt and bus voltage continuous # SHUNT VOLTAGE REGISTER (R) _REG_SHUNTVOLTAGE = const(0x01)