Skip to content

Adding fields #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Feb 16, 2021
136 changes: 118 additions & 18 deletions adafruit_ina260.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,17 @@
"""
`adafruit_ina260`
================================================================================

CircuitPython driver for the TI INA260 current and power sensor


* Author(s): Bryan Siepert

Implementation Notes
--------------------

**Hardware:**

* `INA260 Breakout <https://www.adafruit.com/products/4226>`_

**Software and Dependencies:**

* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases

* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
* Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
* https://github.com/adafruit/circuitpython/releases
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
* Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
"""

# imports
Expand All @@ -36,8 +27,8 @@
import adafruit_bus_device.i2c_device as i2cdevice

from adafruit_register.i2c_struct import ROUnaryStruct
from adafruit_register.i2c_bits import RWBits
from adafruit_register.i2c_bit import ROBit
from adafruit_register.i2c_bits import ROBits, RWBits
from adafruit_register.i2c_bit import ROBit, RWBit

_REG_CONFIG = const(0x00) # CONFIGURATION REGISTER (R/W)
_REG_CURRENT = const(0x01) # SHUNT VOLTAGE REGISTER (R)
Expand All @@ -48,6 +39,7 @@
_REG_MFG_UID = const(0xFE) # MANUFACTURER UNIQUE ID REGISTER (R)
_REG_DIE_UID = const(0xFF) # DIE UNIQUE ID REGISTER (R)


# pylint: disable=too-few-public-methods
class Mode:
"""Modes avaible to be set
Expand Down Expand Up @@ -108,6 +100,21 @@ class ConversionTime:
TIME_4_156_ms = const(0x6)
TIME_8_244_ms = const(0x7)

@staticmethod
def get_seconds(time_enum):
"""Retrieve the time in seconds giving value read from register"""
conv_dict = {
0: 140e-6,
1: 204e-6,
2: 332e-6,
3: 558e-6,
4: 1.1e-3,
5: 2.116e-3,
6: 4.156e-3,
7: 8.244e-3,
}
return conv_dict[time_enum]


class AveragingCount:
"""Options for ``averaging_count``
Expand Down Expand Up @@ -143,6 +150,12 @@ class AveragingCount:
COUNT_512 = const(0x6)
COUNT_1024 = const(0x7)

@staticmethod
def get_averaging_count(avg_count):
"""Retrieve the number of measurements giving value read from register"""
conv_dict = {0: 1, 1: 4, 2: 16, 3: 64, 4: 128, 5: 256, 6: 512, 7: 1024}
return conv_dict[avg_count]


# pylint: enable=too-few-public-methods

Expand All @@ -158,12 +171,80 @@ class INA260:
def __init__(self, i2c_bus, address=0x40):
self.i2c_device = i2cdevice.I2CDevice(i2c_bus, address)

if self._manufacturer_id != self.TEXAS_INSTRUMENT_ID:
raise RuntimeError(
"Failed to find Texas Instrument ID, read {} while expected {}"
" - check your wiring!".format(
self._manufacturer_id, self.TEXAS_INSTRUMENT_ID
)
)

if self._device_id != self.INA260_ID:
raise RuntimeError(
"Failed to find INA260 ID, read {} while expected {}"
" - check your wiring!".format(self._device_id, self.INA260_ID)
)

_raw_current = ROUnaryStruct(_REG_CURRENT, ">h")
_raw_voltage = ROUnaryStruct(_REG_BUSVOLTAGE, ">H")
_raw_power = ROUnaryStruct(_REG_POWER, ">H")

_conversion_ready = ROBit(_REG_MASK_ENABLE, 3, 2, False)
# MASK_ENABLE fields
overcurrent_limit = RWBit(_REG_MASK_ENABLE, 15, 2, False)
"""Setting this bit high configures the ALERT pin to be asserted if the current measurement
following a conversion exceeds the value programmed in the Alert Limit Register.
"""
under_current_limit = RWBit(_REG_MASK_ENABLE, 14, 2, False)
"""Setting this bit high configures the ALERT pin to be asserted if the current measurement
following a conversion drops below the value programmed in the Alert Limit Register.
"""
bus_voltage_over_voltage = RWBit(_REG_MASK_ENABLE, 13, 2, False)
"""Setting this bit high configures the ALERT pin to be asserted if the bus voltage measurement
following a conversion exceeds the value programmed in the Alert Limit Register.
"""
bus_voltage_under_voltage = RWBit(_REG_MASK_ENABLE, 12, 2, False)
"""Setting this bit high configures the ALERT pin to be asserted if the bus voltage measurement
following a conversion drops below the value programmed in the Alert Limit Register.
"""
power_over_limit = RWBit(_REG_MASK_ENABLE, 11, 2, False)
"""Setting this bit high configures the ALERT pin to be asserted if the Power calculation
made following a bus voltage measurement exceeds the value programmed in the
Alert Limit Register.
"""
conversion_ready = RWBit(_REG_MASK_ENABLE, 10, 2, False)
"""Setting this bit high configures the ALERT pin to be asserted when the Conversion Ready Flag,
Bit 3, is asserted indicating that the device is ready for the next conversion.
"""
# from 5 to 9 are not used
alert_function_flag = ROBit(_REG_MASK_ENABLE, 4, 2, False)
"""While only one Alert Function can be monitored at the ALERT pin at time, the
Conversion Ready can also be enabled to assert the ALERT pin.
Reading the Alert Function Flag following an alert allows the user to determine if the Alert
Function was the source of the Alert.

When the Alert Latch Enable bit is set to Latch mode, the Alert Function Flag bit
clears only when the Mask/Enable Register is read.
When the Alert Latch Enable bit is set to Transparent mode, the Alert Function Flag bit
is cleared following the next conversion that does not result in an Alert condition.
"""
_conversion_ready_flag = ROBit(_REG_MASK_ENABLE, 3, 2, False)
"""Bit to help coordinate one-shot or triggered conversion. This bit is set after all
conversion, averaging, and multiplication are complete.
Conversion Ready flag bit clears when writing the configuration register or
reading the Mask/Enable register.
"""
math_overflow_flag = ROBit(_REG_MASK_ENABLE, 2, 2, False)
"""This bit is set to 1 if an arithmetic operation resulted in an overflow error.
"""
alert_polarity_bit = RWBit(_REG_MASK_ENABLE, 1, 2, False)
"""Active-high open collector when True, Active-low open collector when false (default).
"""
alert_latch_enable = RWBit(_REG_MASK_ENABLE, 0, 2, False)
"""Configures the latching feature of the ALERT pin and Alert Flag Bits.
"""

reset_bit = RWBit(_REG_CONFIG, 15, 2, False)
"""Setting this bit t 1 generates a system reset. Reset all registers to default values."""
averaging_count = RWBits(3, _REG_CONFIG, 9, 2, False)
"""The window size of the rolling average used in continuous mode"""
voltage_conversion_time = RWBits(3, _REG_CONFIG, 6, 2, False)
Expand All @@ -177,28 +258,47 @@ def __init__(self, i2c_bus, address=0x40):
"""

mask_enable = RWBits(16, _REG_MASK_ENABLE, 0, 2, False)
"""The Mask/Enable Register selects the function that is enabled to control the ALERT pin as
well as how that pin functions.
If multiple functions are enabled, the highest significant bit
position Alert Function (D15-D11) takes priority and responds to the Alert Limit Register.
"""
alert_limit = RWBits(16, _REG_ALERT_LIMIT, 0, 2, False)
"""The Alert Limit Register contains the value used to compare to the register selected in the
Mask/Enable Register to determine if a limit has been exceeded.
The format for this register will match the format of the register that is selected for
comparison.
"""

TEXAS_INSTRUMENT_ID = const(0x5449)
INA260_ID = const(0x227)
_manufacturer_id = ROUnaryStruct(_REG_MFG_UID, ">H")
"""Manufacturer identification bits"""
_device_id = ROBits(12, _REG_DIE_UID, 4, 2, False)
"""Device identification bits"""
revision_id = ROBits(4, _REG_DIE_UID, 0, 2, False)
"""Device revision identification bits"""

@property
def current(self):
"""The current (between V+ and V-) in mA"""
if self.mode == Mode.TRIGGERED:
while self._conversion_ready == 0:
while self._conversion_ready_flag == 0:
pass
return self._raw_current * 1.25

@property
def voltage(self):
"""The bus voltage in V"""
if self.mode == Mode.TRIGGERED:
while self._conversion_ready == 0:
while self._conversion_ready_flag == 0:
pass
return self._raw_voltage * 0.00125

@property
def power(self):
"""The power being delivered to the load in mW"""
if self.mode == Mode.TRIGGERED:
while self._conversion_ready == 0:
while self._conversion_ready_flag == 0:
pass
return self._raw_power * 10
58 changes: 58 additions & 0 deletions examples/ina260_latch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# SPDX-FileCopyrightText: Gabriele Pongelli 2021 for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import time
import board
from adafruit_ina260 import INA260, Mode, ConversionTime


if __name__ == "__main__":
try:
i2c = board.I2C()
ina260 = INA260(i2c)
except RuntimeError as r_e:
# catch exception on init, no INA260 chip found
print(r_e)
raise r_e
else:
# set overcurrent limit flag and threshold value
# 0x0008 x 1,25 mA = 10 mA as alert limit
ina260.alert_limit = 0x0008

# alert pin is asserted, can be check with gpiozero
ina260.overcurrent_limit = True

# keep the flag high until MASK_ENABLE register will be read
ina260.alert_latch_enable = True

ina260.mode = Mode.CONTINUOUS

# set higher conversion time and wait its value before each read
ina260.current_conversion_time = ConversionTime.TIME_8_244_ms
for _ in enumerate(range(5)):
time.sleep(ConversionTime.get_seconds(ina260.current_conversion_time))
print(
"Current: %.2f mA Voltage: %.2f V Power:%.2f mW"
% (ina260.current, ina260.voltage, ina260.power)
)

# supposing meanwhile the alert limit was exceeded, setting an higher limit
# and clear the ALERT
# 0x0100 x 1,25 mA = 320 mA as alert limit
ina260.alert_limit = 0x0100

# alert function flag bit should be true if alert threshold was exceeded
print("Alert function flag: {}".format(ina260.alert_function_flag))

# in latch mode, reading the register clears the ALERT & alert function flag
print("MASK register: {}".format(ina260.mask_enable))

# reset the whole chip and wait 2 sec
ina260.reset_bit = True
time.sleep(2)
print(
"MASK_REGISTER check, must be 0x0000 after reset: {}".format(
ina260.mask_enable
)
)