Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added functions for controlling additional comparator settings #99

Merged
merged 3 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion adafruit_ads1x15/ads1015.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
pass

# pylint: disable=unused-import
from .ads1x15 import ADS1x15, Mode
from .ads1x15 import ADS1x15

# Data sample rates
_ADS1015_CONFIG_DR = {
Expand Down
2 changes: 1 addition & 1 deletion adafruit_ads1x15/ads1115.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
pass

# pylint: disable=unused-import
from .ads1x15 import ADS1x15, Mode
from .ads1x15 import ADS1x15

# Data sample rates
_ADS1115_CONFIG_DR = {
Expand Down
119 changes: 105 additions & 14 deletions adafruit_ads1x15/ads1x15.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,42 @@ class Mode:
"""Single-Shot Mode"""


class Comp_Mode:
"""An enum-like class representing possible ADC Comparator operating modes."""

# See datasheet "Operating Modes" section
# values here are masks for setting COMP_MODE bit in Config Register
# pylint: disable=too-few-public-methods
TRADITIONAL = 0x0000
"""Traditional Compartor Mode activates above high threshold, de-activates below low"""
WINDOW = 0x0010
"""Window Comparator Mode activates when reading is outside of high and low thresholds"""


class Comp_Polarity:
"""An enum-like class representing possible ADC Comparator polarity modes."""

# See datasheet "Operating Modes" section
# values here are masks for setting COMP_POL bit in Config Register
# pylint: disable=too-few-public-methods
ACTIVE_LOW = 0x0000
"""ALERT_RDY pin is LOW when comparator is active"""
ACTIVE_HIGH = 0x0008
"""ALERT_RDY pin is HIGH when comparator is active"""


class Comp_Latch:
"""An enum-like class representing possible ADC Comparator latching modes."""

# See datasheet "Operating Modes" section
# values here are masks for setting COMP_LAT bit in Config Register
# pylint: disable=too-few-public-methods
NONLATCHING = 0x0000
"""ALERT_RDY pin does not latch when asserted"""
LATCHING = 0x0004
"""ALERT_RDY pin remains asserted until data is read by controller"""


class ADS1x15:
"""Base functionality for ADS1x15 analog to digital converters.

Expand All @@ -79,10 +115,17 @@ 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. See subclass for value range and default.
function. Range of -32768 to 32767, default -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. See subclass for value range and default.
function. Range of -32768 to 32767, default 32767
:param Comp_Mode comparator_mode: Configures the comparator as either traditional or window.
Defaults to 'Comp_Mode.TRADITIONAL'
:param Comp_Polarity comparator_polarity: Configures the comparator output as either active
low or active high. Defaults to 'Comp_Polarity.ACTIVE_LOW'
:param Comp_Latch comparator_latch: Configures the comparator output to only stay asserted while
readings exceed threshold or latch on assertion until data is read.
Defaults to 'Comp_Latch.NONLATCHING'
:param int address: The I2C address of the device.
"""

Expand All @@ -96,6 +139,9 @@ def __init__(
comparator_queue_length: int = 0,
comparator_low_threshold: int = -32768,
comparator_high_threshold: int = 32767,
comparator_mode: int = Comp_Mode.TRADITIONAL,
comparator_polarity: int = Comp_Polarity.ACTIVE_LOW,
comparator_latch: int = Comp_Latch.NONLATCHING,
address: int = _ADS1X15_DEFAULT_ADDRESS,
):
# pylint: disable=too-many-arguments
Expand All @@ -108,6 +154,9 @@ def __init__(
self.i2c_device = I2CDevice(i2c, address)
self.comparator_low_threshold = comparator_low_threshold
self.comparator_high_threshold = comparator_high_threshold
self.comparator_mode = comparator_mode
self.comparator_polarity = comparator_polarity
self.comparator_latch = comparator_latch

@property
def bits(self) -> int:
Expand Down Expand Up @@ -227,13 +276,45 @@ def mode(self, mode: int) -> None:
raise ValueError("Unsupported mode.")
self._mode = mode

def read(self, pin: Pin, is_differential: bool = False) -> int:
@property
def comparator_mode(self) -> int:
"""The ADC comparator mode."""
return self._comparator_mode

@comparator_mode.setter
def comparator_mode(self, comp_mode: int) -> None:
if comp_mode not in (Comp_Mode.TRADITIONAL, Comp_Mode.WINDOW):
raise ValueError("Unsupported mode.")
self._comparator_mode = comp_mode

@property
def comparator_polarity(self) -> int:
"""The ADC comparator polarity mode."""
return self._comparator_polarity

@comparator_polarity.setter
def comparator_polarity(self, comp_pol: int) -> None:
if comp_pol not in (Comp_Polarity.ACTIVE_LOW, Comp_Polarity.ACTIVE_HIGH):
raise ValueError("Unsupported mode.")
self._comparator_polarity = comp_pol

@property
def comparator_latch(self) -> int:
"""The ADC comparator latching mode."""
return self._comparator_latch

@comparator_latch.setter
def comparator_latch(self, comp_latch: int) -> None:
if comp_latch not in (Comp_Latch.NONLATCHING, Comp_Latch.LATCHING):
raise ValueError("Unsupported mode.")
self._comparator_latch = comp_latch

def read(self, pin: Pin) -> int:
"""I2C Interface for ADS1x15-based ADCs reads.

:param ~microcontroller.Pin pin: individual or differential pin.
:param bool is_differential: single-ended or differential read.
"""
pin = pin if is_differential else pin + 0x04
return self._read(pin)

def _data_rate_default(self) -> int:
Expand All @@ -260,16 +341,7 @@ def _read(self, pin: Pin) -> int:

# Configure ADC every time before a conversion in SINGLE mode
# or changing channels in CONTINUOUS mode
if self.mode == Mode.SINGLE:
config = _ADS1X15_CONFIG_OS_SINGLE
else:
config = 0
config |= (pin & 0x07) << _ADS1X15_CONFIG_MUX_OFFSET
config |= _ADS1X15_CONFIG_GAIN[self.gain]
config |= self.mode
config |= self.rate_config[self.data_rate]
config |= _ADS1X15_CONFIG_COMP_QUEUE[self.comparator_queue_length]
self._write_register(_ADS1X15_POINTER_CONFIG, config)
self.write_config(pin)

# Wait for conversion to complete
# ADS1x1x devices settle within a single conversion cycle
Expand Down Expand Up @@ -317,3 +389,22 @@ def _read_register(self, reg: int, fast: bool = False) -> int:
else:
i2c.write_then_readinto(bytearray([reg]), self.buf, in_end=2)
return self.buf[0] << 8 | self.buf[1]

def write_config(self, pin_config: int) -> None:
tannewt marked this conversation as resolved.
Show resolved Hide resolved
"""Write to configuration register of ADC

:param int pin_config: setting for MUX value in config register
"""
if self.mode == Mode.SINGLE:
config = _ADS1X15_CONFIG_OS_SINGLE
else:
config = 0
config |= (pin_config & 0x07) << _ADS1X15_CONFIG_MUX_OFFSET
config |= _ADS1X15_CONFIG_GAIN[self.gain]
config |= self.mode
config |= self.rate_config[self.data_rate]
config |= self.comparator_mode
config |= self.comparator_polarity
config |= self.comparator_latch
config |= _ADS1X15_CONFIG_COMP_QUEUE[self.comparator_queue_length]
self._write_register(_ADS1X15_POINTER_CONFIG, config)
8 changes: 7 additions & 1 deletion adafruit_ads1x15/analog_in.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ 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)
pin = self._pin_setting if self.is_differential else self._pin_setting + 0x04
return self._ads.read(pin)

def write_config(self) -> None:
"""Calculates MUX setting and writes to configuration register"""
pin = self._pin_setting if self.is_differential else self._pin_setting + 0x04
self._ads.write_config(pin)

@property
def voltage(self) -> float:
Expand Down
14 changes: 13 additions & 1 deletion examples/ads1x15_comparator_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import adafruit_ads1x15.ads1015 as ADS

# import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.ads1x15 import Mode, Comp_Mode, Comp_Polarity, Comp_Latch
from adafruit_ads1x15.analog_in import AnalogIn

# Create the I2C bus
Expand All @@ -26,14 +27,25 @@
# Create Interrupt-driven input to track comparator changes
int_pin = countio.Counter(board.GP9, edge=countio.Edge.RISE)

# Set ADC to continuously read new data
ads.mode = Mode.CONTINUOUS
# Set comparator to assert after 1 ADC conversion
ads.comparator_queue_length = 1

# Set comparator to use traditional threshold instead of window
ads.comparator_mode = Comp_Mode.TRADITIONAL
# Set comparator output to de-assert if readings no longer above threshold
ads.comparator_latch = Comp_Latch.NONLATCHING
# Set comparator output to logic LOW when asserted
ads.comparator_polarity = Comp_Polarity.ACTIVE_LOW
# Gain should be explicitly set to ensure threshold values are calculated correctly
ads.gain = 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)

chan.write_config()

count = 0
while True:
print(chan.value, chan.voltage) # This initiates new ADC reading
Expand Down