Skip to content

Commit 562f341

Browse files
authored
Merge pull request #1 from adafruit/initial_lib
library, docs and example
2 parents 32192a2 + 700bd16 commit 562f341

File tree

6 files changed

+212
-19
lines changed

6 files changed

+212
-19
lines changed

README.rst

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ This driver depends on:
3131
* `Adafruit CircuitPython <https://github.com/adafruit/circuitpython>`_
3232
* `Bus Device <https://github.com/adafruit/Adafruit_CircuitPython_BusDevice>`_
3333
* `Register <https://github.com/adafruit/Adafruit_CircuitPython_Register>`_
34+
* `Adafruit CircuitPython INA228 <https://github.com/adafruit/Adafruit_CircuitPython_INA228>`_
3435

3536
Please ensure all dependencies are available on the CircuitPython filesystem.
3637
This is easily achieved by downloading
@@ -39,6 +40,7 @@ or individual libraries can be installed using
3940
`circup <https://github.com/adafruit/circup>`_.
4041

4142
`Purchase INA237 from the Adafruit shop <http://www.adafruit.com/products/6340>`_
43+
4244
`Purchase INA238 from the Adafruit shop <http://www.adafruit.com/products/6349>`_
4345

4446
Installing from PyPI
@@ -93,8 +95,24 @@ Or the following command to update an existing version:
9395
Usage Example
9496
=============
9597

96-
.. todo:: Add a quick, simple example. It and other examples should live in the
97-
examples folder and be included in docs/examples.rst.
98+
.. code-block:: python
99+
100+
import time
101+
import board
102+
import adafruit_ina23x
103+
104+
i2c = board.I2C()
105+
ina23x = adafruit_ina23x.INA23X(i2c)
106+
107+
while True:
108+
print(f"Current: {ina23x.current * 1000:.2f} mA")
109+
print(f"Bus Voltage: {ina23x.bus_voltage:.2f} V")
110+
print(f"Shunt Voltage: {ina23x.shunt_voltage * 1000:.2f} mV")
111+
print(f"Power: {ina23x.power * 1000:.2f} mW")
112+
print(f"Temperature: {ina23x.die_temperature:.2f} °C")
113+
print()
114+
115+
time.sleep(2)
98116
99117
Documentation
100118
=============

adafruit_ina23x.py

Lines changed: 142 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
21
# SPDX-FileCopyrightText: Copyright (c) 2025 Liz Clark for Adafruit Industries
32
#
43
# SPDX-License-Identifier: MIT
54
"""
65
`adafruit_ina23x`
76
================================================================================
87
9-
CircuitPython driver for the INA237 and INA238 DC Current Voltage Power Monitor
8+
CircuitPython driver for the INA237 and INA238 DC Current Voltage Power Monitors
109
1110
1211
* Author(s): Liz Clark
@@ -16,22 +15,155 @@
1615
1716
**Hardware:**
1817
19-
.. todo:: Add links to any specific hardware product page(s), or category page(s).
20-
Use unordered list & hyperlink rST inline format: "* `Link Text <url>`_"
18+
* `Adafruit INA237 Breakout <https://www.adafruit.com/product/6340>`_
19+
* `Adafruit INA238 Breakout <https://www.adafruit.com/product/6349>`_
2120
2221
**Software and Dependencies:**
2322
2423
* Adafruit CircuitPython firmware for the supported boards:
2524
https://circuitpython.org/downloads
2625
27-
.. todo:: Uncomment or remove the Bus Device and/or the Register library dependencies
28-
based on the library's use of either.
29-
30-
# * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
31-
# * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
26+
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
27+
* Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
28+
* Adafruit CircuitPython INA228 library: https://github.com/adafruit/Adafruit_CircuitPython_INA228
3229
"""
3330

34-
# imports
31+
import time
32+
33+
from adafruit_ina228 import INA2XX, AlertType
34+
from adafruit_register.i2c_bit import ROBit
35+
from adafruit_register.i2c_bits import ROBits, RWBits
36+
from adafruit_register.i2c_struct import ROUnaryStruct
37+
from micropython import const
38+
39+
try:
40+
import typing # pylint: disable=unused-import
41+
42+
from busio import I2C
43+
except ImportError:
44+
pass
3545

3646
__version__ = "0.0.0+auto.0"
3747
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_INA23x.git"
48+
49+
_SOVL = const(0x0C) # Shunt Overvoltage Threshold
50+
_SUVL = const(0x0D) # Shunt Undervoltage Threshold
51+
_BOVL = const(0x0E) # Bus Overvoltage Threshold
52+
_BUVL = const(0x0F) # Bus Undervoltage Threshold
53+
_TEMPLIMIT = const(0x10) # Temperature Over-Limit Threshold
54+
_PWRLIMIT = const(0x11) # Power Over-Limit Threshold
55+
56+
# Constants
57+
_INA237_DEVICE_ID = const(0x237)
58+
_INA238_DEVICE_ID = const(0x238)
59+
60+
61+
class INA23X(INA2XX): # noqa: PLR0904
62+
"""Driver for the INA237/INA238 current and power sensor.
63+
64+
:param ~busio.I2C i2c_bus: The I2C bus the INA23X is connected to.
65+
:param int address: The I2C device address. Defaults to :const:`0x40`
66+
:param bool skip_reset: Skip resetting the device on init. Defaults to False.
67+
"""
68+
69+
# INA23X-specific register bits
70+
_alert_type = RWBits(7, 0x0B, 5, register_width=2, lsb_first=False)
71+
_conversion_ready = ROBit(0x0B, 1, register_width=2, lsb_first=False)
72+
_alert_flags = ROBits(12, 0x0B, 0, register_width=2, lsb_first=False)
73+
74+
_raw_vshunt = ROUnaryStruct(0x04, ">h")
75+
_raw_current = ROUnaryStruct(0x07, ">h")
76+
_raw_power = ROUnaryStruct(0x08, ">H")
77+
78+
def __init__(self, i2c_bus: I2C, address: int = 0x40, skip_reset: bool = False) -> None:
79+
super().__init__(i2c_bus, address, skip_reset)
80+
81+
# Verify device ID (both INA237 and INA238 use compatible IDs)
82+
if self.device_id not in {_INA237_DEVICE_ID, _INA238_DEVICE_ID}:
83+
raise ValueError("Failed to find INA237/INA238 - incorrect device ID")
84+
85+
# Set INA23X defaults
86+
self.set_calibration(0.015, 10.0)
87+
88+
def set_calibration(self, shunt_res: float = 0.015, max_current: float = 10.0) -> None:
89+
"""Set the calibration based on shunt resistance and maximum expected current.
90+
91+
:param float shunt_res: Shunt resistance in ohms
92+
:param float max_current: Maximum expected current in amperes
93+
"""
94+
self._shunt_res = shunt_res
95+
# INA237/238 uses 2^15 as divisor
96+
self._current_lsb = max_current / (1 << 15)
97+
self._update_shunt_cal()
98+
99+
def _update_shunt_cal(self) -> None:
100+
"""Update the shunt calibration register."""
101+
# Scale factor based on ADC range
102+
scale = 4 if self._adc_range else 1
103+
104+
# INA237/238 formula: SHUNT_CAL = 819.2 × 10^6 × CURRENT_LSB × RSHUNT × scale
105+
shunt_cal = int(819.2e6 * self._current_lsb * self._shunt_res * scale)
106+
self._shunt_cal = min(shunt_cal, 0xFFFF)
107+
108+
@property
109+
def die_temperature(self) -> float:
110+
"""Die temperature in degrees Celsius."""
111+
# INA237/238 uses 12 bits (15:4) with 125 m°C/LSB
112+
return (self._raw_dietemp >> 4) * 0.125
113+
114+
@property
115+
def bus_voltage(self) -> float:
116+
"""Bus voltage in volts."""
117+
# INA237/238 uses 3.125 mV/LSB
118+
return self._raw_vbus * 0.003125
119+
120+
@property
121+
def shunt_voltage(self) -> float:
122+
"""Shunt voltage in volts."""
123+
# Scale depends on ADC range
124+
scale = 1.25e-6 if self._adc_range else 5.0e-6 # µV/LSB
125+
return self._raw_vshunt * scale
126+
127+
@property
128+
def current(self) -> float:
129+
"""Current in amperes."""
130+
return self._raw_current * self._current_lsb
131+
132+
@property
133+
def power(self) -> float:
134+
"""Power in watts."""
135+
# INA237/238 power LSB = 20 × current_lsb
136+
return self._raw_power * 20.0 * self._current_lsb
137+
138+
@property
139+
def conversion_ready(self) -> bool:
140+
"""Check if conversion is complete."""
141+
return bool(self._conversion_ready)
142+
143+
@property
144+
def alert_type(self) -> int:
145+
"""Alert type configuration."""
146+
return self._alert_type
147+
148+
@alert_type.setter
149+
def alert_type(self, value: int) -> None:
150+
# Alert type can be a combination of flags, so we check if all bits are valid
151+
valid_mask = (
152+
AlertType.CONVERSION_READY
153+
| AlertType.OVERTEMPERATURE
154+
| AlertType.OVERPOWER
155+
| AlertType.UNDERVOLTAGE
156+
| AlertType.OVERVOLTAGE
157+
| AlertType.UNDERSHUNT
158+
| AlertType.OVERSHUNT
159+
)
160+
if value & ~valid_mask:
161+
raise ValueError(
162+
f"Invalid alert type 0x{value:02X}. Must be a combination of AlertType.* constants"
163+
)
164+
self._alert_type = value
165+
166+
@property
167+
def alert_flags(self) -> int:
168+
"""Current alert flags."""
169+
return self._alert_flags

docs/conf.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@
2525
# Uncomment the below if you use native CircuitPython modules such as
2626
# digitalio, micropython and busio. List the modules you use. Without it, the
2727
# autodoc module docs will fail to generate with a warning.
28-
# autodoc_mock_imports = ["digitalio", "busio"]
28+
autodoc_mock_imports = ["digitalio", "busio", "adafruit_ina228", "adafruit_register"]
2929

3030
autodoc_preserve_defaults = True
3131

3232
intersphinx_mapping = {
3333
"python": ("https://docs.python.org/3", None),
3434
"BusDevice": ("https://docs.circuitpython.org/projects/busdevice/en/latest/", None),
3535
"Register": ("https://docs.circuitpython.org/projects/register/en/latest/", None),
36+
"INA228": ("https://docs.circuitpython.org/projects/ina228/en/latest/", None),
3637
"CircuitPython": ("https://docs.circuitpython.org/en/latest/", None),
3738
}
3839

docs/index.rst

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,13 @@ Table of Contents
2424
.. toctree::
2525
:caption: Tutorials
2626

27-
.. todo:: Add any Learn guide links here. If there are none, then simply delete this todo and leave
28-
the toctree above for use later.
27+
Adafruit INA23x Learn Guide <https://learn.adafruit.com/adafruit-ina237-dc-current-voltage-power-monitor>
2928

3029
.. toctree::
3130
:caption: Related Products
3231

33-
.. todo:: Add any product links here. If there are none, then simply delete this todo and leave
34-
the toctree above for use later.
32+
Adafruit INA237 85V 10A 16-bit DC Current Voltage Power Monitor - STEMMA QT <http://www.adafruit.com/products/6340>
33+
Adafruit INA238 DC Current Voltage Power Monitor - STEMMA QT <http://www.adafruit.com/products/6349>
3534

3635
.. toctree::
3736
:caption: Other Links

examples/ina23x_simpletest.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,46 @@
1-
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
21
# SPDX-FileCopyrightText: Copyright (c) 2025 Liz Clark for Adafruit Industries
32
#
4-
# SPDX-License-Identifier: Unlicense
3+
# SPDX-License-Identifier: MIT
4+
5+
"""Adafruit CircuitPython INA23x Simpletest"""
6+
7+
import time
8+
9+
import adafruit_ina228
10+
import board
11+
12+
import adafruit_ina23x
13+
14+
# Create I2C bus
15+
i2c = board.I2C()
16+
17+
# Create INA237/238 instance
18+
ina23x = adafruit_ina23x.INA23X(i2c)
19+
20+
# Configure the sensor (optional - these are just examples)
21+
# ina23x.set_calibration(0.015, 10.0) # Default values
22+
# ina23x.mode = adafruit_ina228.Mode.CONTINUOUS # Already default
23+
# ina23x.averaging_count = adafruit_ina228.AveragingCount.COUNT_4
24+
25+
conv_times = [50, 84, 150, 280, 540, 1052, 2074, 4120]
26+
avg_counts = [1, 4, 16, 64, 128, 256, 512, 1024]
27+
28+
print("CircuitPython INA23x Test")
29+
print(f"Bus conversion time: {conv_times[ina23x.bus_voltage_conv_time]} microseconds")
30+
print(f"Shunt conversion time: {conv_times[ina23x.shunt_voltage_conv_time]} microseconds")
31+
print(f"Samples averaged: {avg_counts[ina23x.averaging_count]}")
32+
print()
33+
34+
while True:
35+
print(f"Current: {ina23x.current * 1000:.2f} mA")
36+
print(f"Bus Voltage: {ina23x.bus_voltage:.2f} V")
37+
print(f"Shunt Voltage: {ina23x.shunt_voltage * 1000:.2f} mV")
38+
print(f"Power: {ina23x.power * 1000:.2f} mW")
39+
print(f"Temperature: {ina23x.die_temperature:.2f} °C")
40+
print()
41+
42+
# Check if conversion is ready (useful in triggered mode)
43+
# if ina23x.conversion_ready:
44+
# print("Conversion ready!")
45+
46+
time.sleep(2)

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
Adafruit-Blinka
77
adafruit-circuitpython-busdevice
88
adafruit-circuitpython-register
9+
adafruit-circuitpython-ina228

0 commit comments

Comments
 (0)