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

MCP32xx (12 bit) ADC support and optional baudrate parameter for SPI comms #47

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
12 changes: 7 additions & 5 deletions adafruit_mcp3xxx/analog_in.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
14 changes: 13 additions & 1 deletion adafruit_mcp3xxx/mcp3002.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
<http://ww1.microchip.com/downloads/en/devicedoc/21294e.pdf#G1.1011678>`_ and `Pin Description
Expand All @@ -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
Expand Down
32 changes: 19 additions & 13 deletions adafruit_mcp3xxx/mcp3004.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
<https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf#page=1>`_ and `Pin Description section
Expand All @@ -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
Expand All @@ -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]
32 changes: 19 additions & 13 deletions adafruit_mcp3xxx/mcp3008.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
<https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf#page=1>`_ and `Pin Description section
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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]
57 changes: 57 additions & 0 deletions adafruit_mcp3xxx/mcp3202.py
Original file line number Diff line number Diff line change
@@ -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
<https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/21034F.pdf>`_
and `Pin Description
<https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/21034F.pdf#G1.1063009>`_
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]
62 changes: 62 additions & 0 deletions adafruit_mcp3xxx/mcp3204.py
Original file line number Diff line number Diff line change
@@ -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
<https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/21298e.pdf>`_
and `Pin Description section
<https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/21298e.pdf#G1.1041174>`_
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]
79 changes: 79 additions & 0 deletions adafruit_mcp3xxx/mcp3208.py
Original file line number Diff line number Diff line change
@@ -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
<https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/21298e.pdf>`_
and `Pin Description section
<https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/21298e.pdf#G1.1041174>`_
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]
Loading