Skip to content

Update adafruit_ina228.py #3

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 1 commit into from
Jun 4, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 102 additions & 16 deletions adafruit_ina228.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,28 @@ class Mode:
CONTINUOUS_ALL = 0x0F


class AlertType:
"""Constants for alert type settings"""

NONE = 0x00
CONVERSION_READY = 0x01
OVERPOWER = 0x02
UNDERVOLTAGE = 0x04
OVERVOLTAGE = 0x08
UNDERCURRENT = 0x10
OVERCURRENT = 0x20
_VALID_VALUES = [
NONE,
CONVERSION_READY,
OVERPOWER,
UNDERVOLTAGE,
OVERVOLTAGE,
UNDERCURRENT,
OVERCURRENT,
]
_MAX_COMBINED = 0x3F


class INA228: # noqa: PLR0904
"""Driver for the INA228 power and current sensor"""

Expand All @@ -95,8 +117,14 @@ class INA228: # noqa: PLR0904
_shunt_cal = UnaryStruct(_SHUNT_CAL, ">H")
_diag_alrt = UnaryStruct(_DIAG_ALRT, ">H")
_adc_range = RWBit(_CONFIG, 4, register_width=2)
_alert_type = RWBits(6, _DIAG_ALRT, 8, register_width=2)
_alert_polarity_bit = RWBit(_DIAG_ALRT, 12, register_width=2)
_alert_latch_bit = RWBit(_DIAG_ALRT, 15, register_width=2)
_reset_bit = RWBit(_CONFIG, 15, register_width=2)
_reset_accumulators_bit = RWBit(_CONFIG, 14, register_width=2)
"""Operating mode"""
mode = RWBits(4, _ADC_CONFIG, 12, register_width=2)
_alert_conv_bit = RWBit(_DIAG_ALRT, 14, register_width=2)
_vbus_ct = RWBits(3, _ADC_CONFIG, 9, register_width=2)
_vshunt_ct = RWBits(3, _ADC_CONFIG, 6, register_width=2)
_temper_ct = RWBits(3, _ADC_CONFIG, 3, register_width=2)
Expand All @@ -117,8 +145,13 @@ def __init__(self, i2c_bus, addr=0x40):
self.i2c_device = I2CDevice(i2c_bus, addr)
self.buf3 = bytearray(3) # Buffer for 24-bit registers
self.buf5 = bytearray(5) # Buffer for 40-bit registers
# Verify manufacturer ID (should be 0x5449 for Texas Instruments)
if self.manufacturer_id != 0x5449:
raise RuntimeError(
f"Invalid manufacturer ID: 0x{self.manufacturer_id:04X} (expected 0x5449)"
)
# Verify device ID
dev_id = (self._device_id >> 4) & 0xFFF # Get 12-bit device ID
dev_id = (self._device_id >> 4) & 0xFFF
if dev_id != 0x228:
raise RuntimeError(f"Failed to find INA228 - check your wiring! (Got ID: 0x{dev_id:X})")
self._current_lsb = 0
Expand All @@ -131,8 +164,11 @@ def __init__(self, i2c_bus, addr=0x40):
self.averaging_count = 16

def reset(self) -> None:
"""Reset the INA228"""
self._config = 0x8000
"""Reset the INA228 (all registers to default values)"""
self._reset_bit = True
self._alert_conv_bit = True
self.mode = Mode.CONTINUOUS_ALL
time.sleep(0.002)

def _reg24(self, reg):
"""Read 24-bit register"""
Expand All @@ -152,7 +188,61 @@ def _reg40(self, reg):

def reset_accumulators(self) -> None:
"""Reset the energy and charge accumulators"""
self._config = 1 << 14
self._reset_accumulators_bit = True

@property
def adc_range(self) -> int:
"""
ADC range.
0 = ±163.84 mV
1 = ±40.96 mV

When using the ±40.96 mV range, the shunt calibration value is automatically scaled by 4.
"""
return self._adc_range

@adc_range.setter
def adc_range(self, value: int):
if value not in {0, 1}:
raise ValueError("ADC range must be 0 (±163.84 mV) or 1 (±40.96 mV)")
self._adc_range = value
self._update_calibration()

@property
def alert_type(self) -> int:
"""
The alert trigger type. Use AlertType constants.
Can be OR'd together for multiple triggers.

Example:
# Single alert type
sensor.alert_type = AlertType.OVERPOWER

# Multiple alert types
sensor.alert_type = AlertType.OVERPOWER | AlertType.OVERVOLTAGE
"""
return self._alert_type

@alert_type.setter
def alert_type(self, value: int):
# Check if it's a valid combination of alert types
if value < 0 or value > AlertType._MAX_COMBINED:
raise ValueError(f"Invalid alert type value: {value}. Must be 0-0x3F")

# Optional: Validate that only valid bits are set
valid_mask = (
AlertType.CONVERSION_READY
| AlertType.OVERPOWER
| AlertType.UNDERVOLTAGE
| AlertType.OVERVOLTAGE
| AlertType.UNDERCURRENT
| AlertType.OVERCURRENT
)

if value & ~valid_mask:
raise ValueError(f"Invalid alert type bits set: 0x{value:02X}")

self._alert_type = value

@property
def conversion_time_bus(self) -> int:
Expand Down Expand Up @@ -233,7 +323,7 @@ def set_calibration_32V_2A(self) -> None:
"""Configure for 32V and up to 2A measurements"""
self._mode = Mode.CONTINUOUS_ALL
time.sleep(0.001)
self.set_shunt(0.1, 2.0)
self.set_shunt(0.015, 10.0)
self._vbus_ct = 5
self._vshunt_ct = 5
self._temper_ct = 5
Expand Down Expand Up @@ -295,6 +385,8 @@ def current(self) -> float:
def charge(self) -> float:
"""Accumulated charge in coulombs"""
raw = self._reg40(_CHARGE)
if raw & (1 << 39):
raw |= -1 << 40
return raw * self._current_lsb

@property
Expand Down Expand Up @@ -332,26 +424,20 @@ def conversion_time_temperature(self, usec: int):
@property
def alert_latch(self) -> bool:
"""Alert latch setting. True=latched, False=transparent"""
return bool(self._diag_alrt & (1 << 15))
return bool(self._alert_latch_bit)

@alert_latch.setter
def alert_latch(self, value: bool):
if value:
self._diag_alrt |= 1 << 15
else:
self._diag_alrt &= ~(1 << 15)
self._alert_latch_bit = value

@property
def alert_polarity(self) -> bool:
"""Alert polarity. True=inverted, False=normal"""
return bool(self._diag_alrt & (1 << 12))
return bool(self._alert_polarity_bit)

@alert_polarity.setter
def alert_polarity(self, value: bool):
if value:
self._diag_alrt |= 1 << 12
else:
self._diag_alrt &= ~(1 << 12)
self._alert_polarity_bit = value

@property
def shunt_voltage_overlimit(self) -> float:
Expand All @@ -366,7 +452,7 @@ def shunt_voltage_overlimit(self, value: float):
@property
def alert_flags(self) -> dict:
"""
Get all diagnostic and alert flags
All diagnostic and alert flags

Returns a dictionary with the status of each flag:

Expand Down