diff --git a/adafruit_mcp3xxx/analog_in.py b/adafruit_mcp3xxx/analog_in.py index 781b577..dfd001a 100755 --- a/adafruit_mcp3xxx/analog_in.py +++ b/adafruit_mcp3xxx/analog_in.py @@ -8,7 +8,7 @@ AnalogIn for single-ended and differential ADC readings. -* Author(s): Brent Rubell +* Author(s): Brent Rubell, Kevin J. Walters .. warning:: The ADC chips supported by this library do not use negative numbers. If the resulting @@ -51,19 +51,21 @@ def __init__( "Differential pin mapping not defined. Please read the " "documentation for valid differential channel mappings." ) + self._read_shift_left = 16 - self._mcp.BITS + self._read_shift_right = self._mcp.BITS - self._read_shift_left @property def value(self) -> int: """Returns the value of an ADC pin as an integer in the range [0, 65535].""" - # Initial result is only 10 bits. + # Initial result is only 10 or 12 bits. result = int( self._mcp.read(self._pin_setting, is_differential=self.is_differential) ) # Stretch to 16 bits and cover full range. - return (result << 6) | (result >> 4) + return (result << self._read_shift_left) | (result >> self._read_shift_right) @property def voltage(self) -> float: - """Returns the voltage from the ADC pin as a floating point value. Due to the 10-bit - accuracy of the chip, returned values range from 0 to ``reference_voltage``.""" + """Returns the voltage from the ADC pin as a floating point value. + Returned value ranges from 0 to ``reference_voltage``.""" return self.value * self._mcp.reference_voltage / 65535 diff --git a/adafruit_mcp3xxx/mcp3002.py b/adafruit_mcp3xxx/mcp3002.py index eb63bf6..edc83d3 100644 --- a/adafruit_mcp3xxx/mcp3002.py +++ b/adafruit_mcp3xxx/mcp3002.py @@ -9,7 +9,7 @@ MCP3002 2-channel, 10-bit, analog-to-digital converter instance. -* Author(s): Brent Rubell, Brendan Doherty +* Author(s): Brent Rubell, Brendan Doherty, Kevin J. Walters For proper wiring, please refer to `Package Type diagram `_ and `Pin Description @@ -34,9 +34,21 @@ class MCP3002(MCP3xxx): See also the warning in the `AnalogIn`_ class API. """ + BITS = 10 DIFF_PINS = {(0, 1): P0, (1, 0): P1} def read(self, pin: int, is_differential: bool = False) -> int: + """SPI Interface for MCP3xxx-based ADCs reads. Due to 10-bit accuracy, the returned + value ranges [0, 1023]. + + :param int pin: individual or differential pin. + :param bool is_differential: single-ended or differential read. + + .. note:: This library offers a helper class called `AnalogIn`_ for both single-ended + and differential reads. If you opt to not implement `AnalogIn`_ during differential + reads, then the ``pin`` parameter should be the first of the two pins associated with + the desired differential channel mapping. + """ self._out_buf[0] = 0x40 | ((not is_differential) << 5) | (pin << 4) with self._spi_device as spi: # pylint: disable=no-member diff --git a/adafruit_mcp3xxx/mcp3004.py b/adafruit_mcp3xxx/mcp3004.py index 9b04124..bc75672 100755 --- a/adafruit_mcp3xxx/mcp3004.py +++ b/adafruit_mcp3xxx/mcp3004.py @@ -8,7 +8,7 @@ MCP3004 4-channel, 10-bit, analog-to-digital converter instance. -* Author(s): Brent Rubell +* Author(s): Brent Rubell, Kevin J. Walters For proper wiring, please refer to `Package Types diagram `_ and `Pin Description section @@ -18,13 +18,6 @@ from .mcp3xxx import MCP3xxx -try: - import typing # pylint: disable=unused-import - from digitalio import DigitalInOut - from busio import SPI -except ImportError: - pass - # MCP3004 Pin Mapping P0 = 0 P1 = 1 @@ -45,10 +38,23 @@ class MCP3004(MCP3xxx): See also the warning in the `AnalogIn`_ class API. """ + BITS = 10 DIFF_PINS = {(0, 1): P0, (1, 0): P1, (2, 3): P2, (3, 2): P3} - def __init__( - self, spi_bus: SPI, cs: DigitalInOut, ref_voltage: float = 3.3 - ) -> None: - super().__init__(spi_bus, cs, ref_voltage=ref_voltage) - self._out_buf[0] = 0x01 + def read(self, pin: int, is_differential: bool = False) -> int: + """SPI Interface for MCP3xxx-based ADCs reads. Due to 10-bit accuracy, the returned + value ranges [0, 1023]. + + :param int pin: individual or differential pin. + :param bool is_differential: single-ended or differential read. + + .. note:: This library offers a helper class called `AnalogIn`_ for both single-ended + and differential reads. If you opt to not implement `AnalogIn`_ during differential + reads, then the ``pin`` parameter should be the first of the two pins associated with + the desired differential channel mapping. + """ + self._out_buf[1] = ((not is_differential) << 7) | (pin << 4) + with self._spi_device as spi: + # pylint: disable=no-member + spi.write_readinto(self._out_buf, self._in_buf) + return ((self._in_buf[1] & 0x03) << 8) | self._in_buf[2] diff --git a/adafruit_mcp3xxx/mcp3008.py b/adafruit_mcp3xxx/mcp3008.py index 61ca801..a43e89f 100755 --- a/adafruit_mcp3xxx/mcp3008.py +++ b/adafruit_mcp3xxx/mcp3008.py @@ -8,7 +8,7 @@ MCP3008 8-channel, 10-bit, analog-to-digital converter instance. -* Author(s): Brent Rubell +* Author(s): Brent Rubell, Kevin J. Walters For proper wiring, please refer to the `Package Types diagram `_ and `Pin Description section @@ -18,13 +18,6 @@ from .mcp3xxx import MCP3xxx -try: - import typing # pylint: disable=unused-import - from digitalio import DigitalInOut - from busio import SPI -except ImportError: - pass - # MCP3008 Pin Mapping P0 = 0 P1 = 1 @@ -53,6 +46,7 @@ class MCP3008(MCP3xxx): See also the warning in the `AnalogIn`_ class API. """ + BITS = 10 DIFF_PINS = { (0, 1): P0, (1, 0): P1, @@ -64,8 +58,20 @@ class MCP3008(MCP3xxx): (7, 6): P7, } - def __init__( - self, spi_bus: SPI, cs: DigitalInOut, ref_voltage: float = 3.3 - ) -> None: - super().__init__(spi_bus, cs, ref_voltage=ref_voltage) - self._out_buf[0] = 0x01 + def read(self, pin: int, is_differential: bool = False) -> int: + """SPI Interface for MCP3xxx-based ADCs reads. Due to 10-bit accuracy, the returned + value ranges [0, 1023]. + + :param int pin: individual or differential pin. + :param bool is_differential: single-ended or differential read. + + .. note:: This library offers a helper class called `AnalogIn`_ for both single-ended + and differential reads. If you opt to not implement `AnalogIn`_ during differential + reads, then the ``pin`` parameter should be the first of the two pins associated with + the desired differential channel mapping. + """ + self._out_buf[1] = ((not is_differential) << 7) | (pin << 4) + with self._spi_device as spi: + # pylint: disable=no-member + spi.write_readinto(self._out_buf, self._in_buf) + return ((self._in_buf[1] & 0x03) << 8) | self._in_buf[2] diff --git a/adafruit_mcp3xxx/mcp3202.py b/adafruit_mcp3xxx/mcp3202.py new file mode 100644 index 0000000..b2211fe --- /dev/null +++ b/adafruit_mcp3xxx/mcp3202.py @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: 2018 Brent Rubell for Adafruit Industries +# SPDX-FileCopyrightText: 2019 Brendan Doherty Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +:py:class:`~adafruit_mcp3xxx.MCP3202.MCP3202` +================================================ +MCP3202 2-channel, 12-bit, analog-to-digital +converter instance. + +* Author(s): Brent Rubell, Brendan Doherty, Kevin J. Walters + +For proper wiring, please refer to `Package Type diagram +`_ +and `Pin Description +`_ +section of the MCP3202 datasheet. +""" +from .mcp3xxx import MCP3xxx + +# MCP3202 Pin Mapping +P0 = 0 +P1 = 1 + + +class MCP3202(MCP3xxx): + """ + MCP3202 Differential channel mapping. The following list of available differential readings + takes the form ``(positive_pin, negative_pin) = (channel A) - (channel B)``. + + - (P0, P1) = CH0 - CH1 + - (P1, P0) = CH1 - CH0 + + See also the warning in the `AnalogIn`_ class API. + """ + + BITS = 12 + DIFF_PINS = {(0, 1): P0, (1, 0): P1} + + def read(self, pin: int, is_differential: bool = False) -> int: + """SPI Interface for MCP3xxx-based ADCs reads. Due to 12-bit accuracy, the returned + value ranges [0, 4095]. + + :param int pin: individual or differential pin. + :param bool is_differential: single-ended or differential read. + + .. note:: This library offers a helper class called `AnalogIn`_ for both single-ended + and differential reads. If you opt to not implement `AnalogIn`_ during differential + reads, then the ``pin`` parameter should be the first of the two pins associated with + the desired differential channel mapping. + """ + self._out_buf[0] = 0x40 | ((not is_differential) << 5) | (pin << 4) + with self._spi_device as spi: + # pylint: disable=no-member + spi.write_readinto(self._out_buf, self._in_buf, out_end=2, in_end=2) + return ((self._in_buf[0] & 0x0F) << 8) | self._in_buf[1] diff --git a/adafruit_mcp3xxx/mcp3204.py b/adafruit_mcp3xxx/mcp3204.py new file mode 100755 index 0000000..ac129c4 --- /dev/null +++ b/adafruit_mcp3xxx/mcp3204.py @@ -0,0 +1,62 @@ +# SPDX-FileCopyrightText: 2018 Brent Rubell for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +:py:class:`~adafruit_mcp3xxx.mcp3204.MCP3204` +================================================ +MCP3204 4-channel, 12-bit, analog-to-digital +converter instance. + +* Author(s): Brent Rubell, Kevin J. Walters + +For proper wiring, please refer to `Package Types diagram +`_ +and `Pin Description section +`_ +of the MCP3204/MCP3208 datasheet. +""" + +from .mcp3xxx import MCP3xxx + +# MCP3204 Pin Mapping +P0 = 0 +P1 = 1 +P2 = 2 +P3 = 3 + + +class MCP3204(MCP3xxx): + """ + MCP3204 Differential channel mapping. The following list of available differential readings + takes the form ``(positive_pin, negative_pin) = (channel A) - (channel B)``. + + - (P0, P1) = CH0 - CH1 + - (P1, P0) = CH1 - CH0 + - (P2, P3) = CH2 - CH3 + - (P3, P2) = CH3 - CH2 + + See also the warning in the `AnalogIn`_ class API. + """ + + BITS = 12 + DIFF_PINS = {(0, 1): P0, (1, 0): P1, (2, 3): P2, (3, 2): P3} + + def read(self, pin: int, is_differential: bool = False) -> int: + """SPI Interface for MCP3xxx-based ADCs reads. Due to 10-bit accuracy, the returned + value ranges [0, 1023]. + + :param int pin: individual or differential pin. + :param bool is_differential: single-ended or differential read. + + .. note:: This library offers a helper class called `AnalogIn`_ for both single-ended + and differential reads. If you opt to not implement `AnalogIn`_ during differential + reads, then the ``pin`` parameter should be the first of the two pins associated with + the desired differential channel mapping. + """ + self._out_buf[0] = 0x04 | ((not is_differential) << 1) | (pin >> 2) + self._out_buf[1] = (pin & 0x03) << 6 + with self._spi_device as spi: + # pylint: disable=no-member + spi.write_readinto(self._out_buf, self._in_buf) + return ((self._in_buf[1] & 0x0F) << 8) | self._in_buf[2] diff --git a/adafruit_mcp3xxx/mcp3208.py b/adafruit_mcp3xxx/mcp3208.py new file mode 100755 index 0000000..7fc90ea --- /dev/null +++ b/adafruit_mcp3xxx/mcp3208.py @@ -0,0 +1,79 @@ +# SPDX-FileCopyrightText: 2018 Brent Rubell for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +:py:class:`~adafruit_mcp3xxx.mcp3208.MCP3208` +============================================================= +MCP3208 8-channel, 12-bit, analog-to-digital +converter instance. + +* Author(s): Brent Rubell, Kevin J. Walters + +For proper wiring, please refer to `Package Types diagram +`_ +and `Pin Description section +`_ +of the MCP3204/MCP3208 datasheet. +""" + +from .mcp3xxx import MCP3xxx + +# MCP3208 Pin Mapping +P0 = 0 +P1 = 1 +P2 = 2 +P3 = 3 +P4 = 4 +P5 = 5 +P6 = 6 +P7 = 7 + + +class MCP3208(MCP3xxx): + """ + MCP3208 Differential channel mapping. The following list of available differential readings + takes the form ``(positive_pin, negative_pin) = (channel A) - (channel B)``. + + - (P0, P1) = CH0 - CH1 + - (P1, P0) = CH1 - CH0 + - (P2, P3) = CH2 - CH3 + - (P3, P2) = CH3 - CH2 + - (P4, P5) = CH4 - CH5 + - (P5, P4) = CH5 - CH4 + - (P6, P7) = CH6 - CH7 + - (P7, P6) = CH7 - CH6 + + See also the warning in the `AnalogIn`_ class API. + """ + + BITS = 12 + DIFF_PINS = { + (0, 1): P0, + (1, 0): P1, + (2, 3): P2, + (3, 2): P3, + (4, 5): P4, + (5, 4): P5, + (6, 7): P6, + (7, 6): P7, + } + + def read(self, pin: int, is_differential: bool = False) -> int: + """SPI Interface for MCP3xxx-based ADCs reads. Due to 10-bit accuracy, the returned + value ranges [0, 1023]. + + :param int pin: individual or differential pin. + :param bool is_differential: single-ended or differential read. + + .. note:: This library offers a helper class called `AnalogIn`_ for both single-ended + and differential reads. If you opt to not implement `AnalogIn`_ during differential + reads, then the ``pin`` parameter should be the first of the two pins associated with + the desired differential channel mapping. + """ + self._out_buf[0] = 0x04 | ((not is_differential) << 1) | (pin >> 2) + self._out_buf[1] = (pin & 0x03) << 6 + with self._spi_device as spi: + # pylint: disable=no-member + spi.write_readinto(self._out_buf, self._in_buf) + return ((self._in_buf[1] & 0x0F) << 8) | self._in_buf[2] diff --git a/adafruit_mcp3xxx/mcp3xxx.py b/adafruit_mcp3xxx/mcp3xxx.py old mode 100755 new mode 100644 index c378cde..937e7c3 --- a/adafruit_mcp3xxx/mcp3xxx.py +++ b/adafruit_mcp3xxx/mcp3xxx.py @@ -8,7 +8,7 @@ CircuitPython Library for MCP3xxx ADCs with SPI -* Author(s): ladyada, Brent Rubell +* Author(s): ladyada, Brent Rubell, Kevin J. Walters Implementation Notes -------------------- @@ -58,35 +58,24 @@ class MCP3xxx: :param ~adafruit_bus_device.spi_device.SPIDevice spi_bus: SPI bus the ADC is connected to. :param ~digitalio.DigitalInOut cs: Chip Select Pin. :param float ref_voltage: Voltage into (Vin) the ADC. + :param int baudrate: the clock speed for communication to this SPI device. Defaults to 100k. """ def __init__( - self, spi_bus: SPI, cs: DigitalInOut, ref_voltage: float = 3.3 + self, + spi_bus: SPI, + cs: DigitalInOut, + ref_voltage: float = 3.3, + baudrate: int = 100_000, ): # pylint: disable=invalid-name - self._spi_device = SPIDevice(spi_bus, cs) + self._spi_device = SPIDevice(spi_bus, cs, baudrate=baudrate) self._out_buf = bytearray(3) self._in_buf = bytearray(3) self._ref_voltage = ref_voltage + self._out_buf[0] = 0x01 # some sub-classes will overwrite this + @property def reference_voltage(self) -> float: """Returns the MCP3xxx's reference voltage. (read-only)""" return self._ref_voltage - - def read(self, pin: int, is_differential: bool = False) -> int: - """SPI Interface for MCP3xxx-based ADCs reads. Due to 10-bit accuracy, the returned - value ranges [0, 1023]. - - :param int pin: individual or differential pin. - :param bool is_differential: single-ended or differential read. - - .. note:: This library offers a helper class called `AnalogIn`_ for both single-ended - and differential reads. If you opt to not implement `AnalogIn`_ during differential - reads, then the ``pin`` parameter should be the first of the two pins associated with - the desired differential channel mapping. - """ - self._out_buf[1] = ((not is_differential) << 7) | (pin << 4) - with self._spi_device as spi: - # pylint: disable=no-member - spi.write_readinto(self._out_buf, self._in_buf) - return ((self._in_buf[1] & 0x03) << 8) | self._in_buf[2]