adafruit-circuitpython-ads7128 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,595 @@
1
+ # SPDX-FileCopyrightText: 2026 Liz Clark for Adafruit Industries
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ """
5
+ :py:class:`~adafruit_ads7128.ads7128.ADS7128`
6
+ ================================================================================
7
+
8
+ CircuitPython driver for the Adafruit ADS7128 8-Channel ADC and GPIO Expander
9
+
10
+ * Author(s): Liz Clark
11
+
12
+ Implementation Notes
13
+ --------------------
14
+
15
+ **Hardware:**
16
+
17
+ * `Adafruit ADS7128 8-Channel ADC and GPIO Expander <https://www.adafruit.com/product/6494>`_
18
+
19
+ **Software and Dependencies:**
20
+
21
+ * Adafruit CircuitPython firmware for the supported boards:
22
+ https://circuitpython.org/downloads
23
+
24
+ * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
25
+ """
26
+
27
+ import time
28
+
29
+ from adafruit_bus_device import i2c_device
30
+ from micropython import const
31
+
32
+ try:
33
+ from typing import Tuple
34
+
35
+ from busio import I2C
36
+ except ImportError:
37
+ pass
38
+
39
+ __version__ = "1.0.0"
40
+ __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ADS7128.git"
41
+
42
+ # Oversampling ratios
43
+ OSR_NONE = 0
44
+ """No oversampling (12-bit result)."""
45
+ OSR_2 = 1
46
+ """2x oversampling (13-bit result)."""
47
+ OSR_4 = 2
48
+ """4x oversampling (14-bit result)."""
49
+ OSR_8 = 3
50
+ """8x oversampling (15-bit result)."""
51
+ OSR_16 = 4
52
+ """16x oversampling (16-bit result)."""
53
+ OSR_32 = 5
54
+ """32x oversampling (16-bit result)."""
55
+ OSR_64 = 6
56
+ """64x oversampling (16-bit result)."""
57
+ OSR_128 = 7
58
+ """128x oversampling (16-bit result)."""
59
+
60
+ _DEFAULT_ADDR = const(0x10)
61
+
62
+ # Opcodes
63
+ _OP_READ = const(0x10)
64
+ _OP_WRITE = const(0x08)
65
+ _OP_SET_BIT = const(0x18)
66
+ _OP_CLEAR_BIT = const(0x20)
67
+
68
+ # Registers
69
+ _STATUS = const(0x00)
70
+ _GENERAL_CFG = const(0x01)
71
+ _DATA_CFG = const(0x02)
72
+ _OSR_CFG = const(0x03)
73
+ _OPMODE_CFG = const(0x04)
74
+ _PIN_CFG = const(0x05)
75
+ _GPIO_CFG = const(0x07)
76
+ _GPO_DRIVE_CFG = const(0x09)
77
+ _GPO_VALUE = const(0x0B)
78
+ _GPI_VALUE = const(0x0D)
79
+ _ZCD_BLANKING_CFG = const(0x0F)
80
+ _SEQUENCE_CFG = const(0x10)
81
+ _CHANNEL_SEL = const(0x11)
82
+ _AUTO_SEQ_CH_SEL = const(0x12)
83
+ _ALERT_CH_SEL = const(0x14)
84
+ _ALERT_PIN_CFG = const(0x17)
85
+ _EVENT_FLAG = const(0x18)
86
+ _EVENT_HIGH_FLAG = const(0x1A)
87
+ _EVENT_LOW_FLAG = const(0x1C)
88
+ _RECENT_LSB_CH0 = const(0xA0) # +2 per channel
89
+ _RMS_CFG = const(0xC0)
90
+ _RMS_LSB = const(0xC1)
91
+ _RMS_MSB = const(0xC2)
92
+ _GPO_ZCD_UPDATE_EN = const(0xE7)
93
+
94
+ # SYSTEM_STATUS bits
95
+ _BOR = const(0x01)
96
+ _CRC_ERR_IN = const(0x02)
97
+ _RMS_DONE = const(0x10)
98
+
99
+ # GENERAL_CFG bits
100
+ _RST = const(0x01)
101
+ _CAL = const(0x02)
102
+ _CNVST = const(0x08)
103
+ _DWC_EN = const(0x10)
104
+ _STATS_EN = const(0x20)
105
+ _CRC_EN = const(0x40)
106
+ _RMS_EN = const(0x80)
107
+
108
+ # SEQUENCE_CFG bits
109
+ _SEQ_MODE = const(0x01)
110
+ _SEQ_START = const(0x10)
111
+
112
+ # OPMODE_CFG bits
113
+ _OSC_SEL = const(0x10)
114
+ _CONV_MODE = const(0x20)
115
+
116
+ # DATA_CFG bits
117
+ _APPEND_CHID = const(0x10)
118
+
119
+ # ALERT_PIN_CFG bits
120
+ _ALERT_DRIVE = const(0x04)
121
+
122
+ # ZCD_BLANKING_CFG bits
123
+ _ZCD_MULT = const(0x80)
124
+
125
+ # RMS_CFG bits
126
+ _RMS_DC_SUB = const(0x04)
127
+
128
+
129
+ def _crc8(value: int) -> int:
130
+ # CRC-8-CCITT, polynomial 0x07, over a single byte
131
+ crc = value
132
+ for _ in range(8):
133
+ if crc & 0x80:
134
+ crc = ((crc << 1) ^ 0x07) & 0xFF
135
+ else:
136
+ crc = (crc << 1) & 0xFF
137
+ return crc
138
+
139
+
140
+ class ADS7128: # noqa: PLR0904
141
+ """Driver for the ADS7128 8-channel 12-bit ADC with GPIOs.
142
+
143
+ :param ~busio.I2C i2c: The I2C bus the ADS7128 is connected to.
144
+ :param int address: The I2C address of the device. Defaults to :const:`0x10`.
145
+ """
146
+
147
+ def __init__(self, i2c: "I2C", address: int = _DEFAULT_ADDR) -> None:
148
+ self.i2c_device = i2c_device.I2CDevice(i2c, address)
149
+ self._crc_enabled = False
150
+ self._crc_error = False
151
+ self._in_buf = bytearray(1)
152
+ self._out_buf = bytearray(2)
153
+ self._wbuf = bytearray(3)
154
+ self._reset()
155
+
156
+ def _read_register(self, reg: int) -> int:
157
+ if self._crc_enabled:
158
+ out = bytes((_OP_READ, _crc8(_OP_READ), reg, _crc8(reg)))
159
+ in_buf = bytearray(2)
160
+ with self.i2c_device as i2c:
161
+ i2c.write_then_readinto(out, in_buf)
162
+ if in_buf[1] != _crc8(in_buf[0]):
163
+ self._crc_error = True
164
+ return in_buf[0]
165
+ self._out_buf[0] = _OP_READ
166
+ self._out_buf[1] = reg
167
+ with self.i2c_device as i2c:
168
+ i2c.write_then_readinto(self._out_buf, self._in_buf)
169
+ return self._in_buf[0]
170
+
171
+ def _write_register(self, reg: int, data: int) -> None:
172
+ if self._crc_enabled:
173
+ out = bytes((_OP_WRITE, _crc8(_OP_WRITE), reg, _crc8(reg), data, _crc8(data)))
174
+ with self.i2c_device as i2c:
175
+ i2c.write(out)
176
+ return
177
+ self._wbuf[0] = _OP_WRITE
178
+ self._wbuf[1] = reg
179
+ self._wbuf[2] = data
180
+ with self.i2c_device as i2c:
181
+ i2c.write(self._wbuf)
182
+
183
+ def _set_bits(self, reg: int, mask: int) -> None:
184
+ if self._crc_enabled:
185
+ out = bytes((_OP_SET_BIT, _crc8(_OP_SET_BIT), reg, _crc8(reg), mask, _crc8(mask)))
186
+ with self.i2c_device as i2c:
187
+ i2c.write(out)
188
+ return
189
+ self._wbuf[0] = _OP_SET_BIT
190
+ self._wbuf[1] = reg
191
+ self._wbuf[2] = mask
192
+ with self.i2c_device as i2c:
193
+ i2c.write(self._wbuf)
194
+
195
+ def _clear_bits(self, reg: int, mask: int) -> None:
196
+ if self._crc_enabled:
197
+ out = bytes(
198
+ (
199
+ _OP_CLEAR_BIT,
200
+ _crc8(_OP_CLEAR_BIT),
201
+ reg,
202
+ _crc8(reg),
203
+ mask,
204
+ _crc8(mask),
205
+ )
206
+ )
207
+ with self.i2c_device as i2c:
208
+ i2c.write(out)
209
+ return
210
+ self._wbuf[0] = _OP_CLEAR_BIT
211
+ self._wbuf[1] = reg
212
+ self._wbuf[2] = mask
213
+ with self.i2c_device as i2c:
214
+ i2c.write(self._wbuf)
215
+
216
+ def _read_12bit(self, lsb_reg: int) -> int:
217
+ # 12-bit value is MSB-aligned across the register pair:
218
+ # MSB register = [D11:D4], LSB register = [D3:D0, 0, 0, 0, 0]
219
+ lsb = self._read_register(lsb_reg)
220
+ msb = self._read_register(lsb_reg + 1)
221
+ return (msb << 4) | (lsb >> 4)
222
+
223
+ def _reset(self) -> None:
224
+ self._write_register(_GENERAL_CFG, _RST)
225
+ time.sleep(0.005)
226
+ self._write_register(_GENERAL_CFG, _CAL)
227
+ for _ in range(1000):
228
+ if not self._read_register(_GENERAL_CFG) & _CAL:
229
+ break
230
+ time.sleep(0.001)
231
+ else:
232
+ raise RuntimeError("ADS7128 calibration timed out")
233
+ self._write_register(_STATUS, _BOR)
234
+
235
+ @staticmethod
236
+ def _check_channel(channel: int) -> None:
237
+ if not 0 <= channel <= 7:
238
+ raise ValueError("channel must be 0-7")
239
+
240
+ def _read(self, channel: int) -> int:
241
+ """Read a single 12-bit conversion (0-4095) from a channel in manual mode.
242
+
243
+ :param int channel: Channel number, 0-7.
244
+ :return: The 12-bit conversion result.
245
+ :rtype: int
246
+ """
247
+ self._check_channel(channel)
248
+ self._set_bits(_GENERAL_CFG, _STATS_EN)
249
+ chan_sel = self._read_register(_CHANNEL_SEL)
250
+ chan_sel = (chan_sel & 0xF0) | (channel & 0x0F)
251
+ self._write_register(_CHANNEL_SEL, chan_sel)
252
+ self._set_bits(_GENERAL_CFG, _CNVST)
253
+ time.sleep(0.00001)
254
+ return self._read_12bit(_RECENT_LSB_CH0 + channel * 2)
255
+
256
+ @property
257
+ def sequence_channels(self) -> int:
258
+ """Bitmask of channels included in the auto-sequence (bit 0 = CH0)."""
259
+ return self._read_register(_AUTO_SEQ_CH_SEL)
260
+
261
+ @sequence_channels.setter
262
+ def sequence_channels(self, channel_mask: int) -> None:
263
+ self._write_register(_AUTO_SEQ_CH_SEL, channel_mask & 0xFF)
264
+
265
+ def start_sequence(self) -> None:
266
+ """Start autonomous auto-sequence conversions on the selected channels."""
267
+ self._set_bits(_GENERAL_CFG, _STATS_EN)
268
+ self._set_bits(_DATA_CFG, _APPEND_CHID)
269
+ self._set_bits(_OPMODE_CFG, _CONV_MODE)
270
+ self._write_register(_SEQUENCE_CFG, _SEQ_MODE | _SEQ_START)
271
+
272
+ def stop_sequence(self) -> None:
273
+ """Stop the auto-sequence."""
274
+ self._clear_bits(_SEQUENCE_CFG, _SEQ_START)
275
+
276
+ def read_sequence_result(self) -> "Tuple[int, int]":
277
+ """Read the next conversion result from the running sequence.
278
+
279
+ :return: A ``(value, channel)`` tuple where ``value`` is the 12-bit
280
+ conversion result and ``channel`` is the channel it came from.
281
+ :rtype: tuple
282
+ """
283
+ out = bytes((_OP_READ, 0x00))
284
+ in_buf = bytearray(2)
285
+ with self.i2c_device as i2c:
286
+ i2c.write_then_readinto(out, in_buf)
287
+ value = (in_buf[0] << 4) | ((in_buf[1] >> 4) & 0x0F)
288
+ channel = in_buf[1] & 0x0F
289
+ return value, channel
290
+
291
+ @property
292
+ def oversampling(self) -> int:
293
+ """Oversampling ratio (0-7). See the ``OSR_*`` module constants."""
294
+ return self._read_register(_OSR_CFG) & 0x07
295
+
296
+ @oversampling.setter
297
+ def oversampling(self, osr: int) -> None:
298
+ if not 0 <= osr <= 7:
299
+ raise ValueError("oversampling must be 0-7")
300
+ self._write_register(_OSR_CFG, osr & 0x07)
301
+
302
+ @property
303
+ def pin_cfg(self) -> int:
304
+ """Per-channel analog (bit clear) / digital (bit set) selection bitmask."""
305
+ return self._read_register(_PIN_CFG)
306
+
307
+ @pin_cfg.setter
308
+ def pin_cfg(self, value: int) -> None:
309
+ self._write_register(_PIN_CFG, value & 0xFF)
310
+
311
+ @property
312
+ def gpio_cfg(self) -> int:
313
+ """Per-channel digital direction bitmask (bit set = output, clear = input)."""
314
+ return self._read_register(_GPIO_CFG)
315
+
316
+ @gpio_cfg.setter
317
+ def gpio_cfg(self, value: int) -> None:
318
+ self._write_register(_GPIO_CFG, value & 0xFF)
319
+
320
+ @property
321
+ def gpo_drive_cfg(self) -> int:
322
+ """Per-channel output drive bitmask (bit set = push-pull, clear = open-drain)."""
323
+ return self._read_register(_GPO_DRIVE_CFG)
324
+
325
+ @gpo_drive_cfg.setter
326
+ def gpo_drive_cfg(self, value: int) -> None:
327
+ self._write_register(_GPO_DRIVE_CFG, value & 0xFF)
328
+
329
+ @property
330
+ def gpo_value(self) -> int:
331
+ """Digital output level bitmask, one bit per channel."""
332
+ return self._read_register(_GPO_VALUE)
333
+
334
+ @gpo_value.setter
335
+ def gpo_value(self, value: int) -> None:
336
+ self._write_register(_GPO_VALUE, value & 0xFF)
337
+
338
+ @property
339
+ def gpi_value(self) -> int:
340
+ """Digital input level bitmask, one bit per channel. (read-only)"""
341
+ return self._read_register(_GPI_VALUE)
342
+
343
+ @property
344
+ def gpo_zcd_update_en(self) -> int:
345
+ """Per-channel zero-crossing-to-GPO update enable bitmask."""
346
+ return self._read_register(_GPO_ZCD_UPDATE_EN)
347
+
348
+ @gpo_zcd_update_en.setter
349
+ def gpo_zcd_update_en(self, value: int) -> None:
350
+ self._write_register(_GPO_ZCD_UPDATE_EN, value & 0xFF)
351
+
352
+ @property
353
+ def crc_enabled(self) -> bool:
354
+ """Whether CRC validation of I2C transactions is enabled."""
355
+ return self._crc_enabled
356
+
357
+ @crc_enabled.setter
358
+ def crc_enabled(self, enable: bool) -> None:
359
+ if enable:
360
+ self._set_bits(_GENERAL_CFG, _CRC_EN)
361
+ self._crc_enabled = True
362
+ else:
363
+ self._clear_bits(_GENERAL_CFG, _CRC_EN)
364
+ self._crc_enabled = False
365
+
366
+ @property
367
+ def crc_error(self) -> bool:
368
+ """``True`` if a CRC error has been detected on the I2C interface. (read-only)"""
369
+ if self._read_register(_STATUS) & _CRC_ERR_IN:
370
+ return True
371
+ return self._crc_error
372
+
373
+ def clear_crc_error(self) -> None:
374
+ """Clear the CRC error flag."""
375
+ self._crc_error = False
376
+ self._write_register(_STATUS, _CRC_ERR_IN)
377
+
378
+ @property
379
+ def statistics_enabled(self) -> bool:
380
+ """Whether min/max/recent statistics tracking is enabled."""
381
+ return bool(self._read_register(_GENERAL_CFG) & _STATS_EN)
382
+
383
+ @statistics_enabled.setter
384
+ def statistics_enabled(self, enable: bool) -> None:
385
+ if enable:
386
+ self._set_bits(_GENERAL_CFG, _STATS_EN)
387
+ else:
388
+ self._clear_bits(_GENERAL_CFG, _STATS_EN)
389
+
390
+ def reset_statistics(self) -> None:
391
+ """Clear all recorded statistics and restart recording."""
392
+ self._clear_bits(_GENERAL_CFG, _STATS_EN)
393
+ self._set_bits(_GENERAL_CFG, _STATS_EN)
394
+
395
+ @property
396
+ def dwc_enabled(self) -> bool:
397
+ """Whether the digital window comparator is enabled."""
398
+ return bool(self._read_register(_GENERAL_CFG) & _DWC_EN)
399
+
400
+ @dwc_enabled.setter
401
+ def dwc_enabled(self, enable: bool) -> None:
402
+ if enable:
403
+ self._set_bits(_GENERAL_CFG, _DWC_EN)
404
+ else:
405
+ self._clear_bits(_GENERAL_CFG, _DWC_EN)
406
+
407
+ @property
408
+ def event_flags(self) -> int:
409
+ """Combined high/low threshold event flags, one bit per channel. (read-only)"""
410
+ return self._read_register(_EVENT_FLAG)
411
+
412
+ @property
413
+ def event_high_flags(self) -> int:
414
+ """High threshold event flags, one bit per channel. (read-only)"""
415
+ return self._read_register(_EVENT_HIGH_FLAG)
416
+
417
+ @property
418
+ def event_low_flags(self) -> int:
419
+ """Low threshold event flags, one bit per channel. (read-only)"""
420
+ return self._read_register(_EVENT_LOW_FLAG)
421
+
422
+ def clear_event_flags(self) -> None:
423
+ """Clear all high and low threshold event flags."""
424
+ self._write_register(_EVENT_HIGH_FLAG, 0xFF)
425
+ self._write_register(_EVENT_LOW_FLAG, 0xFF)
426
+
427
+ @property
428
+ def alert_push_pull(self) -> bool:
429
+ """ALERT pin drive: ``True`` for push-pull, ``False`` for open-drain."""
430
+ return bool(self._read_register(_ALERT_PIN_CFG) & _ALERT_DRIVE)
431
+
432
+ @alert_push_pull.setter
433
+ def alert_push_pull(self, value: bool) -> None:
434
+ cfg = self._read_register(_ALERT_PIN_CFG)
435
+ if value:
436
+ cfg |= _ALERT_DRIVE
437
+ else:
438
+ cfg &= ~_ALERT_DRIVE & 0xFF
439
+ self._write_register(_ALERT_PIN_CFG, cfg)
440
+
441
+ @property
442
+ def alert_logic(self) -> int:
443
+ """ALERT pin logic: 0=active low, 1=active high, 2=pulsed low, 3=pulsed high."""
444
+ return self._read_register(_ALERT_PIN_CFG) & 0x03
445
+
446
+ @alert_logic.setter
447
+ def alert_logic(self, value: int) -> None:
448
+ if not 0 <= value <= 3:
449
+ raise ValueError("alert_logic must be 0-3")
450
+ cfg = self._read_register(_ALERT_PIN_CFG)
451
+ cfg = (cfg & ~0x03 & 0xFF) | value
452
+ self._write_register(_ALERT_PIN_CFG, cfg)
453
+
454
+ @property
455
+ def alert_channels(self) -> int:
456
+ """Bitmask of channels that can trigger the ALERT pin (bit 0 = CH0)."""
457
+ return self._read_register(_ALERT_CH_SEL)
458
+
459
+ @alert_channels.setter
460
+ def alert_channels(self, channel_mask: int) -> None:
461
+ self._write_register(_ALERT_CH_SEL, channel_mask & 0xFF)
462
+
463
+ @property
464
+ def low_power_oscillator(self) -> bool:
465
+ """Use the low-power oscillator (``True``) or high-speed oscillator (``False``)."""
466
+ return bool(self._read_register(_OPMODE_CFG) & _OSC_SEL)
467
+
468
+ @low_power_oscillator.setter
469
+ def low_power_oscillator(self, value: bool) -> None:
470
+ cfg = self._read_register(_OPMODE_CFG)
471
+ if value:
472
+ cfg |= _OSC_SEL
473
+ else:
474
+ cfg &= ~_OSC_SEL & 0xFF
475
+ self._write_register(_OPMODE_CFG, cfg)
476
+
477
+ @property
478
+ def clock_divider(self) -> int:
479
+ """Autonomous-mode sampling clock divider, 0-15."""
480
+ return self._read_register(_OPMODE_CFG) & 0x0F
481
+
482
+ @clock_divider.setter
483
+ def clock_divider(self, divider: int) -> None:
484
+ if not 0 <= divider <= 15:
485
+ raise ValueError("clock_divider must be 0-15")
486
+ cfg = self._read_register(_OPMODE_CFG)
487
+ cfg = (cfg & 0xF0) | (divider & 0x0F)
488
+ self._write_register(_OPMODE_CFG, cfg)
489
+
490
+ @property
491
+ def zcd_channel(self) -> int:
492
+ """Analog channel monitored by the zero-crossing detector, 0-7."""
493
+ return (self._read_register(_CHANNEL_SEL) >> 4) & 0x0F
494
+
495
+ @zcd_channel.setter
496
+ def zcd_channel(self, channel: int) -> None:
497
+ self._check_channel(channel)
498
+ reg = self._read_register(_CHANNEL_SEL)
499
+ reg = (reg & 0x0F) | (channel << 4)
500
+ self._write_register(_CHANNEL_SEL, reg)
501
+
502
+ @property
503
+ def zcd_blanking(self) -> int:
504
+ """Zero-crossing blanking count, 0-127 (conversions skipped after an event)."""
505
+ return self._read_register(_ZCD_BLANKING_CFG) & 0x7F
506
+
507
+ @zcd_blanking.setter
508
+ def zcd_blanking(self, count: int) -> None:
509
+ if not 0 <= count <= 127:
510
+ raise ValueError("zcd_blanking must be 0-127")
511
+ reg = self._read_register(_ZCD_BLANKING_CFG)
512
+ reg = (reg & _ZCD_MULT) | (count & 0x7F)
513
+ self._write_register(_ZCD_BLANKING_CFG, reg)
514
+
515
+ @property
516
+ def zcd_blanking_multiply(self) -> bool:
517
+ """When ``True``, the zero-crossing blanking count is multiplied by 8."""
518
+ return bool(self._read_register(_ZCD_BLANKING_CFG) & _ZCD_MULT)
519
+
520
+ @zcd_blanking_multiply.setter
521
+ def zcd_blanking_multiply(self, value: bool) -> None:
522
+ reg = self._read_register(_ZCD_BLANKING_CFG)
523
+ if value:
524
+ reg |= _ZCD_MULT
525
+ else:
526
+ reg &= ~_ZCD_MULT & 0xFF
527
+ self._write_register(_ZCD_BLANKING_CFG, reg)
528
+
529
+ @property
530
+ def rms_enabled(self) -> bool:
531
+ """Whether the RMS computation module is enabled.
532
+
533
+ Setting this to ``True`` clears any previous result and starts a new
534
+ computation using samples from autonomous conversion mode.
535
+ """
536
+ return bool(self._read_register(_GENERAL_CFG) & _RMS_EN)
537
+
538
+ @rms_enabled.setter
539
+ def rms_enabled(self, enable: bool) -> None:
540
+ if enable:
541
+ self._set_bits(_GENERAL_CFG, _RMS_EN)
542
+ else:
543
+ self._clear_bits(_GENERAL_CFG, _RMS_EN)
544
+
545
+ @property
546
+ def rms_channel(self) -> int:
547
+ """Analog channel the RMS module monitors, 0-7."""
548
+ return (self._read_register(_RMS_CFG) >> 4) & 0x0F
549
+
550
+ @rms_channel.setter
551
+ def rms_channel(self, channel: int) -> None:
552
+ self._check_channel(channel)
553
+ reg = self._read_register(_RMS_CFG)
554
+ reg = (reg & 0x0F) | (channel << 4)
555
+ self._write_register(_RMS_CFG, reg)
556
+
557
+ @property
558
+ def rms_samples(self) -> int:
559
+ """RMS sample-count setting: 0=1024, 1=4096, 2=16384, 3=65536 samples."""
560
+ return self._read_register(_RMS_CFG) & 0x03
561
+
562
+ @rms_samples.setter
563
+ def rms_samples(self, setting: int) -> None:
564
+ if not 0 <= setting <= 3:
565
+ raise ValueError("rms_samples must be 0-3")
566
+ reg = self._read_register(_RMS_CFG)
567
+ reg = (reg & 0xFC) | (setting & 0x03)
568
+ self._write_register(_RMS_CFG, reg)
569
+
570
+ @property
571
+ def rms_dc_subtract(self) -> bool:
572
+ """Whether the DC component is subtracted before the RMS calculation."""
573
+ return bool(self._read_register(_RMS_CFG) & _RMS_DC_SUB)
574
+
575
+ @rms_dc_subtract.setter
576
+ def rms_dc_subtract(self, enable: bool) -> None:
577
+ if enable:
578
+ self._set_bits(_RMS_CFG, _RMS_DC_SUB)
579
+ else:
580
+ self._clear_bits(_RMS_CFG, _RMS_DC_SUB)
581
+
582
+ @property
583
+ def rms(self) -> int:
584
+ """The 16-bit RMS result over the configured number of samples. (read-only)"""
585
+ lsb = self._read_register(_RMS_LSB)
586
+ msb = self._read_register(_RMS_MSB)
587
+ return (msb << 8) | lsb
588
+
589
+ @property
590
+ def rms_done(self) -> bool:
591
+ """``True`` if the RMS computation is complete. Reading clears the flag. (read-only)"""
592
+ if self._read_register(_STATUS) & _RMS_DONE:
593
+ self._set_bits(_STATUS, _RMS_DONE)
594
+ return True
595
+ return False
@@ -0,0 +1,167 @@
1
+ # SPDX-FileCopyrightText: 2026 Liz Clark for Adafruit Industries
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ """
6
+ :py:class:`~adafruit_ads7128.analog_in.AnalogIn`
7
+ ======================================================
8
+ AnalogIn for ADC readings.
9
+
10
+ * Author(s): Liz Clark
11
+
12
+ """
13
+
14
+ from micropython import const
15
+
16
+ from adafruit_ads7128.ads7128 import ADS7128
17
+
18
+ __version__ = "1.0.0"
19
+ __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ADS7128.git"
20
+
21
+ _EVENT_RGN = const(0x1E)
22
+ _HYSTERESIS_CH0 = const(0x20) # per-channel block base, +4 per channel
23
+ _MAX_LSB_CH0 = const(0x60) # +2 per channel
24
+ _MIN_LSB_CH0 = const(0x80)
25
+ _RECENT_LSB_CH0 = const(0xA0) # +2 per channel
26
+
27
+
28
+ class AnalogIn:
29
+ """AnalogIn-compatible wrapper for ADS7128 single-ended readings.
30
+
31
+ Provides a :attr:`value` property scaled to a 16-bit unsigned range
32
+ ``[0, 65535]`` and a :attr:`voltage` property in volts, matching the
33
+ CircuitPython ``analogio.AnalogIn`` API.
34
+
35
+ :param ADS7128 adc: The ADS7128 driver instance.
36
+ :param int pin: Channel number (0-7).
37
+ """
38
+
39
+ def __init__(self, adc: ADS7128, pin: int) -> None:
40
+ if not isinstance(adc, ADS7128):
41
+ raise ValueError("adc must be an ADS7128 instance")
42
+ if pin < 0 or pin > 7:
43
+ raise ValueError("pin must be 0-7")
44
+ self._adc = adc
45
+ self._pin = pin
46
+ adc.pin_cfg = adc.pin_cfg & ~(1 << pin) & 0xFF
47
+
48
+ @property
49
+ def value(self) -> int:
50
+ """ADC reading as an unsigned 16-bit integer in the range ``[0, 65535]``.
51
+
52
+ The 12-bit conversion result is scaled to 16 bits to match the
53
+ ``analogio.AnalogIn`` API.
54
+ """
55
+ raw = self._adc._read(self._pin)
56
+ return min((raw * 65535) // 4095, 65535)
57
+
58
+ def voltage(self, reference_voltage: float = 5.0) -> float:
59
+ """Read the channel and convert the result to volts.
60
+
61
+ :param float reference_voltage: ADC reference voltage in volts.
62
+ Defaults to :const:`5.0` to match the device's default reference.
63
+ :return: The measured voltage in volts.
64
+ :rtype: float
65
+ """
66
+ return (self._adc._read(self._pin) / 4096.0) * reference_voltage
67
+
68
+ @property
69
+ def max(self) -> int:
70
+ """Maximum value recorded on this channel, in 12-bit counts. (read-only)
71
+
72
+ Requires :attr:`ADS7128.statistics_enabled` to be ``True``.
73
+ """
74
+ return self._adc._read_12bit(_MAX_LSB_CH0 + self._pin * 2)
75
+
76
+ @property
77
+ def min(self) -> int:
78
+ """Minimum value recorded on this channel, in 12-bit counts. (read-only)
79
+
80
+ Requires :attr:`ADS7128.statistics_enabled` to be ``True``.
81
+ """
82
+ return self._adc._read_12bit(_MIN_LSB_CH0 + self._pin * 2)
83
+
84
+ @property
85
+ def recent(self) -> int:
86
+ """Most recent conversion recorded on this channel, in 12-bit counts. (read-only)
87
+
88
+ Requires :attr:`ADS7128.statistics_enabled` to be ``True``.
89
+ """
90
+ return self._adc._read_12bit(_RECENT_LSB_CH0 + self._pin * 2)
91
+
92
+ @property
93
+ def high_threshold(self) -> int:
94
+ """Window-comparator high threshold for this channel, in 12-bit counts (0-4095)."""
95
+ base = _HYSTERESIS_CH0 + self._pin * 4
96
+ msb = self._adc._read_register(base + 1)
97
+ hyst = self._adc._read_register(base)
98
+ return (msb << 4) | ((hyst >> 4) & 0x0F)
99
+
100
+ @high_threshold.setter
101
+ def high_threshold(self, value: int) -> None:
102
+ if not 0 <= value <= 0x0FFF:
103
+ raise ValueError("high_threshold must be 0-4095")
104
+ base = _HYSTERESIS_CH0 + self._pin * 4
105
+ self._adc._write_register(base + 1, (value >> 4) & 0xFF)
106
+ hyst = self._adc._read_register(base)
107
+ hyst = (hyst & 0x0F) | ((value & 0x0F) << 4)
108
+ self._adc._write_register(base, hyst)
109
+
110
+ @property
111
+ def low_threshold(self) -> int:
112
+ """Window-comparator low threshold for this channel, in 12-bit counts (0-4095)."""
113
+ base = _HYSTERESIS_CH0 + self._pin * 4
114
+ msb = self._adc._read_register(base + 3)
115
+ evt = self._adc._read_register(base + 2)
116
+ return (msb << 4) | ((evt >> 4) & 0x0F)
117
+
118
+ @low_threshold.setter
119
+ def low_threshold(self, value: int) -> None:
120
+ if not 0 <= value <= 0x0FFF:
121
+ raise ValueError("low_threshold must be 0-4095")
122
+ base = _HYSTERESIS_CH0 + self._pin * 4
123
+ self._adc._write_register(base + 3, (value >> 4) & 0xFF)
124
+ evt = self._adc._read_register(base + 2)
125
+ evt = (evt & 0x0F) | ((value & 0x0F) << 4)
126
+ self._adc._write_register(base + 2, evt)
127
+
128
+ @property
129
+ def hysteresis(self) -> int:
130
+ """Window-comparator hysteresis for this channel, 0-15."""
131
+ return self._adc._read_register(_HYSTERESIS_CH0 + self._pin * 4) & 0x0F
132
+
133
+ @hysteresis.setter
134
+ def hysteresis(self, value: int) -> None:
135
+ if not 0 <= value <= 15:
136
+ raise ValueError("hysteresis must be 0-15")
137
+ base = _HYSTERESIS_CH0 + self._pin * 4
138
+ reg = self._adc._read_register(base)
139
+ reg = (reg & 0xF0) | (value & 0x0F)
140
+ self._adc._write_register(base, reg)
141
+
142
+ @property
143
+ def event_region(self) -> bool:
144
+ """Comparator event region: ``True`` for in-band, ``False`` for out-of-window."""
145
+ return bool(self._adc._read_register(_EVENT_RGN) & (1 << self._pin))
146
+
147
+ @event_region.setter
148
+ def event_region(self, in_band: bool) -> None:
149
+ if in_band:
150
+ self._adc._set_bits(_EVENT_RGN, 1 << self._pin)
151
+ else:
152
+ self._adc._clear_bits(_EVENT_RGN, 1 << self._pin)
153
+
154
+ @property
155
+ def event_count(self) -> int:
156
+ """Consecutive samples before an alert triggers, 0-15 (alert after count + 1)."""
157
+ base = _HYSTERESIS_CH0 + self._pin * 4
158
+ return self._adc._read_register(base + 2) & 0x0F
159
+
160
+ @event_count.setter
161
+ def event_count(self, count: int) -> None:
162
+ if not 0 <= count <= 15:
163
+ raise ValueError("event_count must be 0-15")
164
+ base = _HYSTERESIS_CH0 + self._pin * 4
165
+ evt = self._adc._read_register(base + 2)
166
+ evt = (evt & 0xF0) | (count & 0x0F)
167
+ self._adc._write_register(base + 2, evt)
@@ -0,0 +1,188 @@
1
+ # SPDX-FileCopyrightText: 2026 Liz Clark for Adafruit Industries
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ """
6
+ :py:class:`~adafruit_ads7128.digital_inout.DigitalInOut`
7
+ ==============================================================
8
+
9
+ Digital input/output of the ADS7128.
10
+
11
+ * Author(s): Liz Clark
12
+
13
+ """
14
+
15
+ import digitalio
16
+ from micropython import const
17
+
18
+ from adafruit_ads7128.ads7128 import ADS7128
19
+
20
+ try:
21
+ from typing import Optional
22
+
23
+ from digitalio import Direction, DriveMode, Pull
24
+ except ImportError:
25
+ pass
26
+
27
+ __version__ = "1.0.0"
28
+ __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ADS7128.git"
29
+
30
+
31
+ _ZCD_CFG_CH0_3 = const(0xE3)
32
+ _ZCD_CFG_CH4_7 = const(0xE4)
33
+
34
+
35
+ def _get_bit(val: int, bit: int) -> bool:
36
+ return val & (1 << bit) > 0
37
+
38
+
39
+ def _enable_bit(val: int, bit: int) -> int:
40
+ return val | (1 << bit)
41
+
42
+
43
+ def _clear_bit(val: int, bit: int) -> int:
44
+ return val & ~(1 << bit) & 0xFF
45
+
46
+
47
+ class DigitalInOut:
48
+ """Digital input/output of the ADS7128. The interface is the same as the
49
+ ``digitalio.DigitalInOut`` class, however:
50
+
51
+ * the ADS7128 does not support pull-up or pull-down resistors;
52
+ * a channel used here is taken out of analog mode.
53
+
54
+ Open-drain outputs are supported through :attr:`drive_mode`. A
55
+ :exc:`ValueError` is raised when attempting to set an unsupported pull
56
+ configuration.
57
+
58
+ :param ADS7128 adc: The ADS7128 driver instance.
59
+ :param int pin: Channel number (0-7).
60
+ """
61
+
62
+ def __init__(self, adc: ADS7128, pin: int) -> None:
63
+ if not isinstance(adc, ADS7128):
64
+ raise ValueError("adc must be an ADS7128 instance")
65
+ if pin < 0 or pin > 7:
66
+ raise ValueError("pin must be 0-7")
67
+ self._adc = adc
68
+ self._pin = pin
69
+
70
+ def switch_to_output(
71
+ self,
72
+ value: bool = False,
73
+ drive_mode: "DriveMode" = digitalio.DriveMode.PUSH_PULL,
74
+ **kwargs,
75
+ ) -> None:
76
+ """Switch the pin to a digital output with the given starting value and
77
+ drive mode (push-pull by default).
78
+
79
+ :param bool value: Initial output level. Defaults to ``False`` (low).
80
+ :param ~digitalio.DriveMode drive_mode: Output drive mode.
81
+ """
82
+ self.direction = digitalio.Direction.OUTPUT
83
+ self.drive_mode = drive_mode
84
+ self.value = value
85
+
86
+ def switch_to_input(self, pull: "Pull" = None, **kwargs) -> None:
87
+ """Switch the pin to a digital input.
88
+
89
+ :param ~digitalio.Pull pull: Must be ``None``; pull resistors are not
90
+ supported and any other value raises :exc:`ValueError`.
91
+ """
92
+ self.direction = digitalio.Direction.INPUT
93
+ self.pull = pull
94
+
95
+ @property
96
+ def value(self) -> bool:
97
+ """The value of the pin, either ``True`` for high or ``False`` for low.
98
+
99
+ Configure the pin as an output or input before writing or reading this.
100
+ """
101
+ if _get_bit(self._adc.gpio_cfg, self._pin):
102
+ return _get_bit(self._adc.gpo_value, self._pin)
103
+ return _get_bit(self._adc.gpi_value, self._pin)
104
+
105
+ @value.setter
106
+ def value(self, val: bool) -> None:
107
+ if val:
108
+ self._adc.gpo_value = _enable_bit(self._adc.gpo_value, self._pin)
109
+ else:
110
+ self._adc.gpo_value = _clear_bit(self._adc.gpo_value, self._pin)
111
+
112
+ @property
113
+ def direction(self) -> "Direction":
114
+ """The direction of the pin, either ``digitalio.Direction.INPUT`` or
115
+ ``digitalio.Direction.OUTPUT``.
116
+ """
117
+ if _get_bit(self._adc.gpio_cfg, self._pin):
118
+ return digitalio.Direction.OUTPUT
119
+ return digitalio.Direction.INPUT
120
+
121
+ @direction.setter
122
+ def direction(self, val: "Direction") -> None:
123
+ self._adc.pin_cfg = _enable_bit(self._adc.pin_cfg, self._pin)
124
+ if val == digitalio.Direction.INPUT:
125
+ self._adc.gpio_cfg = _clear_bit(self._adc.gpio_cfg, self._pin)
126
+ elif val == digitalio.Direction.OUTPUT:
127
+ self._adc.gpio_cfg = _enable_bit(self._adc.gpio_cfg, self._pin)
128
+ else:
129
+ raise ValueError("Expected INPUT or OUTPUT direction!")
130
+
131
+ @property
132
+ def drive_mode(self) -> "DriveMode":
133
+ """The output drive mode, either ``digitalio.DriveMode.PUSH_PULL`` or
134
+ ``digitalio.DriveMode.OPEN_DRAIN``.
135
+ """
136
+ if _get_bit(self._adc.gpo_drive_cfg, self._pin):
137
+ return digitalio.DriveMode.PUSH_PULL
138
+ return digitalio.DriveMode.OPEN_DRAIN
139
+
140
+ @drive_mode.setter
141
+ def drive_mode(self, val: "DriveMode") -> None:
142
+ if val == digitalio.DriveMode.PUSH_PULL:
143
+ self._adc.gpo_drive_cfg = _enable_bit(self._adc.gpo_drive_cfg, self._pin)
144
+ elif val == digitalio.DriveMode.OPEN_DRAIN:
145
+ self._adc.gpo_drive_cfg = _clear_bit(self._adc.gpo_drive_cfg, self._pin)
146
+ else:
147
+ raise ValueError("Expected PUSH_PULL or OPEN_DRAIN drive mode!")
148
+
149
+ @property
150
+ def zcd_output(self) -> int:
151
+ """Zero-crossing-detector output mode mapped onto this GPO pin.
152
+
153
+ 0=low, 1=high, 2=ZCD signal, 3=inverted ZCD. Use with
154
+ :attr:`zcd_output_enabled`.
155
+ """
156
+ if self._pin < 4:
157
+ reg = _ZCD_CFG_CH0_3
158
+ shift = self._pin * 2
159
+ else:
160
+ reg = _ZCD_CFG_CH4_7
161
+ shift = (self._pin - 4) * 2
162
+ return (self._adc._read_register(reg) >> shift) & 0x03
163
+
164
+ @zcd_output.setter
165
+ def zcd_output(self, mode: int) -> None:
166
+ if not 0 <= mode <= 3:
167
+ raise ValueError("zcd_output must be 0-3")
168
+ if self._pin < 4:
169
+ reg = _ZCD_CFG_CH0_3
170
+ shift = self._pin * 2
171
+ else:
172
+ reg = _ZCD_CFG_CH4_7
173
+ shift = (self._pin - 4) * 2
174
+ val = self._adc._read_register(reg)
175
+ val = (val & ~(0x03 << shift) & 0xFF) | (mode << shift)
176
+ self._adc._write_register(reg, val)
177
+
178
+ @property
179
+ def zcd_output_enabled(self) -> bool:
180
+ """Whether the zero-crossing detector drives this GPO pin."""
181
+ return _get_bit(self._adc.gpo_zcd_update_en, self._pin)
182
+
183
+ @zcd_output_enabled.setter
184
+ def zcd_output_enabled(self, value: bool) -> None:
185
+ if value:
186
+ self._adc.gpo_zcd_update_en = _enable_bit(self._adc.gpo_zcd_update_en, self._pin)
187
+ else:
188
+ self._adc.gpo_zcd_update_en = _clear_bit(self._adc.gpo_zcd_update_en, self._pin)
@@ -0,0 +1,147 @@
1
+ Metadata-Version: 2.4
2
+ Name: adafruit-circuitpython-ads7128
3
+ Version: 1.0.0
4
+ Summary: CircuitPython driver for the Adafruit ADS7128 8-Channel ADC and GPIO Expander
5
+ Author-email: Adafruit Industries <circuitpython@adafruit.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/adafruit/Adafruit_CircuitPython_ADS7128
8
+ Keywords: adafruit,blinka,circuitpython,micropython,ads7128,ADC,,GPIO,expander
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Topic :: Software Development :: Libraries
11
+ Classifier: Topic :: Software Development :: Embedded Systems
12
+ Classifier: Topic :: System :: Hardware
13
+ Classifier: Programming Language :: Python :: 3
14
+ Description-Content-Type: text/x-rst
15
+ License-File: LICENSE
16
+ Requires-Dist: Adafruit-Blinka
17
+ Requires-Dist: adafruit-circuitpython-busdevice
18
+ Requires-Dist: adafruit-circuitpython-register
19
+ Provides-Extra: optional
20
+ Dynamic: license-file
21
+
22
+ Introduction
23
+ ============
24
+
25
+
26
+ .. image:: https://readthedocs.org/projects/adafruit-circuitpython-ads7128/badge/?version=latest
27
+ :target: https://docs.circuitpython.org/projects/ads7128/en/latest/
28
+ :alt: Documentation Status
29
+
30
+
31
+ .. image:: https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_Bundle/main/badges/adafruit_discord.svg
32
+ :target: https://adafru.it/discord
33
+ :alt: Discord
34
+
35
+
36
+ .. image:: https://github.com/adafruit/Adafruit_CircuitPython_ADS7128/workflows/Build%20CI/badge.svg
37
+ :target: https://github.com/adafruit/Adafruit_CircuitPython_ADS7128/actions
38
+ :alt: Build Status
39
+
40
+
41
+ .. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
42
+ :target: https://github.com/astral-sh/ruff
43
+ :alt: Code Style: Ruff
44
+
45
+ CircuitPython driver for the Adafruit ADS7128 8-Channel ADC and GPIO Expander
46
+
47
+
48
+ Dependencies
49
+ =============
50
+ This driver depends on:
51
+
52
+ * `Adafruit CircuitPython <https://github.com/adafruit/circuitpython>`_
53
+ * `Bus Device <https://github.com/adafruit/Adafruit_CircuitPython_BusDevice>`_
54
+ * `Register <https://github.com/adafruit/Adafruit_CircuitPython_Register>`_
55
+
56
+ Please ensure all dependencies are available on the CircuitPython filesystem.
57
+ This is easily achieved by downloading
58
+ `the Adafruit library and driver bundle <https://circuitpython.org/libraries>`_
59
+ or individual libraries can be installed using
60
+ `circup <https://github.com/adafruit/circup>`_.
61
+
62
+ `Purchase one from the Adafruit shop <http://www.adafruit.com/products/6494>`_
63
+
64
+ Installing from PyPI
65
+ =====================
66
+
67
+ On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from
68
+ PyPI <https://pypi.org/project/adafruit-circuitpython-ads7128/>`_.
69
+ To install for current user:
70
+
71
+ .. code-block:: shell
72
+
73
+ pip3 install adafruit-circuitpython-ads7128
74
+
75
+ To install system-wide (this may be required in some cases):
76
+
77
+ .. code-block:: shell
78
+
79
+ sudo pip3 install adafruit-circuitpython-ads7128
80
+
81
+ To install in a virtual environment in your current project:
82
+
83
+ .. code-block:: shell
84
+
85
+ mkdir project-name && cd project-name
86
+ python3 -m venv .venv
87
+ source .env/bin/activate
88
+ pip3 install adafruit-circuitpython-ads7128
89
+
90
+ Installing to a Connected CircuitPython Device with Circup
91
+ ==========================================================
92
+
93
+ Make sure that you have ``circup`` installed in your Python environment.
94
+ Install it with the following command if necessary:
95
+
96
+ .. code-block:: shell
97
+
98
+ pip3 install circup
99
+
100
+ With ``circup`` installed and your CircuitPython device connected use the
101
+ following command to install:
102
+
103
+ .. code-block:: shell
104
+
105
+ circup install adafruit_ads7128
106
+
107
+ Or the following command to update an existing version:
108
+
109
+ .. code-block:: shell
110
+
111
+ circup update
112
+
113
+ Usage Example
114
+ =============
115
+
116
+ .. code-block:: python
117
+
118
+ import time
119
+
120
+ import board
121
+
122
+ from adafruit_ads7128.ads7128 import ADS7128
123
+ from adafruit_ads7128.analog_in import AnalogIn
124
+
125
+ REFERENCE_VOLTAGE = 3.3
126
+
127
+ i2c = board.I2C()
128
+ adc = ADS7128(i2c)
129
+ channel = AnalogIn(adc, 0)
130
+
131
+ while True:
132
+ print(f"value: {channel.value} voltage: {channel.voltage(REFERENCE_VOLTAGE):.3f} V")
133
+ time.sleep(1.0)
134
+
135
+ Documentation
136
+ =============
137
+ API documentation for this library can be found on `Read the Docs <https://docs.circuitpython.org/projects/ads7128/en/latest/>`_.
138
+
139
+ For information on building library documentation, please check out
140
+ `this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.
141
+
142
+ Contributing
143
+ ============
144
+
145
+ Contributions are welcome! Please read our `Code of Conduct
146
+ <https://github.com/adafruit/Adafruit_CircuitPython_ADS7128/blob/HEAD/CODE_OF_CONDUCT.md>`_
147
+ before contributing to help this project stay welcoming.
@@ -0,0 +1,8 @@
1
+ adafruit_ads7128/ads7128.py,sha256=Gqra7hlDzWPXs1MGMyerz8VzygFLVvB7tCB6h-DmG-0,19505
2
+ adafruit_ads7128/analog_in.py,sha256=bhJRRHnISrIAOjEparXZjFOCvxac7r2p2I5AaWWBNU0,6094
3
+ adafruit_ads7128/digital_inout.py,sha256=qndR0Sygo3rDyN9N2AOXq13kfRdiOjPsSgaBS1mCI-U,6301
4
+ adafruit_circuitpython_ads7128-1.0.0.dist-info/licenses/LICENSE,sha256=0JsO0yQOspYeKuhk2Y_s1wan9NO0DYeWSRJBrYJdeko,1100
5
+ adafruit_circuitpython_ads7128-1.0.0.dist-info/METADATA,sha256=Kh0jl5eh5LDYsvLqQRrR_S8IG4Akc5TtlmnTRczbpVw,4695
6
+ adafruit_circuitpython_ads7128-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
7
+ adafruit_circuitpython_ads7128-1.0.0.dist-info/top_level.txt,sha256=lYnOESNlST-F5z_4I2LlQ-n58vkuWz4UhKIkFpbyohI,17
8
+ adafruit_circuitpython_ads7128-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Liz Clark for Adafruit Industries
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ adafruit_ads7128