Skip to content

Commit bf390e7

Browse files
authored
Merge pull request #98 from RoaCode/comparator
Added Comparator functionality
2 parents acc1daa + 3e31097 commit bf390e7

File tree

6 files changed

+157
-8
lines changed

6 files changed

+157
-8
lines changed

.pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ repos:
1818
- id: end-of-file-fixer
1919
- id: trailing-whitespace
2020
- repo: https://github.com/pycqa/pylint
21-
rev: v2.17.4
21+
rev: v3.2.6
2222
hooks:
2323
- id: pylint
2424
name: pylint (library code)

adafruit_ads1x15/ads1015.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ def rate_config(self) -> Dict[int, int]:
6565
return _ADS1015_CONFIG_DR
6666

6767
def _data_rate_default(self) -> Literal[1600]:
68+
"""Default data rate setting is 1600 samples per second"""
6869
return 1600
6970

7071
def _conversion_value(self, raw_adc: int) -> int:
7172
value = struct.unpack(">h", raw_adc.to_bytes(2, "big"))[0]
72-
return value >> 4
73+
return value

adafruit_ads1x15/ads1115.py

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def rate_config(self) -> Dict[int, int]:
6666
return _ADS1115_CONFIG_DR
6767

6868
def _data_rate_default(self) -> Literal[128]:
69+
"""Default data rate setting is 128 samples per second"""
6970
return 128
7071

7172
def _conversion_value(self, raw_adc: int) -> int:

adafruit_ads1x15/ads1x15.py

+87-2
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,17 @@
3333
_ADS1X15_DEFAULT_ADDRESS = const(0x48)
3434
_ADS1X15_POINTER_CONVERSION = const(0x00)
3535
_ADS1X15_POINTER_CONFIG = const(0x01)
36+
_ADS1X15_POINTER_LO_THRES = const(0x02)
37+
_ADS1X15_POINTER_HI_THRES = const(0x03)
38+
3639
_ADS1X15_CONFIG_OS_SINGLE = const(0x8000)
3740
_ADS1X15_CONFIG_MUX_OFFSET = const(12)
38-
_ADS1X15_CONFIG_COMP_QUE_DISABLE = const(0x0003)
41+
_ADS1X15_CONFIG_COMP_QUEUE = {
42+
0: 0x0003,
43+
1: 0x0000,
44+
2: 0x0001,
45+
4: 0x0002,
46+
}
3947
_ADS1X15_CONFIG_GAIN = {
4048
2 / 3: 0x0000,
4149
1: 0x0200,
@@ -66,15 +74,28 @@ class ADS1x15:
6674
:param int data_rate: The data rate for ADC conversion in samples per second.
6775
Default value depends on the device.
6876
:param Mode mode: The conversion mode, defaults to `Mode.SINGLE`.
77+
:param int comparator_queue_length: The number of successive conversions exceeding
78+
the comparator threshold before asserting ALERT/RDY pin.
79+
Defaults to 0 (comparator function disabled).
80+
:param int comparator_low_threshold: Voltage limit under which comparator de-asserts
81+
ALERT/RDY pin. Must be lower than high threshold to use comparator
82+
function. See subclass for value range and default.
83+
:param int comparator_high_threshold: Voltage limit over which comparator asserts
84+
ALERT/RDY pin. Must be higher than low threshold to use comparator
85+
function. See subclass for value range and default.
6986
:param int address: The I2C address of the device.
7087
"""
7188

89+
# pylint: disable=too-many-instance-attributes
7290
def __init__(
7391
self,
7492
i2c: I2C,
7593
gain: float = 1,
7694
data_rate: Optional[int] = None,
7795
mode: int = Mode.SINGLE,
96+
comparator_queue_length: int = 0,
97+
comparator_low_threshold: int = -32768,
98+
comparator_high_threshold: int = 32767,
7899
address: int = _ADS1X15_DEFAULT_ADDRESS,
79100
):
80101
# pylint: disable=too-many-arguments
@@ -83,7 +104,10 @@ def __init__(
83104
self.gain = gain
84105
self.data_rate = self._data_rate_default() if data_rate is None else data_rate
85106
self.mode = mode
107+
self.comparator_queue_length = comparator_queue_length
86108
self.i2c_device = I2CDevice(i2c, address)
109+
self.comparator_low_threshold = comparator_low_threshold
110+
self.comparator_high_threshold = comparator_high_threshold
87111

88112
@property
89113
def bits(self) -> int:
@@ -131,6 +155,67 @@ def gains(self) -> List[float]:
131155
g.sort()
132156
return g
133157

158+
@property
159+
def comparator_queue_length(self) -> int:
160+
"""The ADC comparator queue length."""
161+
return self._comparator_queue_length
162+
163+
@comparator_queue_length.setter
164+
def comparator_queue_length(self, comparator_queue_length: int) -> None:
165+
possible_comp_queue_lengths = self.comparator_queue_lengths
166+
if comparator_queue_length not in possible_comp_queue_lengths:
167+
raise ValueError(
168+
"Comparator Queue must be one of: {}".format(
169+
possible_comp_queue_lengths
170+
)
171+
)
172+
self._comparator_queue_length = comparator_queue_length
173+
174+
@property
175+
def comparator_queue_lengths(self) -> List[int]:
176+
"""Possible comparator queue length settings."""
177+
g = list(_ADS1X15_CONFIG_COMP_QUEUE.keys())
178+
g.sort()
179+
return g
180+
181+
@property
182+
def comparator_low_threshold(self) -> int:
183+
"""The ADC Comparator Lower Limit Threshold."""
184+
return self._comparator_low_threshold
185+
186+
@property
187+
def comparator_high_threshold(self) -> int:
188+
"""The ADC Comparator Higher Limit Threshold."""
189+
return self._comparator_high_threshold
190+
191+
@comparator_low_threshold.setter
192+
def comparator_low_threshold(self, value: int) -> None:
193+
"""Set comparator low threshold value for ADS1x15 ADC
194+
195+
:param int value: 16-bit signed integer to write to register
196+
"""
197+
if value < -32768 or value > 32767:
198+
raise ValueError(
199+
"Comparator Threshold value must be between -32768 and 32767"
200+
)
201+
202+
self._comparator_low_threshold = value
203+
self._write_register(_ADS1X15_POINTER_LO_THRES, self.comparator_low_threshold)
204+
205+
@comparator_high_threshold.setter
206+
def comparator_high_threshold(self, value: int) -> None:
207+
"""Set comparator high threshold value for ADS1x15 ADC
208+
209+
:param int value: 16-bit signed integer to write to register
210+
"""
211+
if value < -32768 or value > 32767:
212+
raise ValueError(
213+
"Comparator Threshold value must be between -32768 and 32767"
214+
)
215+
216+
self._comparator_high_threshold = value
217+
self._write_register(_ADS1X15_POINTER_HI_THRES, self.comparator_high_threshold)
218+
134219
@property
135220
def mode(self) -> int:
136221
"""The ADC conversion mode."""
@@ -183,7 +268,7 @@ def _read(self, pin: Pin) -> int:
183268
config |= _ADS1X15_CONFIG_GAIN[self.gain]
184269
config |= self.mode
185270
config |= self.rate_config[self.data_rate]
186-
config |= _ADS1X15_CONFIG_COMP_QUE_DISABLE
271+
config |= _ADS1X15_CONFIG_COMP_QUEUE[self.comparator_queue_length]
187272
self._write_register(_ADS1X15_POINTER_CONFIG, config)
188273

189274
# Wait for conversion to complete

adafruit_ads1x15/analog_in.py

+23-4
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,31 @@ def value(self) -> int:
5555
Even if the underlying analog to digital converter (ADC) is
5656
lower resolution, the value is 16-bit.
5757
"""
58-
return self._ads.read(
59-
self._pin_setting, is_differential=self.is_differential
60-
) << (16 - self._ads.bits)
58+
return self._ads.read(self._pin_setting, is_differential=self.is_differential)
6159

6260
@property
6361
def voltage(self) -> float:
6462
"""Returns the voltage from the ADC pin as a floating point value."""
65-
volts = self.value * _ADS1X15_PGA_RANGE[self._ads.gain] / 32767
63+
volts = self.convert_to_voltage(self.value)
64+
return volts
65+
66+
def convert_to_value(self, volts: float) -> int:
67+
"""Calculates a standard 16-bit integer value for a given voltage"""
68+
69+
lsb = _ADS1X15_PGA_RANGE[self._ads.gain] / (1 << (self._ads.bits - 1))
70+
value = int(volts / lsb)
71+
72+
# Need to bit shift if value is only 12-bits
73+
value <<= 16 - self._ads.bits
74+
return value
75+
76+
def convert_to_voltage(self, value_int: int) -> float:
77+
"""Calculates voltage from 16-bit ADC reading"""
78+
79+
lsb = _ADS1X15_PGA_RANGE[self._ads.gain] / (1 << (self._ads.bits - 1))
80+
81+
# Need to bit shift if value is only 12-bits
82+
value_int >>= 16 - self._ads.bits
83+
volts = value_int * lsb
84+
6685
return volts
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
import time
5+
import board
6+
import busio
7+
import countio
8+
9+
import adafruit_ads1x15.ads1015 as ADS
10+
11+
# import adafruit_ads1x15.ads1115 as ADS
12+
from adafruit_ads1x15.analog_in import AnalogIn
13+
14+
# Create the I2C bus
15+
i2c = busio.I2C(board.SCL, board.SDA)
16+
17+
# Create the ADS object
18+
ads = ADS.ADS1015(i2c)
19+
# ads = ADS.ADS1115(i2c)
20+
21+
# Create a single-ended channel on Pin 0
22+
# Max counts for ADS1015 = 2047
23+
# ADS1115 = 32767
24+
chan = AnalogIn(ads, ADS.P0)
25+
26+
# Create Interrupt-driven input to track comparator changes
27+
int_pin = countio.Counter(board.GP9, edge=countio.Edge.RISE)
28+
29+
# Set comparator to assert after 1 ADC conversion
30+
ads.comparator_queue_length = 1
31+
32+
# Set comparator low threshold to 2V
33+
ads.comparator_low_threshold = chan.convert_to_value(2.000)
34+
# Set comparator high threshold to 2.002V. High threshold must be above low threshold
35+
ads.comparator_high_threshold = chan.convert_to_value(2.002)
36+
37+
count = 0
38+
while True:
39+
print(chan.value, chan.voltage) # This initiates new ADC reading
40+
if int_pin.count > count:
41+
print("Comparator Triggered")
42+
count = int_pin.count
43+
time.sleep(2)

0 commit comments

Comments
 (0)