@@ -66,6 +66,42 @@ class Mode:
6666 """Single-Shot Mode"""
6767
6868
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+
69105class ADS1x15 :
70106 """Base functionality for ADS1x15 analog to digital converters.
71107
@@ -79,10 +115,17 @@ class ADS1x15:
79115 Defaults to 0 (comparator function disabled).
80116 :param int comparator_low_threshold: Voltage limit under which comparator de-asserts
81117 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
83119 :param int comparator_high_threshold: Voltage limit over which comparator asserts
84120 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'
86129 :param int address: The I2C address of the device.
87130 """
88131
@@ -96,18 +139,29 @@ def __init__(
96139 comparator_queue_length : int = 0 ,
97140 comparator_low_threshold : int = - 32768 ,
98141 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 ,
99145 address : int = _ADS1X15_DEFAULT_ADDRESS ,
100146 ):
101147 # pylint: disable=too-many-arguments
102148 self ._last_pin_read = None
103149 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 )
104154 self .gain = gain
105155 self .data_rate = self ._data_rate_default () if data_rate is None else data_rate
106156 self .mode = mode
107157 self .comparator_queue_length = comparator_queue_length
108- self .i2c_device = I2CDevice (i2c , address )
109158 self .comparator_low_threshold = comparator_low_threshold
110159 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 ()
111165
112166 @property
113167 def bits (self ) -> int :
@@ -125,6 +179,8 @@ def data_rate(self, rate: int) -> None:
125179 if rate not in possible_rates :
126180 raise ValueError ("Data rate must be one of: {}" .format (possible_rates ))
127181 self ._data_rate = rate
182+ if self .initialized :
183+ self ._write_config ()
128184
129185 @property
130186 def rates (self ) -> List [int ]:
@@ -147,6 +203,8 @@ def gain(self, gain: float) -> None:
147203 if gain not in possible_gains :
148204 raise ValueError ("Gain must be one of: {}" .format (possible_gains ))
149205 self ._gain = gain
206+ if self .initialized :
207+ self ._write_config ()
150208
151209 @property
152210 def gains (self ) -> List [float ]:
@@ -170,6 +228,8 @@ def comparator_queue_length(self, comparator_queue_length: int) -> None:
170228 )
171229 )
172230 self ._comparator_queue_length = comparator_queue_length
231+ if self .initialized :
232+ self ._write_config ()
173233
174234 @property
175235 def comparator_queue_lengths (self ) -> List [int ]:
@@ -226,14 +286,54 @@ def mode(self, mode: int) -> None:
226286 if mode not in (Mode .CONTINUOUS , Mode .SINGLE ):
227287 raise ValueError ("Unsupported mode." )
228288 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
229322
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 :
231332 """I2C Interface for ADS1x15-based ADCs reads.
232333
233334 :param ~microcontroller.Pin pin: individual or differential pin.
234335 :param bool is_differential: single-ended or differential read.
235336 """
236- pin = pin if is_differential else pin + 0x04
237337 return self ._read (pin )
238338
239339 def _data_rate_default (self ) -> int :
@@ -260,16 +360,7 @@ def _read(self, pin: Pin) -> int:
260360
261361 # Configure ADC every time before a conversion in SINGLE mode
262362 # 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 )
273364
274365 # Wait for conversion to complete
275366 # ADS1x1x devices settle within a single conversion cycle
@@ -317,3 +408,60 @@ def _read_register(self, reg: int, fast: bool = False) -> int:
317408 else :
318409 i2c .write_then_readinto (bytearray ([reg ]), self .buf , in_end = 2 )
319410 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