Skip to content

Commit

Permalink
Merge pull request #98 from RoaCode/comparator
Browse files Browse the repository at this point in the history
Added Comparator functionality
  • Loading branch information
tannewt authored Aug 6, 2024
2 parents acc1daa + 3e31097 commit bf390e7
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion adafruit_ads1x15/ads1015.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ 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 _conversion_value(self, raw_adc: int) -> int:
value = struct.unpack(">h", raw_adc.to_bytes(2, "big"))[0]
return value >> 4
return value
1 change: 1 addition & 0 deletions adafruit_ads1x15/ads1115.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ 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 _conversion_value(self, raw_adc: int) -> int:
Expand Down
89 changes: 87 additions & 2 deletions adafruit_ads1x15/ads1x15.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -66,15 +74,28 @@ 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_threshold: Voltage limit under which comparator de-asserts
ALERT/RDY pin. Must be lower than high threshold to use comparator
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. See subclass for value range and default.
:param int address: The I2C address of the device.
"""

# pylint: disable=too-many-instance-attributes
def __init__(
self,
i2c: I2C,
gain: float = 1,
data_rate: Optional[int] = None,
mode: int = Mode.SINGLE,
comparator_queue_length: int = 0,
comparator_low_threshold: int = -32768,
comparator_high_threshold: int = 32767,
address: int = _ADS1X15_DEFAULT_ADDRESS,
):
# pylint: disable=too-many-arguments
Expand All @@ -83,7 +104,10 @@ def __init__(
self.gain = gain
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.i2c_device = I2CDevice(i2c, address)
self.comparator_low_threshold = comparator_low_threshold
self.comparator_high_threshold = comparator_high_threshold

@property
def bits(self) -> int:
Expand Down Expand Up @@ -131,6 +155,67 @@ def gains(self) -> List[float]:
g.sort()
return g

@property
def comparator_queue_length(self) -> int:
"""The ADC comparator queue length."""
return self._comparator_queue_length

@comparator_queue_length.setter
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
)
)
self._comparator_queue_length = comparator_queue_length

@property
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_threshold(self) -> int:
"""The ADC Comparator Lower Limit Threshold."""
return self._comparator_low_threshold

@property
def comparator_high_threshold(self) -> int:
"""The ADC Comparator Higher Limit Threshold."""
return self._comparator_high_threshold

@comparator_low_threshold.setter
def comparator_low_threshold(self, value: int) -> None:
"""Set comparator low threshold value for ADS1x15 ADC
:param int value: 16-bit signed integer to write to register
"""
if value < -32768 or value > 32767:
raise ValueError(
"Comparator Threshold value must be between -32768 and 32767"
)

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 ADS1x15 ADC
:param int value: 16-bit signed integer to write to register
"""
if value < -32768 or value > 32767:
raise ValueError(
"Comparator Threshold value must be between -32768 and 32767"
)

self._comparator_high_threshold = value
self._write_register(_ADS1X15_POINTER_HI_THRES, self.comparator_high_threshold)

@property
def mode(self) -> int:
"""The ADC conversion mode."""
Expand Down Expand Up @@ -183,7 +268,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.comparator_queue_length]
self._write_register(_ADS1X15_POINTER_CONFIG, config)

# Wait for conversion to complete
Expand Down
27 changes: 23 additions & 4 deletions adafruit_ads1x15/analog_in.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,31 @@ 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:
"""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 convert_to_value(self, volts: float) -> int:
"""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
return value

def convert_to_voltage(self, value_int: int) -> float:
"""Calculates voltage from 16-bit ADC reading"""

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 = value_int * lsb

return volts
43 changes: 43 additions & 0 deletions examples/ads1x15_comparator_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# 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)

# Set comparator to assert after 1 ADC conversion
ads.comparator_queue_length = 1

# Set comparator low threshold to 2V
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_threshold = chan.convert_to_value(2.002)

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)

0 comments on commit bf390e7

Please sign in to comment.