@@ -87,6 +87,28 @@ class Mode:
87
87
CONTINUOUS_ALL = 0x0F
88
88
89
89
90
+ class AlertType :
91
+ """Constants for alert type settings"""
92
+
93
+ NONE = 0x00
94
+ CONVERSION_READY = 0x01
95
+ OVERPOWER = 0x02
96
+ UNDERVOLTAGE = 0x04
97
+ OVERVOLTAGE = 0x08
98
+ UNDERCURRENT = 0x10
99
+ OVERCURRENT = 0x20
100
+ _VALID_VALUES = [
101
+ NONE ,
102
+ CONVERSION_READY ,
103
+ OVERPOWER ,
104
+ UNDERVOLTAGE ,
105
+ OVERVOLTAGE ,
106
+ UNDERCURRENT ,
107
+ OVERCURRENT ,
108
+ ]
109
+ _MAX_COMBINED = 0x3F
110
+
111
+
90
112
class INA228 : # noqa: PLR0904
91
113
"""Driver for the INA228 power and current sensor"""
92
114
@@ -95,8 +117,14 @@ class INA228: # noqa: PLR0904
95
117
_shunt_cal = UnaryStruct (_SHUNT_CAL , ">H" )
96
118
_diag_alrt = UnaryStruct (_DIAG_ALRT , ">H" )
97
119
_adc_range = RWBit (_CONFIG , 4 , register_width = 2 )
120
+ _alert_type = RWBits (6 , _DIAG_ALRT , 8 , register_width = 2 )
121
+ _alert_polarity_bit = RWBit (_DIAG_ALRT , 12 , register_width = 2 )
122
+ _alert_latch_bit = RWBit (_DIAG_ALRT , 15 , register_width = 2 )
123
+ _reset_bit = RWBit (_CONFIG , 15 , register_width = 2 )
124
+ _reset_accumulators_bit = RWBit (_CONFIG , 14 , register_width = 2 )
98
125
"""Operating mode"""
99
126
mode = RWBits (4 , _ADC_CONFIG , 12 , register_width = 2 )
127
+ _alert_conv_bit = RWBit (_DIAG_ALRT , 14 , register_width = 2 )
100
128
_vbus_ct = RWBits (3 , _ADC_CONFIG , 9 , register_width = 2 )
101
129
_vshunt_ct = RWBits (3 , _ADC_CONFIG , 6 , register_width = 2 )
102
130
_temper_ct = RWBits (3 , _ADC_CONFIG , 3 , register_width = 2 )
@@ -117,8 +145,13 @@ def __init__(self, i2c_bus, addr=0x40):
117
145
self .i2c_device = I2CDevice (i2c_bus , addr )
118
146
self .buf3 = bytearray (3 ) # Buffer for 24-bit registers
119
147
self .buf5 = bytearray (5 ) # Buffer for 40-bit registers
148
+ # Verify manufacturer ID (should be 0x5449 for Texas Instruments)
149
+ if self .manufacturer_id != 0x5449 :
150
+ raise RuntimeError (
151
+ f"Invalid manufacturer ID: 0x{ self .manufacturer_id :04X} (expected 0x5449)"
152
+ )
120
153
# Verify device ID
121
- dev_id = (self ._device_id >> 4 ) & 0xFFF # Get 12-bit device ID
154
+ dev_id = (self ._device_id >> 4 ) & 0xFFF
122
155
if dev_id != 0x228 :
123
156
raise RuntimeError (f"Failed to find INA228 - check your wiring! (Got ID: 0x{ dev_id :X} )" )
124
157
self ._current_lsb = 0
@@ -131,8 +164,11 @@ def __init__(self, i2c_bus, addr=0x40):
131
164
self .averaging_count = 16
132
165
133
166
def reset (self ) -> None :
134
- """Reset the INA228"""
135
- self ._config = 0x8000
167
+ """Reset the INA228 (all registers to default values)"""
168
+ self ._reset_bit = True
169
+ self ._alert_conv_bit = True
170
+ self .mode = Mode .CONTINUOUS_ALL
171
+ time .sleep (0.002 )
136
172
137
173
def _reg24 (self , reg ):
138
174
"""Read 24-bit register"""
@@ -152,7 +188,61 @@ def _reg40(self, reg):
152
188
153
189
def reset_accumulators (self ) -> None :
154
190
"""Reset the energy and charge accumulators"""
155
- self ._config = 1 << 14
191
+ self ._reset_accumulators_bit = True
192
+
193
+ @property
194
+ def adc_range (self ) -> int :
195
+ """
196
+ ADC range.
197
+ 0 = ±163.84 mV
198
+ 1 = ±40.96 mV
199
+
200
+ When using the ±40.96 mV range, the shunt calibration value is automatically scaled by 4.
201
+ """
202
+ return self ._adc_range
203
+
204
+ @adc_range .setter
205
+ def adc_range (self , value : int ):
206
+ if value not in {0 , 1 }:
207
+ raise ValueError ("ADC range must be 0 (±163.84 mV) or 1 (±40.96 mV)" )
208
+ self ._adc_range = value
209
+ self ._update_calibration ()
210
+
211
+ @property
212
+ def alert_type (self ) -> int :
213
+ """
214
+ The alert trigger type. Use AlertType constants.
215
+ Can be OR'd together for multiple triggers.
216
+
217
+ Example:
218
+ # Single alert type
219
+ sensor.alert_type = AlertType.OVERPOWER
220
+
221
+ # Multiple alert types
222
+ sensor.alert_type = AlertType.OVERPOWER | AlertType.OVERVOLTAGE
223
+ """
224
+ return self ._alert_type
225
+
226
+ @alert_type .setter
227
+ def alert_type (self , value : int ):
228
+ # Check if it's a valid combination of alert types
229
+ if value < 0 or value > AlertType ._MAX_COMBINED :
230
+ raise ValueError (f"Invalid alert type value: { value } . Must be 0-0x3F" )
231
+
232
+ # Optional: Validate that only valid bits are set
233
+ valid_mask = (
234
+ AlertType .CONVERSION_READY
235
+ | AlertType .OVERPOWER
236
+ | AlertType .UNDERVOLTAGE
237
+ | AlertType .OVERVOLTAGE
238
+ | AlertType .UNDERCURRENT
239
+ | AlertType .OVERCURRENT
240
+ )
241
+
242
+ if value & ~ valid_mask :
243
+ raise ValueError (f"Invalid alert type bits set: 0x{ value :02X} " )
244
+
245
+ self ._alert_type = value
156
246
157
247
@property
158
248
def conversion_time_bus (self ) -> int :
@@ -233,7 +323,7 @@ def set_calibration_32V_2A(self) -> None:
233
323
"""Configure for 32V and up to 2A measurements"""
234
324
self ._mode = Mode .CONTINUOUS_ALL
235
325
time .sleep (0.001 )
236
- self .set_shunt (0.1 , 2 .0 )
326
+ self .set_shunt (0.015 , 10 .0 )
237
327
self ._vbus_ct = 5
238
328
self ._vshunt_ct = 5
239
329
self ._temper_ct = 5
@@ -295,6 +385,8 @@ def current(self) -> float:
295
385
def charge (self ) -> float :
296
386
"""Accumulated charge in coulombs"""
297
387
raw = self ._reg40 (_CHARGE )
388
+ if raw & (1 << 39 ):
389
+ raw |= - 1 << 40
298
390
return raw * self ._current_lsb
299
391
300
392
@property
@@ -332,26 +424,20 @@ def conversion_time_temperature(self, usec: int):
332
424
@property
333
425
def alert_latch (self ) -> bool :
334
426
"""Alert latch setting. True=latched, False=transparent"""
335
- return bool (self ._diag_alrt & ( 1 << 15 ) )
427
+ return bool (self ._alert_latch_bit )
336
428
337
429
@alert_latch .setter
338
430
def alert_latch (self , value : bool ):
339
- if value :
340
- self ._diag_alrt |= 1 << 15
341
- else :
342
- self ._diag_alrt &= ~ (1 << 15 )
431
+ self ._alert_latch_bit = value
343
432
344
433
@property
345
434
def alert_polarity (self ) -> bool :
346
435
"""Alert polarity. True=inverted, False=normal"""
347
- return bool (self ._diag_alrt & ( 1 << 12 ) )
436
+ return bool (self ._alert_polarity_bit )
348
437
349
438
@alert_polarity .setter
350
439
def alert_polarity (self , value : bool ):
351
- if value :
352
- self ._diag_alrt |= 1 << 12
353
- else :
354
- self ._diag_alrt &= ~ (1 << 12 )
440
+ self ._alert_polarity_bit = value
355
441
356
442
@property
357
443
def shunt_voltage_overlimit (self ) -> float :
@@ -366,7 +452,7 @@ def shunt_voltage_overlimit(self, value: float):
366
452
@property
367
453
def alert_flags (self ) -> dict :
368
454
"""
369
- Get all diagnostic and alert flags
455
+ All diagnostic and alert flags
370
456
371
457
Returns a dictionary with the status of each flag:
372
458
0 commit comments