@@ -66,6 +66,42 @@ class Mode:
66
66
"""Single-Shot Mode"""
67
67
68
68
69
+ class Comp_Mode :
70
+ """An enum-like class representing possible ADC Comparator operating modes."""
71
+
72
+ # See datasheet "Operating Modes" section
73
+ # values here are masks for setting COMP_MODE bit in Config Register
74
+ # pylint: disable=too-few-public-methods
75
+ TRADITIONAL = 0x0000
76
+ """Traditional Compartor Mode activates above high threshold, de-activates below low"""
77
+ WINDOW = 0x0010
78
+ """Window Comparator Mode activates when reading is outside of high and low thresholds"""
79
+
80
+
81
+ class Comp_Polarity :
82
+ """An enum-like class representing possible ADC Comparator polarity modes."""
83
+
84
+ # See datasheet "Operating Modes" section
85
+ # values here are masks for setting COMP_POL bit in Config Register
86
+ # pylint: disable=too-few-public-methods
87
+ ACTIVE_LOW = 0x0000
88
+ """ALERT_RDY pin is LOW when comparator is active"""
89
+ ACTIVE_HIGH = 0x0008
90
+ """ALERT_RDY pin is HIGH when comparator is active"""
91
+
92
+
93
+ class Comp_Latch :
94
+ """An enum-like class representing possible ADC Comparator latching modes."""
95
+
96
+ # See datasheet "Operating Modes" section
97
+ # values here are masks for setting COMP_LAT bit in Config Register
98
+ # pylint: disable=too-few-public-methods
99
+ NONLATCHING = 0x0000
100
+ """ALERT_RDY pin does not latch when asserted"""
101
+ LATCHING = 0x0004
102
+ """ALERT_RDY pin remains asserted until data is read by controller"""
103
+
104
+
69
105
class ADS1x15 :
70
106
"""Base functionality for ADS1x15 analog to digital converters.
71
107
@@ -79,10 +115,17 @@ class ADS1x15:
79
115
Defaults to 0 (comparator function disabled).
80
116
:param int comparator_low_threshold: Voltage limit under which comparator de-asserts
81
117
ALERT/RDY pin. Must be lower than high threshold to use comparator
82
- function. See subclass for value range and default.
118
+ function. Range of -32768 to 32767, default -32768
83
119
:param int comparator_high_threshold: Voltage limit over which comparator asserts
84
120
ALERT/RDY pin. Must be higher than low threshold to use comparator
85
- function. See subclass for value range and default.
121
+ function. Range of -32768 to 32767, default 32767
122
+ :param Comp_Mode comparator_mode: Configures the comparator as either traditional or window.
123
+ Defaults to 'Comp_Mode.TRADITIONAL'
124
+ :param Comp_Polarity comparator_polarity: Configures the comparator output as either active
125
+ low or active high. Defaults to 'Comp_Polarity.ACTIVE_LOW'
126
+ :param Comp_Latch comparator_latch: Configures the comparator output to only stay asserted while
127
+ readings exceed threshold or latch on assertion until data is read.
128
+ Defaults to 'Comp_Latch.NONLATCHING'
86
129
:param int address: The I2C address of the device.
87
130
"""
88
131
@@ -96,18 +139,29 @@ def __init__(
96
139
comparator_queue_length : int = 0 ,
97
140
comparator_low_threshold : int = - 32768 ,
98
141
comparator_high_threshold : int = 32767 ,
142
+ comparator_mode : int = Comp_Mode .TRADITIONAL ,
143
+ comparator_polarity : int = Comp_Polarity .ACTIVE_LOW ,
144
+ comparator_latch : int = Comp_Latch .NONLATCHING ,
99
145
address : int = _ADS1X15_DEFAULT_ADDRESS ,
100
146
):
101
147
# pylint: disable=too-many-arguments
102
148
self ._last_pin_read = None
103
149
self .buf = bytearray (3 )
150
+ self .initialized = (
151
+ False # Prevents writing to ADC until all values are initialized
152
+ )
153
+ self .i2c_device = I2CDevice (i2c , address )
104
154
self .gain = gain
105
155
self .data_rate = self ._data_rate_default () if data_rate is None else data_rate
106
156
self .mode = mode
107
157
self .comparator_queue_length = comparator_queue_length
108
- self .i2c_device = I2CDevice (i2c , address )
109
158
self .comparator_low_threshold = comparator_low_threshold
110
159
self .comparator_high_threshold = comparator_high_threshold
160
+ self .comparator_mode = comparator_mode
161
+ self .comparator_polarity = comparator_polarity
162
+ self .comparator_latch = comparator_latch
163
+ self .initialized = True
164
+ self ._write_config ()
111
165
112
166
@property
113
167
def bits (self ) -> int :
@@ -125,6 +179,8 @@ def data_rate(self, rate: int) -> None:
125
179
if rate not in possible_rates :
126
180
raise ValueError ("Data rate must be one of: {}" .format (possible_rates ))
127
181
self ._data_rate = rate
182
+ if self .initialized :
183
+ self ._write_config ()
128
184
129
185
@property
130
186
def rates (self ) -> List [int ]:
@@ -147,6 +203,8 @@ def gain(self, gain: float) -> None:
147
203
if gain not in possible_gains :
148
204
raise ValueError ("Gain must be one of: {}" .format (possible_gains ))
149
205
self ._gain = gain
206
+ if self .initialized :
207
+ self ._write_config ()
150
208
151
209
@property
152
210
def gains (self ) -> List [float ]:
@@ -170,6 +228,8 @@ def comparator_queue_length(self, comparator_queue_length: int) -> None:
170
228
)
171
229
)
172
230
self ._comparator_queue_length = comparator_queue_length
231
+ if self .initialized :
232
+ self ._write_config ()
173
233
174
234
@property
175
235
def comparator_queue_lengths (self ) -> List [int ]:
@@ -226,14 +286,54 @@ def mode(self, mode: int) -> None:
226
286
if mode not in (Mode .CONTINUOUS , Mode .SINGLE ):
227
287
raise ValueError ("Unsupported mode." )
228
288
self ._mode = mode
289
+ if self .initialized :
290
+ self ._write_config ()
291
+
292
+ @property
293
+ def comparator_mode (self ) -> int :
294
+ """The ADC comparator mode."""
295
+ return self ._comparator_mode
296
+
297
+ @comparator_mode .setter
298
+ def comparator_mode (self , comp_mode : int ) -> None :
299
+ if comp_mode not in (Comp_Mode .TRADITIONAL , Comp_Mode .WINDOW ):
300
+ raise ValueError ("Unsupported mode." )
301
+ self ._comparator_mode = comp_mode
302
+ if self .initialized :
303
+ self ._write_config ()
304
+
305
+ @property
306
+ def comparator_polarity (self ) -> int :
307
+ """The ADC comparator polarity mode."""
308
+ return self ._comparator_polarity
309
+
310
+ @comparator_polarity .setter
311
+ def comparator_polarity (self , comp_pol : int ) -> None :
312
+ if comp_pol not in (Comp_Polarity .ACTIVE_LOW , Comp_Polarity .ACTIVE_HIGH ):
313
+ raise ValueError ("Unsupported mode." )
314
+ self ._comparator_polarity = comp_pol
315
+ if self .initialized :
316
+ self ._write_config ()
317
+
318
+ @property
319
+ def comparator_latch (self ) -> int :
320
+ """The ADC comparator latching mode."""
321
+ return self ._comparator_latch
229
322
230
- def read (self , pin : Pin , is_differential : bool = False ) -> int :
323
+ @comparator_latch .setter
324
+ def comparator_latch (self , comp_latch : int ) -> None :
325
+ if comp_latch not in (Comp_Latch .NONLATCHING , Comp_Latch .LATCHING ):
326
+ raise ValueError ("Unsupported mode." )
327
+ self ._comparator_latch = comp_latch
328
+ if self .initialized :
329
+ self ._write_config ()
330
+
331
+ def read (self , pin : Pin ) -> int :
231
332
"""I2C Interface for ADS1x15-based ADCs reads.
232
333
233
334
:param ~microcontroller.Pin pin: individual or differential pin.
234
335
:param bool is_differential: single-ended or differential read.
235
336
"""
236
- pin = pin if is_differential else pin + 0x04
237
337
return self ._read (pin )
238
338
239
339
def _data_rate_default (self ) -> int :
@@ -260,16 +360,7 @@ def _read(self, pin: Pin) -> int:
260
360
261
361
# Configure ADC every time before a conversion in SINGLE mode
262
362
# or changing channels in CONTINUOUS mode
263
- if self .mode == Mode .SINGLE :
264
- config = _ADS1X15_CONFIG_OS_SINGLE
265
- else :
266
- config = 0
267
- config |= (pin & 0x07 ) << _ADS1X15_CONFIG_MUX_OFFSET
268
- config |= _ADS1X15_CONFIG_GAIN [self .gain ]
269
- config |= self .mode
270
- config |= self .rate_config [self .data_rate ]
271
- config |= _ADS1X15_CONFIG_COMP_QUEUE [self .comparator_queue_length ]
272
- self ._write_register (_ADS1X15_POINTER_CONFIG , config )
363
+ self ._write_config (pin )
273
364
274
365
# Wait for conversion to complete
275
366
# ADS1x1x devices settle within a single conversion cycle
@@ -317,3 +408,60 @@ def _read_register(self, reg: int, fast: bool = False) -> int:
317
408
else :
318
409
i2c .write_then_readinto (bytearray ([reg ]), self .buf , in_end = 2 )
319
410
return self .buf [0 ] << 8 | self .buf [1 ]
411
+
412
+ def _write_config (self , pin_config : Optional [int ] = None ) -> None :
413
+ """Write to configuration register of ADC
414
+
415
+ :param int pin_config: setting for MUX value in config register
416
+ """
417
+ if pin_config is None :
418
+ pin_config = (
419
+ self ._read_register (_ADS1X15_POINTER_CONFIG ) & 0x7000
420
+ ) >> _ADS1X15_CONFIG_MUX_OFFSET
421
+
422
+ if self .mode == Mode .SINGLE :
423
+ config = _ADS1X15_CONFIG_OS_SINGLE
424
+ else :
425
+ config = 0
426
+
427
+ config |= (pin_config & 0x07 ) << _ADS1X15_CONFIG_MUX_OFFSET
428
+ config |= _ADS1X15_CONFIG_GAIN [self .gain ]
429
+ config |= self .mode
430
+ config |= self .rate_config [self .data_rate ]
431
+ config |= self .comparator_mode
432
+ config |= self .comparator_polarity
433
+ config |= self .comparator_latch
434
+ config |= _ADS1X15_CONFIG_COMP_QUEUE [self .comparator_queue_length ]
435
+ self ._write_register (_ADS1X15_POINTER_CONFIG , config )
436
+
437
+ def _read_config (self ) -> None :
438
+ """Reads Config Register and sets all properties accordingly"""
439
+ config_value = self ._read_register (_ADS1X15_POINTER_CONFIG )
440
+
441
+ self .gain = next (
442
+ key
443
+ for key , value in _ADS1X15_CONFIG_GAIN .items ()
444
+ if value == (config_value & 0x0E00 )
445
+ )
446
+ self .data_rate = next (
447
+ key
448
+ for key , value in self .rate_config .items ()
449
+ if value == (config_value & 0x00E0 )
450
+ )
451
+ self .comparator_queue_length = next (
452
+ key
453
+ for key , value in _ADS1X15_CONFIG_COMP_QUEUE .items ()
454
+ if value == (config_value & 0x0003 )
455
+ )
456
+ self .mode = Mode .SINGLE if config_value & 0x0100 else Mode .CONTINUOUS
457
+ self .comparator_mode = (
458
+ Comp_Mode .WINDOW if config_value & 0x0010 else Comp_Mode .TRADITIONAL
459
+ )
460
+ self .comparator_polarity = (
461
+ Comp_Polarity .ACTIVE_HIGH
462
+ if config_value & 0x0008
463
+ else Comp_Polarity .ACTIVE_LOW
464
+ )
465
+ self .comparator_latch = (
466
+ Comp_Latch .LATCHING if config_value & 0x0004 else Comp_Latch .NONLATCHING
467
+ )
0 commit comments