From 017fb9f425a46768bd3df0786b8bbae1d247a2b3 Mon Sep 17 00:00:00 2001 From: RoaCode Date: Tue, 23 Jul 2024 17:09:11 -0400 Subject: [PATCH 01/12] Added Comparator functionality Added controls for the COMP_QUE fields in the Config Register that handle the Comparator output. Also added an example of use. --- adafruit_ads1x15/ads1x15.py | 49 ++++++++++++++++++++++++-- adafruit_ads1x15/analog_in.py | 4 +++ examples/ads1x15_comparator_example.py | 38 ++++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 examples/ads1x15_comparator_example.py diff --git a/adafruit_ads1x15/ads1x15.py b/adafruit_ads1x15/ads1x15.py index 7f7ea11..801fc37 100644 --- a/adafruit_ads1x15/ads1x15.py +++ b/adafruit_ads1x15/ads1x15.py @@ -33,9 +33,17 @@ _ADS1X15_DEFAULT_ADDRESS = const(0x48) _ADS1X15_POINTER_CONVERSION = const(0x00) _ADS1X15_POINTER_CONFIG = const(0x01) +_ADS1X15_POINTER_LO_THRES = const(0x02) +_ADS1X15_POINTER_HI_THRES = const(0x03) + _ADS1X15_CONFIG_OS_SINGLE = const(0x8000) _ADS1X15_CONFIG_MUX_OFFSET = const(12) -_ADS1X15_CONFIG_COMP_QUE_DISABLE = const(0x0003) +_ADS1X15_CONFIG_COMP_QUEUE = { + 0: 0x0003, + 1: 0x0000, + 2: 0x0001, + 4: 0x0002, +} _ADS1X15_CONFIG_GAIN = { 2 / 3: 0x0000, 1: 0x0200, @@ -75,6 +83,7 @@ def __init__( gain: float = 1, data_rate: Optional[int] = None, mode: int = Mode.SINGLE, + compqueue: int = 0, address: int = _ADS1X15_DEFAULT_ADDRESS, ): # pylint: disable=too-many-arguments @@ -83,6 +92,7 @@ def __init__( self.gain = gain self.data_rate = self._data_rate_default() if data_rate is None else data_rate self.mode = mode + self.compqueue = compqueue self.i2c_device = I2CDevice(i2c, address) @property @@ -131,6 +141,25 @@ def gains(self) -> List[float]: g.sort() return g + @property + def compqueue(self) -> int: + """The ADC Comparator Queue.""" + return self._compqueue + + @compqueue.setter + def compqueue(self, compqueue: int) -> None: + possible_compqueues = self.compqueues + if compqueue not in possible_compqueues: + raise ValueError("Comparator Queue must be one of: {}".format(possible_compqueues)) + self._compqueue = compqueue + + @property + def compqueues(self) -> List[int]: + """Possible gain settings.""" + g = list(_ADS1X15_CONFIG_COMP_QUEUE.keys()) + g.sort() + return g + @property def mode(self) -> int: """The ADC conversion mode.""" @@ -183,7 +212,7 @@ def _read(self, pin: Pin) -> int: config |= _ADS1X15_CONFIG_GAIN[self.gain] config |= self.mode config |= self.rate_config[self.data_rate] - config |= _ADS1X15_CONFIG_COMP_QUE_DISABLE + config |= _ADS1X15_CONFIG_COMP_QUEUE[self.compqueue] self._write_register(_ADS1X15_POINTER_CONFIG, config) # Wait for conversion to complete @@ -222,6 +251,22 @@ def _write_register(self, reg: int, value: int): with self.i2c_device as i2c: i2c.write(self.buf) + def write_comparator_low_threshold(self, value: int): + """Write 16 bit value to register.""" + self.buf[0] = _ADS1X15_POINTER_LO_THRES + self.buf[1] = (value >> 8) & 0xFF + self.buf[2] = value & 0xFF + with self.i2c_device as i2c: + i2c.write(self.buf) + + def write_comparator_high_threshold(self, value: int): + """Write 16 bit value to register.""" + self.buf[0] = _ADS1X15_POINTER_HI_THRES + self.buf[1] = (value >> 8) & 0xFF + self.buf[2] = value & 0xFF + with self.i2c_device as i2c: + i2c.write(self.buf) + def _read_register(self, reg: int, fast: bool = False) -> int: """Read 16 bit register value. If fast is True, the pointer register is not updated. diff --git a/adafruit_ads1x15/analog_in.py b/adafruit_ads1x15/analog_in.py index e13e11e..ef51289 100644 --- a/adafruit_ads1x15/analog_in.py +++ b/adafruit_ads1x15/analog_in.py @@ -64,3 +64,7 @@ def voltage(self) -> float: """Returns the voltage from the ADC pin as a floating point value.""" volts = self.value * _ADS1X15_PGA_RANGE[self._ads.gain] / 32767 return volts + + def ADC_value(self, volts: float) -> int: + value = int((volts * 32767) / _ADS1X15_PGA_RANGE[self._ads.gain]) + return value diff --git a/examples/ads1x15_comparator_example.py b/examples/ads1x15_comparator_example.py new file mode 100644 index 0000000..8acc2e9 --- /dev/null +++ b/examples/ads1x15_comparator_example.py @@ -0,0 +1,38 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +import time +import board +import busio +import countio + +import adafruit_ads1x15.ads1015 as ADS +# import adafruit_ads1x15.ads1115 as ADS +from adafruit_ads1x15.analog_in import AnalogIn + +# Create the I2C bus +i2c = busio.I2C(board.SCL, board.SDA) + +# Create the ADS object +ads = ADS.ADS1015(i2c) +# ads = ADS.ADS1115(i2c) + +# Create a single-ended channel on Pin 0 +# Max counts for ADS1015 = 2047 +# ADS1115 = 32767 +chan = AnalogIn(ads, ADS.P0) + +# Create Interrupt-driven input to track comparator changes +int_pin = countio.Counter(board.GP9, edge=countio.Edge.RISE) + +ads.compqueue = 1 +ads.write_comparator_low_threshold(0x3E80) +ads.write_comparator_high_threshold(0x3E90) + +count = 0 +while True: + print(chan.value, chan.voltage) #This initiates new ADC reading + if int_pin.count > count: + print("Comparator Triggered") + count = int_pin.count + time.sleep(2) From c84a39dc9573323af4336faec1543cb38bfaca3b Mon Sep 17 00:00:00 2001 From: RoaCode Date: Tue, 23 Jul 2024 17:18:55 -0400 Subject: [PATCH 02/12] Improved Comments Added comments for new functions --- adafruit_ads1x15/ads1x15.py | 4 ++-- adafruit_ads1x15/analog_in.py | 1 + examples/ads1x15_comparator_example.py | 7 +++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/adafruit_ads1x15/ads1x15.py b/adafruit_ads1x15/ads1x15.py index 801fc37..6150338 100644 --- a/adafruit_ads1x15/ads1x15.py +++ b/adafruit_ads1x15/ads1x15.py @@ -252,7 +252,7 @@ def _write_register(self, reg: int, value: int): i2c.write(self.buf) def write_comparator_low_threshold(self, value: int): - """Write 16 bit value to register.""" + """Write 16 bit value to Comparator Low Threshold register.""" self.buf[0] = _ADS1X15_POINTER_LO_THRES self.buf[1] = (value >> 8) & 0xFF self.buf[2] = value & 0xFF @@ -260,7 +260,7 @@ def write_comparator_low_threshold(self, value: int): i2c.write(self.buf) def write_comparator_high_threshold(self, value: int): - """Write 16 bit value to register.""" + """Write 16 bit value to Comparator High Threshold register.""" self.buf[0] = _ADS1X15_POINTER_HI_THRES self.buf[1] = (value >> 8) & 0xFF self.buf[2] = value & 0xFF diff --git a/adafruit_ads1x15/analog_in.py b/adafruit_ads1x15/analog_in.py index ef51289..068d94d 100644 --- a/adafruit_ads1x15/analog_in.py +++ b/adafruit_ads1x15/analog_in.py @@ -66,5 +66,6 @@ def voltage(self) -> float: return volts def ADC_value(self, volts: float) -> int: + """Calculates integer for threshold registers from voltage level input""" value = int((volts * 32767) / _ADS1X15_PGA_RANGE[self._ads.gain]) return value diff --git a/examples/ads1x15_comparator_example.py b/examples/ads1x15_comparator_example.py index 8acc2e9..39e4512 100644 --- a/examples/ads1x15_comparator_example.py +++ b/examples/ads1x15_comparator_example.py @@ -25,9 +25,12 @@ # Create Interrupt-driven input to track comparator changes int_pin = countio.Counter(board.GP9, edge=countio.Edge.RISE) +# Set comparator to assert after 1 ADC conversion ads.compqueue = 1 -ads.write_comparator_low_threshold(0x3E80) -ads.write_comparator_high_threshold(0x3E90) +# Set comparator low threshold to 2V +ads.write_comparator_low_threshold(chan.ADC_value(2)) +# Set comparator high threshold to 2.002V. High threshold must be above low threshold +ads.write_comparator_high_threshold(chan.ADC_value(2.002)) count = 0 while True: From 7d98fde50741b5fa077d457f90705017e806506d Mon Sep 17 00:00:00 2001 From: RoaCode Date: Wed, 24 Jul 2024 15:33:51 -0400 Subject: [PATCH 03/12] Addressed PR comments Added threshold properties, changed to "comparator_queue_length" property name, added "convert to voltage" and "convert to value" functions --- adafruit_ads1x15/ads1x15.py | 71 ++++++++++++++++++-------- adafruit_ads1x15/analog_in.py | 15 ++++-- examples/ads1x15_comparator_example.py | 9 ++-- 3 files changed, 68 insertions(+), 27 deletions(-) diff --git a/adafruit_ads1x15/ads1x15.py b/adafruit_ads1x15/ads1x15.py index 6150338..fda80af 100644 --- a/adafruit_ads1x15/ads1x15.py +++ b/adafruit_ads1x15/ads1x15.py @@ -74,6 +74,9 @@ class ADS1x15: :param int data_rate: The data rate for ADC conversion in samples per second. Default value depends on the device. :param Mode mode: The conversion mode, defaults to `Mode.SINGLE`. + :param int comparator_queue_length: The number of successive conversions exceeding the comparator threshold before asserting ALERT/RDY pin, defaults to 0 (comparator function disabled). + :param int comparator_low_thres: Voltage limit under which comparator de-asserts ALERT/RDY pin. Must be lower than high threshold to use comparator function. Defaults to 0x800. + :param int comparator_high_thres: Voltage limit over which comparator asserts ALERT/RDY pin. Must be higher than low threshold to use comparator function. Defaults to 0x7FF. :param int address: The I2C address of the device. """ @@ -83,7 +86,9 @@ def __init__( gain: float = 1, data_rate: Optional[int] = None, mode: int = Mode.SINGLE, - compqueue: int = 0, + comparator_queue_length: int = 0, + comparator_low_thres: int = 0x8000, + comparator_high_thres: int = 0x7FF0, address: int = _ADS1X15_DEFAULT_ADDRESS, ): # pylint: disable=too-many-arguments @@ -92,7 +97,9 @@ def __init__( self.gain = gain self.data_rate = self._data_rate_default() if data_rate is None else data_rate self.mode = mode - self.compqueue = compqueue + self.comparator_queue_length = comparator_queue_length + self.comparator_low_thres: comparator_low_thres + self.comparator_high_thres: comparator_high_thres self.i2c_device = I2CDevice(i2c, address) @property @@ -142,24 +149,48 @@ def gains(self) -> List[float]: return g @property - def compqueue(self) -> int: + def comparator_queue_length(self) -> int: """The ADC Comparator Queue.""" - return self._compqueue + return self._comparator_queue_length - @compqueue.setter - def compqueue(self, compqueue: int) -> None: - possible_compqueues = self.compqueues - if compqueue not in possible_compqueues: - raise ValueError("Comparator Queue must be one of: {}".format(possible_compqueues)) - self._compqueue = compqueue + @comparator_queue_length.setter + def comparator_queue_length(self, comparator_queue_length: int) -> None: + possible_comparator_queue_lengths = self.comparator_queue_lengths + if comparator_queue_length not in possible_comparator_queue_lengths: + raise ValueError("Comparator Queue must be one of: {}".format(possible_comparator_queue_lengths)) + self._comparator_queue_length = comparator_queue_length @property - def compqueues(self) -> List[int]: - """Possible gain settings.""" + def comparator_queue_lengths(self) -> List[int]: + """Possible comparator queue length settings.""" g = list(_ADS1X15_CONFIG_COMP_QUEUE.keys()) g.sort() return g + @property + def comparator_low_thres(self) -> int: + """The ADC Comparator Lower Limit Threshold.""" + return self._comparator_low_thres + + @comparator_low_thres.setter + def comparator_low_thres(self, comparator_low_thres: int) -> None: + """Sets 12-bit threshold in 16-bit register in unsigned format.""" + if comparator_low_thres < 0 or comparator_low_thres > 65535: + raise ValueError("Comparator Low Threshold must be unsigned 16-bit integer between 0 and 65535") + self._comparator_low_thres = comparator_low_thres + + @property + def comparator_high_thres(self) -> int: + """The ADC Comparator Higher Limit Threshold.""" + return self._comparator_high_thres + + @comparator_high_thres.setter + def comparator_high_thres(self, comparator_high_thres: int) -> None: + """Sets 12-bit threshold in 16-bit register in unsigned format.""" + if comparator_high_thres < 0 or comparator_high_thres > 65535: + raise ValueError("Comparator High Threshold must be unsigned 16-bit integer between 0 and 65535") + self._comparator_high_thres = comparator_high_thres + @property def mode(self) -> int: """The ADC conversion mode.""" @@ -212,7 +243,7 @@ def _read(self, pin: Pin) -> int: config |= _ADS1X15_CONFIG_GAIN[self.gain] config |= self.mode config |= self.rate_config[self.data_rate] - config |= _ADS1X15_CONFIG_COMP_QUEUE[self.compqueue] + config |= _ADS1X15_CONFIG_COMP_QUEUE[self.comparator_queue_length] self._write_register(_ADS1X15_POINTER_CONFIG, config) # Wait for conversion to complete @@ -251,19 +282,17 @@ def _write_register(self, reg: int, value: int): with self.i2c_device as i2c: i2c.write(self.buf) - def write_comparator_low_threshold(self, value: int): - """Write 16 bit value to Comparator Low Threshold register.""" + def write_comparator_thresholds(self): + """Write 16 bit values to Comparator Low and High Threshold registers.""" self.buf[0] = _ADS1X15_POINTER_LO_THRES - self.buf[1] = (value >> 8) & 0xFF - self.buf[2] = value & 0xFF + self.buf[1] = (self._comparator_low_thres >> 8) & 0xFF + self.buf[2] = self._comparator_low_thres & 0xFF with self.i2c_device as i2c: i2c.write(self.buf) - def write_comparator_high_threshold(self, value: int): - """Write 16 bit value to Comparator High Threshold register.""" self.buf[0] = _ADS1X15_POINTER_HI_THRES - self.buf[1] = (value >> 8) & 0xFF - self.buf[2] = value & 0xFF + self.buf[1] = (self._comparator_high_thres >> 8) & 0xFF + self.buf[2] = self._comparator_high_thres & 0xFF with self.i2c_device as i2c: i2c.write(self.buf) diff --git a/adafruit_ads1x15/analog_in.py b/adafruit_ads1x15/analog_in.py index 068d94d..be9781a 100644 --- a/adafruit_ads1x15/analog_in.py +++ b/adafruit_ads1x15/analog_in.py @@ -62,10 +62,19 @@ def value(self) -> int: @property def voltage(self) -> float: """Returns the voltage from the ADC pin as a floating point value.""" - volts = self.value * _ADS1X15_PGA_RANGE[self._ads.gain] / 32767 + volts = self.convert_to_voltage(self.value) return volts - def ADC_value(self, volts: float) -> int: + def convert_to_value(self, volts: float) -> int: """Calculates integer for threshold registers from voltage level input""" - value = int((volts * 32767) / _ADS1X15_PGA_RANGE[self._ads.gain]) + value = round((volts * 32767) / _ADS1X15_PGA_RANGE[self._ads.gain]) + if value < 0: + value = 65536 + value return value + + def convert_to_voltage(self, value: int) -> float: + """Calculates integer for threshold registers from voltage level input""" + volts = self.value * _ADS1X15_PGA_RANGE[self._ads.gain] / 32767 + if volts > _ADS1X15_PGA_RANGE[self._ads.gain]: + volts = _ADS1X15_PGA_RANGE[self._ads.gain] - volts + return volts diff --git a/examples/ads1x15_comparator_example.py b/examples/ads1x15_comparator_example.py index 39e4512..3afcfb6 100644 --- a/examples/ads1x15_comparator_example.py +++ b/examples/ads1x15_comparator_example.py @@ -26,11 +26,14 @@ int_pin = countio.Counter(board.GP9, edge=countio.Edge.RISE) # Set comparator to assert after 1 ADC conversion -ads.compqueue = 1 +ads.comparator_queue_length = 1 + # Set comparator low threshold to 2V -ads.write_comparator_low_threshold(chan.ADC_value(2)) +ads.comparator_low_thres = chan.convert_to_value(2.000) # Set comparator high threshold to 2.002V. High threshold must be above low threshold -ads.write_comparator_high_threshold(chan.ADC_value(2.002)) +ads.comparator_high_thres = chan.convert_to_value(2.002) +# Write comparator values to the chip registers +ads.write_comparator_thresholds() count = 0 while True: From 0aa1cd73e0c96fbeef630367d333322bce3c4469 Mon Sep 17 00:00:00 2001 From: RoaCode Date: Thu, 25 Jul 2024 17:00:24 -0400 Subject: [PATCH 04/12] Moved threshold writes to setters Writing of the threshold registers moved to the setter functions, "threshold" spelled out in variables, improved readability of some comments. --- adafruit_ads1x15/ads1x15.py | 76 ++++++++++++++------------ adafruit_ads1x15/analog_in.py | 2 +- examples/ads1x15_comparator_example.py | 6 +- 3 files changed, 45 insertions(+), 39 deletions(-) diff --git a/adafruit_ads1x15/ads1x15.py b/adafruit_ads1x15/ads1x15.py index fda80af..c104530 100644 --- a/adafruit_ads1x15/ads1x15.py +++ b/adafruit_ads1x15/ads1x15.py @@ -71,12 +71,20 @@ class ADS1x15: :param ~busio.I2C i2c: The I2C bus the device is connected to. :param float gain: The ADC gain. +Search logs + :param int data_rate: The data rate for ADC conversion in samples per second. Default value depends on the device. :param Mode mode: The conversion mode, defaults to `Mode.SINGLE`. - :param int comparator_queue_length: The number of successive conversions exceeding the comparator threshold before asserting ALERT/RDY pin, defaults to 0 (comparator function disabled). - :param int comparator_low_thres: Voltage limit under which comparator de-asserts ALERT/RDY pin. Must be lower than high threshold to use comparator function. Defaults to 0x800. - :param int comparator_high_thres: Voltage limit over which comparator asserts ALERT/RDY pin. Must be higher than low threshold to use comparator function. Defaults to 0x7FF. + :param int comparator_queue_length: The number of successive conversions exceeding + the comparator threshold before asserting ALERT/RDY pin. + Defaults to 0 (comparator function disabled). + :param int comparator_low_threshold: Voltage limit under which comparator de-asserts + ALERT/RDY pin. Must be lower than high threshold to use comparator + function. Defaults to 0x8000. + :param int comparator_high_threshold: Voltage limit over which comparator asserts + ALERT/RDY pin. Must be higher than low threshold to use comparator + function. Defaults to 0x7FF0. :param int address: The I2C address of the device. """ @@ -87,8 +95,8 @@ def __init__( data_rate: Optional[int] = None, mode: int = Mode.SINGLE, comparator_queue_length: int = 0, - comparator_low_thres: int = 0x8000, - comparator_high_thres: int = 0x7FF0, + comparator_low_threshold: int = 0x8000, + comparator_high_threshold: int = 0x7FF0, address: int = _ADS1X15_DEFAULT_ADDRESS, ): # pylint: disable=too-many-arguments @@ -98,8 +106,8 @@ def __init__( self.data_rate = self._data_rate_default() if data_rate is None else data_rate self.mode = mode self.comparator_queue_length = comparator_queue_length - self.comparator_low_thres: comparator_low_thres - self.comparator_high_thres: comparator_high_thres + self.comparator_low_threshold: comparator_low_threshold + self.comparator_high_threshold: comparator_high_threshold self.i2c_device = I2CDevice(i2c, address) @property @@ -150,7 +158,7 @@ def gains(self) -> List[float]: @property def comparator_queue_length(self) -> int: - """The ADC Comparator Queue.""" + """The ADC comparator queue length.""" return self._comparator_queue_length @comparator_queue_length.setter @@ -168,28 +176,42 @@ def comparator_queue_lengths(self) -> List[int]: return g @property - def comparator_low_thres(self) -> int: + def comparator_low_threshold(self) -> int: """The ADC Comparator Lower Limit Threshold.""" - return self._comparator_low_thres + return self._comparator_low_threshold - @comparator_low_thres.setter - def comparator_low_thres(self, comparator_low_thres: int) -> None: + @comparator_low_threshold.setter + def comparator_low_threshold(self, comparator_low_threshold: int) -> None: """Sets 12-bit threshold in 16-bit register in unsigned format.""" - if comparator_low_thres < 0 or comparator_low_thres > 65535: + if comparator_low_threshold < 0 or comparator_low_threshold > 65535: raise ValueError("Comparator Low Threshold must be unsigned 16-bit integer between 0 and 65535") - self._comparator_low_thres = comparator_low_thres + self._comparator_low_threshold = comparator_low_threshold + + """Write value to chip""" + self.buf[0] = _ADS1X15_POINTER_LO_THRES + self.buf[1] = (self._comparator_low_threshold >> 8) & 0xFF + self.buf[2] = self._comparator_low_threshold & 0xFF + with self.i2c_device as i2c: + i2c.write(self.buf) @property - def comparator_high_thres(self) -> int: + def comparator_high_threshold(self) -> int: """The ADC Comparator Higher Limit Threshold.""" - return self._comparator_high_thres + return self._comparator_high_threshold - @comparator_high_thres.setter - def comparator_high_thres(self, comparator_high_thres: int) -> None: + @comparator_high_threshold.setter + def comparator_high_threshold(self, comparator_high_threshold: int) -> None: """Sets 12-bit threshold in 16-bit register in unsigned format.""" - if comparator_high_thres < 0 or comparator_high_thres > 65535: + if comparator_high_threshold < 0 or comparator_high_threshold > 65535: raise ValueError("Comparator High Threshold must be unsigned 16-bit integer between 0 and 65535") - self._comparator_high_thres = comparator_high_thres + self._comparator_high_threshold = comparator_high_threshold + + """Write value to chip""" + self.buf[0] = _ADS1X15_POINTER_HI_THRES + self.buf[1] = (self._comparator_high_threshold >> 8) & 0xFF + self.buf[2] = self._comparator_high_threshold & 0xFF + with self.i2c_device as i2c: + i2c.write(self.buf) @property def mode(self) -> int: @@ -282,20 +304,6 @@ def _write_register(self, reg: int, value: int): with self.i2c_device as i2c: i2c.write(self.buf) - def write_comparator_thresholds(self): - """Write 16 bit values to Comparator Low and High Threshold registers.""" - self.buf[0] = _ADS1X15_POINTER_LO_THRES - self.buf[1] = (self._comparator_low_thres >> 8) & 0xFF - self.buf[2] = self._comparator_low_thres & 0xFF - with self.i2c_device as i2c: - i2c.write(self.buf) - - self.buf[0] = _ADS1X15_POINTER_HI_THRES - self.buf[1] = (self._comparator_high_thres >> 8) & 0xFF - self.buf[2] = self._comparator_high_thres & 0xFF - with self.i2c_device as i2c: - i2c.write(self.buf) - def _read_register(self, reg: int, fast: bool = False) -> int: """Read 16 bit register value. If fast is True, the pointer register is not updated. diff --git a/adafruit_ads1x15/analog_in.py b/adafruit_ads1x15/analog_in.py index be9781a..b301a51 100644 --- a/adafruit_ads1x15/analog_in.py +++ b/adafruit_ads1x15/analog_in.py @@ -74,7 +74,7 @@ def convert_to_value(self, volts: float) -> int: def convert_to_voltage(self, value: int) -> float: """Calculates integer for threshold registers from voltage level input""" - volts = self.value * _ADS1X15_PGA_RANGE[self._ads.gain] / 32767 + volts = value * _ADS1X15_PGA_RANGE[self._ads.gain] / 32767 if volts > _ADS1X15_PGA_RANGE[self._ads.gain]: volts = _ADS1X15_PGA_RANGE[self._ads.gain] - volts return volts diff --git a/examples/ads1x15_comparator_example.py b/examples/ads1x15_comparator_example.py index 3afcfb6..5b64ffe 100644 --- a/examples/ads1x15_comparator_example.py +++ b/examples/ads1x15_comparator_example.py @@ -29,11 +29,9 @@ ads.comparator_queue_length = 1 # Set comparator low threshold to 2V -ads.comparator_low_thres = chan.convert_to_value(2.000) +ads.comparator_low_threshold = chan.convert_to_value(2.000) # Set comparator high threshold to 2.002V. High threshold must be above low threshold -ads.comparator_high_thres = chan.convert_to_value(2.002) -# Write comparator values to the chip registers -ads.write_comparator_thresholds() +ads.comparator_high_threshold = chan.convert_to_value(2.002) count = 0 while True: From 29ee801be9e48a2a3633bb895e8a0f0f526c62a8 Mon Sep 17 00:00:00 2001 From: RoaCode Date: Fri, 26 Jul 2024 13:46:05 -0400 Subject: [PATCH 05/12] Fixed ads1x15 init comment Fixed issues in ads1x15 init comment. Removed stray copy/paste and added more info for comparator thresholds. --- adafruit_ads1x15/ads1x15.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/adafruit_ads1x15/ads1x15.py b/adafruit_ads1x15/ads1x15.py index c104530..f950b6f 100644 --- a/adafruit_ads1x15/ads1x15.py +++ b/adafruit_ads1x15/ads1x15.py @@ -71,8 +71,6 @@ class ADS1x15: :param ~busio.I2C i2c: The I2C bus the device is connected to. :param float gain: The ADC gain. -Search logs - :param int data_rate: The data rate for ADC conversion in samples per second. Default value depends on the device. :param Mode mode: The conversion mode, defaults to `Mode.SINGLE`. @@ -81,10 +79,12 @@ class ADS1x15: Defaults to 0 (comparator function disabled). :param int comparator_low_threshold: Voltage limit under which comparator de-asserts ALERT/RDY pin. Must be lower than high threshold to use comparator - function. Defaults to 0x8000. + function. Value is 12-bit, 2's complement stored in + 16-bit register where 4 LSBs are 0. Defaults to 0x8000 (decimal -32768). :param int comparator_high_threshold: Voltage limit over which comparator asserts ALERT/RDY pin. Must be higher than low threshold to use comparator - function. Defaults to 0x7FF0. + function. Value is 12-bit, 2's complement stored in + 16-bit register where 4 LSBs are 0. Defaults to 0x7FF0 (decimal 32752). :param int address: The I2C address of the device. """ From a7306395a4e702d6cd3c4d84156ec3718207976d Mon Sep 17 00:00:00 2001 From: RoaCode Date: Mon, 29 Jul 2024 08:47:48 -0400 Subject: [PATCH 06/12] Corrected Pylint issues Disabled instance attributes req for ADS1x15 init function and shortened "possible_comparator_queue_lengths" to "possible_comp_queue_lengths" --- adafruit_ads1x15/ads1x15.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/adafruit_ads1x15/ads1x15.py b/adafruit_ads1x15/ads1x15.py index f950b6f..6559262 100644 --- a/adafruit_ads1x15/ads1x15.py +++ b/adafruit_ads1x15/ads1x15.py @@ -100,6 +100,7 @@ def __init__( address: int = _ADS1X15_DEFAULT_ADDRESS, ): # pylint: disable=too-many-arguments + # pylint: disable=too-many-instance-attributes self._last_pin_read = None self.buf = bytearray(3) self.gain = gain @@ -163,9 +164,9 @@ def comparator_queue_length(self) -> int: @comparator_queue_length.setter def comparator_queue_length(self, comparator_queue_length: int) -> None: - possible_comparator_queue_lengths = self.comparator_queue_lengths - if comparator_queue_length not in possible_comparator_queue_lengths: - raise ValueError("Comparator Queue must be one of: {}".format(possible_comparator_queue_lengths)) + possible_comp_queue_lengths = self.comparator_queue_lengths + if comparator_queue_length not in possible_comp_queue_lengths: + raise ValueError("Comparator Queue must be one of: {}".format(possible_comp_queue_lengths)) self._comparator_queue_length = comparator_queue_length @property From f74e4f97c5c9d517807bf99c2c5f82b02de4dc05 Mon Sep 17 00:00:00 2001 From: RoaCode Date: Mon, 29 Jul 2024 11:46:14 -0400 Subject: [PATCH 07/12] Correcting pylint issues Trying to fix "too many instance attributes" issue --- .pre-commit-config.yaml | 2 +- adafruit_ads1x15/ads1x15.py | 16 ++++++++++++---- examples/ads1x15_comparator_example.py | 3 ++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 70ade69..874bf5f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/pycqa/pylint - rev: v2.17.4 + rev: v3.2.6 hooks: - id: pylint name: pylint (library code) diff --git a/adafruit_ads1x15/ads1x15.py b/adafruit_ads1x15/ads1x15.py index 6559262..b8e2653 100644 --- a/adafruit_ads1x15/ads1x15.py +++ b/adafruit_ads1x15/ads1x15.py @@ -88,6 +88,7 @@ class ADS1x15: :param int address: The I2C address of the device. """ + # pylint: disable=too-many-instance-attributes def __init__( self, i2c: I2C, @@ -100,7 +101,6 @@ def __init__( address: int = _ADS1X15_DEFAULT_ADDRESS, ): # pylint: disable=too-many-arguments - # pylint: disable=too-many-instance-attributes self._last_pin_read = None self.buf = bytearray(3) self.gain = gain @@ -166,7 +166,11 @@ def comparator_queue_length(self) -> int: def comparator_queue_length(self, comparator_queue_length: int) -> None: possible_comp_queue_lengths = self.comparator_queue_lengths if comparator_queue_length not in possible_comp_queue_lengths: - raise ValueError("Comparator Queue must be one of: {}".format(possible_comp_queue_lengths)) + raise ValueError( + "Comparator Queue must be one of: {}".format( + possible_comp_queue_lengths + ) + ) self._comparator_queue_length = comparator_queue_length @property @@ -185,7 +189,9 @@ def comparator_low_threshold(self) -> int: def comparator_low_threshold(self, comparator_low_threshold: int) -> None: """Sets 12-bit threshold in 16-bit register in unsigned format.""" if comparator_low_threshold < 0 or comparator_low_threshold > 65535: - raise ValueError("Comparator Low Threshold must be unsigned 16-bit integer between 0 and 65535") + raise ValueError( + "Comparator Low Threshold must be unsigned 16-bit integer between 0 and 65535" + ) self._comparator_low_threshold = comparator_low_threshold """Write value to chip""" @@ -204,7 +210,9 @@ def comparator_high_threshold(self) -> int: def comparator_high_threshold(self, comparator_high_threshold: int) -> None: """Sets 12-bit threshold in 16-bit register in unsigned format.""" if comparator_high_threshold < 0 or comparator_high_threshold > 65535: - raise ValueError("Comparator High Threshold must be unsigned 16-bit integer between 0 and 65535") + raise ValueError( + "Comparator High Threshold must be unsigned 16-bit integer between 0 and 65535" + ) self._comparator_high_threshold = comparator_high_threshold """Write value to chip""" diff --git a/examples/ads1x15_comparator_example.py b/examples/ads1x15_comparator_example.py index 5b64ffe..25567ff 100644 --- a/examples/ads1x15_comparator_example.py +++ b/examples/ads1x15_comparator_example.py @@ -7,6 +7,7 @@ import countio import adafruit_ads1x15.ads1015 as ADS + # import adafruit_ads1x15.ads1115 as ADS from adafruit_ads1x15.analog_in import AnalogIn @@ -35,7 +36,7 @@ count = 0 while True: - print(chan.value, chan.voltage) #This initiates new ADC reading + print(chan.value, chan.voltage) # This initiates new ADC reading if int_pin.count > count: print("Comparator Triggered") count = int_pin.count From 4ba61448dafbcdfd2b5d01ae6a695dc9b4eb087e Mon Sep 17 00:00:00 2001 From: RoaCode Date: Mon, 29 Jul 2024 17:24:20 -0400 Subject: [PATCH 08/12] Moved 2's complement calculation to threshold setters Threshold properties changed to 12-bit signed integers and conversion to unsigned 16-bit numbers moved to threshold setter functions. --- adafruit_ads1x15/ads1x15.py | 38 ++++++++++++++++++++++++----------- adafruit_ads1x15/analog_in.py | 8 +++----- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/adafruit_ads1x15/ads1x15.py b/adafruit_ads1x15/ads1x15.py index b8e2653..bd38b0a 100644 --- a/adafruit_ads1x15/ads1x15.py +++ b/adafruit_ads1x15/ads1x15.py @@ -96,8 +96,8 @@ def __init__( data_rate: Optional[int] = None, mode: int = Mode.SINGLE, comparator_queue_length: int = 0, - comparator_low_threshold: int = 0x8000, - comparator_high_threshold: int = 0x7FF0, + comparator_low_threshold: int = -2048, + comparator_high_threshold: int = 2047, address: int = _ADS1X15_DEFAULT_ADDRESS, ): # pylint: disable=too-many-arguments @@ -187,17 +187,24 @@ def comparator_low_threshold(self) -> int: @comparator_low_threshold.setter def comparator_low_threshold(self, comparator_low_threshold: int) -> None: - """Sets 12-bit threshold in 16-bit register in unsigned format.""" - if comparator_low_threshold < 0 or comparator_low_threshold > 65535: + """Sets Comparator low threshold value""" + if comparator_low_threshold < -2048 or comparator_low_threshold > 2047: raise ValueError( - "Comparator Low Threshold must be unsigned 16-bit integer between 0 and 65535" + "Comparator Low Threshold must be an integer between -2048 and 2047" ) self._comparator_low_threshold = comparator_low_threshold + """Convert integer value to 12-bit twos complement and bit shift""" + if comparator_low_threshold < 0: + tempval = 4096 + comparator_low_threshold + else: + tempval = comparator_low_threshold + tempval <<= 4 + """Write value to chip""" self.buf[0] = _ADS1X15_POINTER_LO_THRES - self.buf[1] = (self._comparator_low_threshold >> 8) & 0xFF - self.buf[2] = self._comparator_low_threshold & 0xFF + self.buf[1] = (tempval >> 8) & 0xFF + self.buf[2] = tempval & 0xFF with self.i2c_device as i2c: i2c.write(self.buf) @@ -208,17 +215,24 @@ def comparator_high_threshold(self) -> int: @comparator_high_threshold.setter def comparator_high_threshold(self, comparator_high_threshold: int) -> None: - """Sets 12-bit threshold in 16-bit register in unsigned format.""" - if comparator_high_threshold < 0 or comparator_high_threshold > 65535: + """Sets Comparator high threshold value""" + if comparator_high_threshold < -2048 or comparator_high_threshold > 2047: raise ValueError( - "Comparator High Threshold must be unsigned 16-bit integer between 0 and 65535" + "Comparator High Threshold must be an integer between -2048 and 2047" ) self._comparator_high_threshold = comparator_high_threshold + """Convert integer value to 12-bit twos complement and bit shift""" + if comparator_high_threshold < 0: + tempval = 4096 + comparator_high_threshold + else: + tempval = comparator_high_threshold + tempval <<= 4 + """Write value to chip""" self.buf[0] = _ADS1X15_POINTER_HI_THRES - self.buf[1] = (self._comparator_high_threshold >> 8) & 0xFF - self.buf[2] = self._comparator_high_threshold & 0xFF + self.buf[1] = (tempval >> 8) & 0xFF + self.buf[2] = tempval & 0xFF with self.i2c_device as i2c: i2c.write(self.buf) diff --git a/adafruit_ads1x15/analog_in.py b/adafruit_ads1x15/analog_in.py index b301a51..7b40dde 100644 --- a/adafruit_ads1x15/analog_in.py +++ b/adafruit_ads1x15/analog_in.py @@ -66,14 +66,12 @@ def voltage(self) -> float: return volts def convert_to_value(self, volts: float) -> int: - """Calculates integer for threshold registers from voltage level input""" - value = round((volts * 32767) / _ADS1X15_PGA_RANGE[self._ads.gain]) - if value < 0: - value = 65536 + value + """Calculates 12-bit integer for threshold registers from voltage level input""" + value = round(volts * 2047 / _ADS1X15_PGA_RANGE[self._ads.gain]) return value def convert_to_voltage(self, value: int) -> float: - """Calculates integer for threshold registers from voltage level input""" + """Calculates voltage from 16-bit ADC reading""" volts = value * _ADS1X15_PGA_RANGE[self._ads.gain] / 32767 if volts > _ADS1X15_PGA_RANGE[self._ads.gain]: volts = _ADS1X15_PGA_RANGE[self._ads.gain] - volts From 8ddd81ca466addf34891597608eda2d0c51e6059 Mon Sep 17 00:00:00 2001 From: RoaCode Date: Wed, 31 Jul 2024 12:21:20 -0400 Subject: [PATCH 09/12] Moved threshold defaults to subclass Adapted functions to use bits properties and moved part specific settings to subclasses --- adafruit_ads1x15/ads1015.py | 8 +++- adafruit_ads1x15/ads1115.py | 6 +++ adafruit_ads1x15/ads1x15.py | 90 +++++++++++++++++------------------ adafruit_ads1x15/analog_in.py | 41 ++++++++++++---- 4 files changed, 89 insertions(+), 56 deletions(-) diff --git a/adafruit_ads1x15/ads1015.py b/adafruit_ads1x15/ads1015.py index f1ecdbe..2da65e6 100644 --- a/adafruit_ads1x15/ads1015.py +++ b/adafruit_ads1x15/ads1015.py @@ -67,6 +67,12 @@ def rate_config(self) -> Dict[int, int]: def _data_rate_default(self) -> Literal[1600]: return 1600 + def _comp_low_thres_default(self) -> Literal[0x8000]: + return 0x8000 + + def _comp_high_thres_default(self) -> Literal[0x7FF0]: + return 0x7FF0 + def _conversion_value(self, raw_adc: int) -> int: value = struct.unpack(">h", raw_adc.to_bytes(2, "big"))[0] - return value >> 4 + return value diff --git a/adafruit_ads1x15/ads1115.py b/adafruit_ads1x15/ads1115.py index a35149c..6d8c6df 100644 --- a/adafruit_ads1x15/ads1115.py +++ b/adafruit_ads1x15/ads1115.py @@ -68,6 +68,12 @@ def rate_config(self) -> Dict[int, int]: def _data_rate_default(self) -> Literal[128]: return 128 + def _comp_low_thres_default(self) -> Literal[0x8000]: + return 0x8000 + + def _comp_high_thres_default(self) -> Literal[0x7FFF]: + return 0x7FFF + def _conversion_value(self, raw_adc: int) -> int: value = struct.unpack(">h", raw_adc.to_bytes(2, "big"))[0] return value diff --git a/adafruit_ads1x15/ads1x15.py b/adafruit_ads1x15/ads1x15.py index bd38b0a..2295143 100644 --- a/adafruit_ads1x15/ads1x15.py +++ b/adafruit_ads1x15/ads1x15.py @@ -96,8 +96,8 @@ def __init__( data_rate: Optional[int] = None, mode: int = Mode.SINGLE, comparator_queue_length: int = 0, - comparator_low_threshold: int = -2048, - comparator_high_threshold: int = 2047, + comparator_low_threshold: Optional[int] = None, + comparator_high_threshold: Optional[int] = None, address: int = _ADS1X15_DEFAULT_ADDRESS, ): # pylint: disable=too-many-arguments @@ -107,9 +107,17 @@ def __init__( self.data_rate = self._data_rate_default() if data_rate is None else data_rate self.mode = mode self.comparator_queue_length = comparator_queue_length - self.comparator_low_threshold: comparator_low_threshold - self.comparator_high_threshold: comparator_high_threshold self.i2c_device = I2CDevice(i2c, address) + self.comparator_low_threshold = ( + self._comp_low_thres_default() + if comparator_low_threshold is None + else comparator_low_threshold + ) + self.comparator_high_threshold = ( + self._comp_high_thres_default() + if comparator_high_threshold is None + else comparator_high_threshold + ) @property def bits(self) -> int: @@ -185,56 +193,32 @@ def comparator_low_threshold(self) -> int: """The ADC Comparator Lower Limit Threshold.""" return self._comparator_low_threshold - @comparator_low_threshold.setter - def comparator_low_threshold(self, comparator_low_threshold: int) -> None: - """Sets Comparator low threshold value""" - if comparator_low_threshold < -2048 or comparator_low_threshold > 2047: - raise ValueError( - "Comparator Low Threshold must be an integer between -2048 and 2047" - ) - self._comparator_low_threshold = comparator_low_threshold - - """Convert integer value to 12-bit twos complement and bit shift""" - if comparator_low_threshold < 0: - tempval = 4096 + comparator_low_threshold - else: - tempval = comparator_low_threshold - tempval <<= 4 - - """Write value to chip""" - self.buf[0] = _ADS1X15_POINTER_LO_THRES - self.buf[1] = (tempval >> 8) & 0xFF - self.buf[2] = tempval & 0xFF - with self.i2c_device as i2c: - i2c.write(self.buf) - @property def comparator_high_threshold(self) -> int: """The ADC Comparator Higher Limit Threshold.""" return self._comparator_high_threshold - @comparator_high_threshold.setter - def comparator_high_threshold(self, comparator_high_threshold: int) -> None: - """Sets Comparator high threshold value""" - if comparator_high_threshold < -2048 or comparator_high_threshold > 2047: - raise ValueError( - "Comparator High Threshold must be an integer between -2048 and 2047" - ) - self._comparator_high_threshold = comparator_high_threshold + @comparator_low_threshold.setter + def comparator_low_threshold(self, value: int) -> None: + """Set comparator low threshold value for ADS1015 ADC - """Convert integer value to 12-bit twos complement and bit shift""" - if comparator_high_threshold < 0: - tempval = 4096 + comparator_high_threshold - else: - tempval = comparator_high_threshold - tempval <<= 4 + :param int value: 16-bit signed integer to write to register + """ + if value < 0 or value > 65535: + raise ValueError("Comparator Threshold value must be between 0 and 65535") + self._comparator_low_threshold = value + self._write_register(_ADS1X15_POINTER_LO_THRES, self.comparator_low_threshold) - """Write value to chip""" - self.buf[0] = _ADS1X15_POINTER_HI_THRES - self.buf[1] = (tempval >> 8) & 0xFF - self.buf[2] = tempval & 0xFF - with self.i2c_device as i2c: - i2c.write(self.buf) + @comparator_high_threshold.setter + def comparator_high_threshold(self, value: int) -> None: + """Set comparator high threshold value for ADS1015 ADC + + :param int value: 16-bit signed integer to write to register + """ + if value < 0 or value > 65535: + raise ValueError("Comparator Threshold value must be between 0 and 65535") + self._comparator_high_threshold = value + self._write_register(_ADS1X15_POINTER_HI_THRES, self.comparator_high_threshold) @property def mode(self) -> int: @@ -262,6 +246,18 @@ def _data_rate_default(self) -> int: """ raise NotImplementedError("Subclasses must implement _data_rate_default!") + def _comp_low_thres_default(self) -> int: + """Retrieve the default comparator low threshold for this ADC (in 16-bit signed int). + Should be implemented by subclasses. + """ + raise NotImplementedError("Subclasses must implement _comp_low_thres_default!") + + def _comp_high_thres_default(self) -> int: + """Retrieve the default comparator high threshold for this ADC (in 16-bit signed int). + Should be implemented by subclasses. + """ + raise NotImplementedError("Subclasses must implement _comp_high_thres_default!") + def _conversion_value(self, raw_adc: int) -> int: """Subclasses should override this function that takes the 16 raw ADC values of a conversion result and returns a signed integer value. diff --git a/adafruit_ads1x15/analog_in.py b/adafruit_ads1x15/analog_in.py index 7b40dde..6269e44 100644 --- a/adafruit_ads1x15/analog_in.py +++ b/adafruit_ads1x15/analog_in.py @@ -55,9 +55,7 @@ def value(self) -> int: Even if the underlying analog to digital converter (ADC) is lower resolution, the value is 16-bit. """ - return self._ads.read( - self._pin_setting, is_differential=self.is_differential - ) << (16 - self._ads.bits) + return self._ads.read(self._pin_setting, is_differential=self.is_differential) @property def voltage(self) -> float: @@ -67,12 +65,39 @@ def voltage(self) -> float: def convert_to_value(self, volts: float) -> int: """Calculates 12-bit integer for threshold registers from voltage level input""" - value = round(volts * 2047 / _ADS1X15_PGA_RANGE[self._ads.gain]) + + # Convert 2's complement of signed int if number is negative + if volts > 0: + value = round( + (volts / _ADS1X15_PGA_RANGE[self._ads.gain]) + * ((1 << (self._ads.bits - 1)) - 1) + ) + else: + value = round( + (volts / _ADS1X15_PGA_RANGE[self._ads.gain]) + * (1 << (self._ads.bits - 1)) + ) + value += 1 << self._ads.bits + + # Need to bit shift if value is only 12-bits + value <<= 16 - self._ads.bits return value - def convert_to_voltage(self, value: int) -> float: + def convert_to_voltage(self, value_int: int) -> float: """Calculates voltage from 16-bit ADC reading""" - volts = value * _ADS1X15_PGA_RANGE[self._ads.gain] / 32767 - if volts > _ADS1X15_PGA_RANGE[self._ads.gain]: - volts = _ADS1X15_PGA_RANGE[self._ads.gain] - volts + + if value_int & 0x8000: + # Need to convert negative number through 2's complement + value_int -= 0x10000 + + # Need to bit shift if value is only 12-bits + value_int >>= 16 - self._ads.bits + + volts = float(value_int) + volts = ( + volts + * _ADS1X15_PGA_RANGE[self._ads.gain] + / (0x7FFF >> (16 - self._ads.bits)) + ) + return volts From 657b768256ec1655d5f61d4f32f2c7202eaf8a20 Mon Sep 17 00:00:00 2001 From: RoaCode <176423185+RoaCode@users.noreply.github.com> Date: Thu, 1 Aug 2024 13:54:52 -0400 Subject: [PATCH 10/12] Updated comments with threshold register info Moved specific comments about threshold registers to subclasses --- adafruit_ads1x15/ads1015.py | 5 +++++ adafruit_ads1x15/ads1115.py | 5 +++++ adafruit_ads1x15/ads1x15.py | 6 ++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/adafruit_ads1x15/ads1015.py b/adafruit_ads1x15/ads1015.py index 2da65e6..5240810 100644 --- a/adafruit_ads1x15/ads1015.py +++ b/adafruit_ads1x15/ads1015.py @@ -65,12 +65,17 @@ def rate_config(self) -> Dict[int, int]: return _ADS1015_CONFIG_DR def _data_rate_default(self) -> Literal[1600]: + """Default data rate setting is 1600 samples per second""" return 1600 def _comp_low_thres_default(self) -> Literal[0x8000]: + """Value is 12-bit, 2's complement stored in 16-bit register where 4 LSBs are 0. + Defaults to 0x8000 as 16-bit hex (-2048 as 12-bit decimal).""" return 0x8000 def _comp_high_thres_default(self) -> Literal[0x7FF0]: + """Value is 12-bit, 2's complement stored in 16-bit register where 4 LSBs are 0. + Defaults to 0x7FF0 as 16-bit hex (2047 as 12-bit decimal).""" return 0x7FF0 def _conversion_value(self, raw_adc: int) -> int: diff --git a/adafruit_ads1x15/ads1115.py b/adafruit_ads1x15/ads1115.py index 6d8c6df..a03f8f3 100644 --- a/adafruit_ads1x15/ads1115.py +++ b/adafruit_ads1x15/ads1115.py @@ -66,12 +66,17 @@ def rate_config(self) -> Dict[int, int]: return _ADS1115_CONFIG_DR def _data_rate_default(self) -> Literal[128]: + """Default data rate setting is 128 samples per second""" return 128 def _comp_low_thres_default(self) -> Literal[0x8000]: + """Value is 16-bit, 2's complement. + Defaults to 0x8000 as 16-bit hex (-32768 16-bit decimal).""" return 0x8000 def _comp_high_thres_default(self) -> Literal[0x7FFF]: + """Value is 16-bit, 2's complement. + Defaults to 0x7FFF as 16-bit hex (32767 16-bit decimal).""" return 0x7FFF def _conversion_value(self, raw_adc: int) -> int: diff --git a/adafruit_ads1x15/ads1x15.py b/adafruit_ads1x15/ads1x15.py index 2295143..97d99cf 100644 --- a/adafruit_ads1x15/ads1x15.py +++ b/adafruit_ads1x15/ads1x15.py @@ -79,12 +79,10 @@ class ADS1x15: Defaults to 0 (comparator function disabled). :param int comparator_low_threshold: Voltage limit under which comparator de-asserts ALERT/RDY pin. Must be lower than high threshold to use comparator - function. Value is 12-bit, 2's complement stored in - 16-bit register where 4 LSBs are 0. Defaults to 0x8000 (decimal -32768). + function. See subclass for value range and default. :param int comparator_high_threshold: Voltage limit over which comparator asserts ALERT/RDY pin. Must be higher than low threshold to use comparator - function. Value is 12-bit, 2's complement stored in - 16-bit register where 4 LSBs are 0. Defaults to 0x7FF0 (decimal 32752). + function. See subclass for value range and default. :param int address: The I2C address of the device. """ From f7fd261ced6e6f48361aad9c2791b6bc02bb752c Mon Sep 17 00:00:00 2001 From: RoaCode <176423185+RoaCode@users.noreply.github.com> Date: Mon, 5 Aug 2024 13:36:30 -0400 Subject: [PATCH 11/12] Removed 2s Complement calculations Conversion calculations handled with signed integers, removing 2s complement. Removed subclass comparator threshold defaults since both chips have same default values. --- adafruit_ads1x15/ads1015.py | 10 ------- adafruit_ads1x15/ads1115.py | 10 ------- adafruit_ads1x15/ads1x15.py | 52 +++++++++++++++-------------------- adafruit_ads1x15/analog_in.py | 30 ++++---------------- 4 files changed, 28 insertions(+), 74 deletions(-) diff --git a/adafruit_ads1x15/ads1015.py b/adafruit_ads1x15/ads1015.py index 5240810..38bf7f7 100644 --- a/adafruit_ads1x15/ads1015.py +++ b/adafruit_ads1x15/ads1015.py @@ -68,16 +68,6 @@ def _data_rate_default(self) -> Literal[1600]: """Default data rate setting is 1600 samples per second""" return 1600 - def _comp_low_thres_default(self) -> Literal[0x8000]: - """Value is 12-bit, 2's complement stored in 16-bit register where 4 LSBs are 0. - Defaults to 0x8000 as 16-bit hex (-2048 as 12-bit decimal).""" - return 0x8000 - - def _comp_high_thres_default(self) -> Literal[0x7FF0]: - """Value is 12-bit, 2's complement stored in 16-bit register where 4 LSBs are 0. - Defaults to 0x7FF0 as 16-bit hex (2047 as 12-bit decimal).""" - return 0x7FF0 - def _conversion_value(self, raw_adc: int) -> int: value = struct.unpack(">h", raw_adc.to_bytes(2, "big"))[0] return value diff --git a/adafruit_ads1x15/ads1115.py b/adafruit_ads1x15/ads1115.py index a03f8f3..ca834f5 100644 --- a/adafruit_ads1x15/ads1115.py +++ b/adafruit_ads1x15/ads1115.py @@ -69,16 +69,6 @@ def _data_rate_default(self) -> Literal[128]: """Default data rate setting is 128 samples per second""" return 128 - def _comp_low_thres_default(self) -> Literal[0x8000]: - """Value is 16-bit, 2's complement. - Defaults to 0x8000 as 16-bit hex (-32768 16-bit decimal).""" - return 0x8000 - - def _comp_high_thres_default(self) -> Literal[0x7FFF]: - """Value is 16-bit, 2's complement. - Defaults to 0x7FFF as 16-bit hex (32767 16-bit decimal).""" - return 0x7FFF - def _conversion_value(self, raw_adc: int) -> int: value = struct.unpack(">h", raw_adc.to_bytes(2, "big"))[0] return value diff --git a/adafruit_ads1x15/ads1x15.py b/adafruit_ads1x15/ads1x15.py index 97d99cf..1cc8f13 100644 --- a/adafruit_ads1x15/ads1x15.py +++ b/adafruit_ads1x15/ads1x15.py @@ -94,8 +94,8 @@ def __init__( data_rate: Optional[int] = None, mode: int = Mode.SINGLE, comparator_queue_length: int = 0, - comparator_low_threshold: Optional[int] = None, - comparator_high_threshold: Optional[int] = None, + comparator_low_threshold: int = -32768, + comparator_high_threshold: int = 32767, address: int = _ADS1X15_DEFAULT_ADDRESS, ): # pylint: disable=too-many-arguments @@ -106,16 +106,8 @@ def __init__( self.mode = mode self.comparator_queue_length = comparator_queue_length self.i2c_device = I2CDevice(i2c, address) - self.comparator_low_threshold = ( - self._comp_low_thres_default() - if comparator_low_threshold is None - else comparator_low_threshold - ) - self.comparator_high_threshold = ( - self._comp_high_thres_default() - if comparator_high_threshold is None - else comparator_high_threshold - ) + self.comparator_low_threshold = comparator_low_threshold + self.comparator_high_threshold = comparator_high_threshold @property def bits(self) -> int: @@ -198,23 +190,35 @@ def comparator_high_threshold(self) -> int: @comparator_low_threshold.setter def comparator_low_threshold(self, value: int) -> None: - """Set comparator low threshold value for ADS1015 ADC + """Set comparator low threshold value for ADS1x15 ADC :param int value: 16-bit signed integer to write to register """ - if value < 0 or value > 65535: - raise ValueError("Comparator Threshold value must be between 0 and 65535") + if value < -32768 or value > 32767: + raise ValueError( + "Comparator Threshold value must be between -32768 and 32767" + ) + + if (self.bits == 12) & (value & 0x000F > 0): + print("4 LSBs will be truncated for ADS1015 for 12-bit value") + self._comparator_low_threshold = value self._write_register(_ADS1X15_POINTER_LO_THRES, self.comparator_low_threshold) @comparator_high_threshold.setter def comparator_high_threshold(self, value: int) -> None: - """Set comparator high threshold value for ADS1015 ADC + """Set comparator high threshold value for ADS1x15 ADC :param int value: 16-bit signed integer to write to register """ - if value < 0 or value > 65535: - raise ValueError("Comparator Threshold value must be between 0 and 65535") + if value < -32768 or value > 32767: + raise ValueError( + "Comparator Threshold value must be between -32768 and 32767" + ) + + if (self.bits == 12) & (value & 0x000F > 0): + print("4 LSBs will be truncated for ADS1015 for 12-bit value") + self._comparator_high_threshold = value self._write_register(_ADS1X15_POINTER_HI_THRES, self.comparator_high_threshold) @@ -244,18 +248,6 @@ def _data_rate_default(self) -> int: """ raise NotImplementedError("Subclasses must implement _data_rate_default!") - def _comp_low_thres_default(self) -> int: - """Retrieve the default comparator low threshold for this ADC (in 16-bit signed int). - Should be implemented by subclasses. - """ - raise NotImplementedError("Subclasses must implement _comp_low_thres_default!") - - def _comp_high_thres_default(self) -> int: - """Retrieve the default comparator high threshold for this ADC (in 16-bit signed int). - Should be implemented by subclasses. - """ - raise NotImplementedError("Subclasses must implement _comp_high_thres_default!") - def _conversion_value(self, raw_adc: int) -> int: """Subclasses should override this function that takes the 16 raw ADC values of a conversion result and returns a signed integer value. diff --git a/adafruit_ads1x15/analog_in.py b/adafruit_ads1x15/analog_in.py index 6269e44..726314c 100644 --- a/adafruit_ads1x15/analog_in.py +++ b/adafruit_ads1x15/analog_in.py @@ -64,20 +64,10 @@ def voltage(self) -> float: return volts def convert_to_value(self, volts: float) -> int: - """Calculates 12-bit integer for threshold registers from voltage level input""" - - # Convert 2's complement of signed int if number is negative - if volts > 0: - value = round( - (volts / _ADS1X15_PGA_RANGE[self._ads.gain]) - * ((1 << (self._ads.bits - 1)) - 1) - ) - else: - value = round( - (volts / _ADS1X15_PGA_RANGE[self._ads.gain]) - * (1 << (self._ads.bits - 1)) - ) - value += 1 << self._ads.bits + """Calculates a standard 16-bit integer value for a given voltage""" + + lsb = _ADS1X15_PGA_RANGE[self._ads.gain] / (1 << (self._ads.bits - 1)) + value = int(volts / lsb) # Need to bit shift if value is only 12-bits value <<= 16 - self._ads.bits @@ -86,18 +76,10 @@ def convert_to_value(self, volts: float) -> int: def convert_to_voltage(self, value_int: int) -> float: """Calculates voltage from 16-bit ADC reading""" - if value_int & 0x8000: - # Need to convert negative number through 2's complement - value_int -= 0x10000 + lsb = _ADS1X15_PGA_RANGE[self._ads.gain] / (1 << (self._ads.bits - 1)) # Need to bit shift if value is only 12-bits value_int >>= 16 - self._ads.bits - - volts = float(value_int) - volts = ( - volts - * _ADS1X15_PGA_RANGE[self._ads.gain] - / (0x7FFF >> (16 - self._ads.bits)) - ) + volts = value_int * lsb return volts From 3e31097609c5de2b48f9369ec1a0d3981ec0070e Mon Sep 17 00:00:00 2001 From: RoaCode <176423185+RoaCode@users.noreply.github.com> Date: Tue, 6 Aug 2024 08:33:58 -0400 Subject: [PATCH 12/12] Removed bit truncation warning --- adafruit_ads1x15/ads1x15.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/adafruit_ads1x15/ads1x15.py b/adafruit_ads1x15/ads1x15.py index 1cc8f13..fdd53cd 100644 --- a/adafruit_ads1x15/ads1x15.py +++ b/adafruit_ads1x15/ads1x15.py @@ -199,9 +199,6 @@ def comparator_low_threshold(self, value: int) -> None: "Comparator Threshold value must be between -32768 and 32767" ) - if (self.bits == 12) & (value & 0x000F > 0): - print("4 LSBs will be truncated for ADS1015 for 12-bit value") - self._comparator_low_threshold = value self._write_register(_ADS1X15_POINTER_LO_THRES, self.comparator_low_threshold) @@ -216,9 +213,6 @@ def comparator_high_threshold(self, value: int) -> None: "Comparator Threshold value must be between -32768 and 32767" ) - if (self.bits == 12) & (value & 0x000F > 0): - print("4 LSBs will be truncated for ADS1015 for 12-bit value") - self._comparator_high_threshold = value self._write_register(_ADS1X15_POINTER_HI_THRES, self.comparator_high_threshold)