Skip to content

Commit

Permalink
Merge pull request #20 from 2bndy5/mcp3002-support
Browse files Browse the repository at this point in the history
MCP3002 support
  • Loading branch information
brentru committed Oct 29, 2019
2 parents 6c16e1c + 9979fa8 commit dba64ec
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 76 deletions.
41 changes: 23 additions & 18 deletions adafruit_mcp3xxx/analog_in.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,45 @@
differential ADC readings.
* Author(s): Brent Rubell
.. warning::
The ADC chips supported by this library do not use negative numbers. If the resulting
differential read is less than 0, then the returned integer value (and voltage value) is ``0``.
If for some reason the voltage on a channel is greater than the reference voltage or
less than 0, then the returned integer value is ``65472‬`` or ``0`` respectively.
"""

from .mcp3xxx import MCP3xxx

class AnalogIn():
"""AnalogIn Mock Implementation for ADC Reads.
:param ~mcp3004.MCP3004,~mcp3008.MCP3008 mcp: The mcp object.
:param MCP3002,MCP3004,MCP3008 mcp: The mcp object.
:param int positive_pin: Required pin for single-ended.
:param int negative_pin: Optional pin for differential reads.
"""
def __init__(self, mcp, positive_pin, negative_pin=None):
if not isinstance(mcp, MCP3xxx):
raise ValueError("mcp object is not a sibling of MCP3xxx class.")
self._mcp = mcp
self._pin_setting = positive_pin
self._negative_pin = negative_pin
self.is_differential = False
if negative_pin is not None:
self.is_differential = True
self._channels = []
try:
self._pins = self._mcp.MCP3008_DIFF_PINS
except AttributeError:
self._pins = self._mcp.MCP3004_DIFF_PINS
self._pin_setting = self._pins.get((self._pin_setting, self._negative_pin),
"Difference pin not found.")

def __getitem__(self, key):
return self._channels[self._pins[key]]
self.is_differential = negative_pin is not None
if self.is_differential:
self._pin_setting = self._mcp.DIFF_PINS.get((positive_pin, negative_pin), None)
if self._pin_setting is None:
raise ValueError("Differential pin mapping not defined. Please read the "
"documentation for valid differential channel mappings.")

@property
def value(self):
"""Returns the value of an ADC pin as an integer."""
"""Returns the value of an ADC pin as an integer. Due to 10-bit accuracy of the chip, the
returned values range [0, 65472]."""
return self._mcp.read(self._pin_setting, is_differential=self.is_differential) << 6

@property
def voltage(self):
"""Returns the voltage from the ADC pin as a floating point value."""
"""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`` *
65472 / 65535)"""
return (self.value * self._mcp.reference_voltage) / 65535
62 changes: 62 additions & 0 deletions adafruit_mcp3xxx/mcp3002.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Brent Rubell for Adafruit
# Copyright (c) 2019 Brendan Doherty
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
:py:class:`~adafruit_mcp3xxx.MCP3002.MCP3002`
================================================
MCP3002 2-channel, 10-bit, analog-to-digital
converter instance.
* Author(s): Brent Rubell, Brendan Doherty
For proper wiring, please refer to `Package Type diagram
<http://ww1.microchip.com/downloads/en/devicedoc/21294e.pdf#G1.1011678>`_ and `Pin Description
<http://ww1.microchip.com/downloads/en/devicedoc/21294e.pdf#G1.1034774>`_ section of the MCP3002
datasheet.
"""
from .mcp3xxx import MCP3xxx

# MCP3002 Pin Mapping
P0 = 0
P1 = 1

class MCP3002(MCP3xxx):
"""
MCP3002 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.
"""
DIFF_PINS = {
(0, 1) : P0,
(1, 0) : P1
}

def read(self, pin, is_differential=False):
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] & 0x03) << 8) | self._in_buf[1]
26 changes: 19 additions & 7 deletions adafruit_mcp3xxx/mcp3004.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
converter instance.
* Author(s): Brent Rubell
For proper wiring, please refer to `Package Types diagram
<https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf#page=1>`_ and `Pin Description section
<https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf#G1.1035093>`_ of the MCP3004/MCP3008
datasheet.
"""

from .mcp3xxx import MCP3xxx
Expand All @@ -37,17 +42,24 @@
P3 = 3

class MCP3004(MCP3xxx):

"""
MCP3004 Differential channel mapping.
- 0: CH0 = IN+, CH1 = IN-
- 1: CH1 = IN+, CH0 = IN-
- 2: CH2 = IN+, CH3 = IN-
- 3: CH3 = IN+, CH2 = IN-
MCP3004 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.
"""
MCP3004_DIFF_PINS = {
DIFF_PINS = {
(0, 1) : P0,
(1, 0) : P1,
(2, 3) : P2,
(3, 2) : P3
}

def __init__(self, spi_bus, cs, ref_voltage=3.3):
super(MCP3004, self).__init__(spi_bus, cs, ref_voltage=ref_voltage)
self._out_buf[0] = 0x01
34 changes: 23 additions & 11 deletions adafruit_mcp3xxx/mcp3008.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
converter instance.
* Author(s): Brent Rubell
For proper wiring, please refer to the `Package Types diagram
<https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf#page=1>`_ and `Pin Description section
<https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf#G1.1035093>`_ of the MCP3004/MCP3008
datasheet.
"""

from .mcp3xxx import MCP3xxx
Expand All @@ -41,19 +46,22 @@
P7 = 7

class MCP3008(MCP3xxx):

"""
MCP3008 Differential channel mapping.
- 0: CH0 = IN+, CH1 = IN-
- 1: CH1 = IN+, CH0 = IN-
- 2: CH2 = IN+, CH3 = IN-
- 3: CH3 = IN+, CH2 = IN-
- 4: CH4 = IN+, CH5 = IN-
- 5: CH5 = IN+, CH4 = IN-
- 6: CH6 = IN+, CH7 = IN-
- 7: CH7 = IN+, CH6 = IN-
MCP3008 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.
"""
MCP3008_DIFF_PINS = {
DIFF_PINS = {
(0, 1) : P0,
(1, 0) : P1,
(2, 3) : P2,
Expand All @@ -63,3 +71,7 @@ class MCP3008(MCP3xxx):
(6, 7) : P6,
(7, 6) : P7
}

def __init__(self, spi_bus, cs, ref_voltage=3.3):
super(MCP3008, self).__init__(spi_bus, cs, ref_voltage=ref_voltage)
self._out_buf[0] = 0x01
47 changes: 24 additions & 23 deletions adafruit_mcp3xxx/mcp3xxx.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,33 @@
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
.. note:: The ADC chips' input pins (AKA "channels") are aliased in this library
as integer variables whose names start with "P" (eg ``MCP3008.P0`` is channel 0 on the MCP3008
chip). Each module that contains a driver class for a particular ADC chip has these aliases
predefined accordingly. This is done for code readability and prevention of erroneous SPI
commands.
.. important::
The differential reads (comparisons done by the ADC chip) are limited to certain pairs of
channels. These predefined pairs are referenced in this documentation as differential
channel mappings. Please refer to the driver class of your ADC chip (`MCP3008`_,
`MCP3004`_, `MCP3002`_) for a list of available differential channel mappings.
"""

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MCP3xxx.git"


from micropython import const
from adafruit_bus_device.spi_device import SPIDevice

# MCP3004/008 data transfer commands
_MCP30084_OUT_BUFF = const(0x00)
_MCP30084_DIFF_READ = const(0x02)
_MCP30084_SINGLE_READ = const(0x3)


class MCP3xxx:
"""
MCP3xxx Interface.
This abstract base class is meant to be inherited by `MCP3008`_, `MCP3004`_,
or `MCP3002`_ child classes.
: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.
"""
def __init__(self, spi_bus, cs, ref_voltage=3.3):
self._spi_device = SPIDevice(spi_bus, cs)
Expand All @@ -72,26 +76,23 @@ def __init__(self, spi_bus, cs, ref_voltage=3.3):

@property
def reference_voltage(self):
"""Returns the MCP3xxx's reference voltage."""
"""Returns the MCP3xxx's reference voltage. (read-only)"""
return self._ref_voltage

def read(self, pin, is_differential=False):
"""SPI Interface for MCP3xxx-based ADCs reads.
"""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.
"""
command = (_MCP30084_DIFF_READ if is_differential else _MCP30084_SINGLE_READ) << 6
command |= pin << 3
self._out_buf[0] = command
self._out_buf[1] = _MCP30084_OUT_BUFF
self._out_buf[2] = _MCP30084_OUT_BUFF
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, out_start=0,
out_end=len(self._out_buf), in_start=0, in_end=len(self._in_buf))
result = (self._in_buf[0] & 0x01) << 9
result |= self._in_buf[1] << 1
result |= self._in_buf[2] >> 7
return result
spi.write_readinto(self._out_buf, self._in_buf)
return ((self._in_buf[1] & 0x03) << 8) | self._in_buf[2]
37 changes: 21 additions & 16 deletions docs/api.rst
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
API
------------

.. automodule:: adafruit_mcp3xxx.mcp3xxx
:members:

.. automodule:: adafruit_mcp3xxx.mcp3004
:members:
:show-inheritance:

.. automodule:: adafruit_mcp3xxx.mcp3008
:members:
:show-inheritance:

.. automodule:: adafruit_mcp3xxx.analog_in
:members:
API
------------

.. automodule:: adafruit_mcp3xxx.mcp3xxx
:members:

.. automodule:: adafruit_mcp3xxx.analog_in
:members:

.. automodule:: adafruit_mcp3xxx.mcp3008
:members:
:show-inheritance:

.. automodule:: adafruit_mcp3xxx.mcp3004
:members:
:show-inheritance:

.. automodule:: adafruit_mcp3xxx.mcp3002
:members:
:exclude-members: read
:show-inheritance:
10 changes: 9 additions & 1 deletion docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,18 @@ Ensure your device works with this simple test.
:caption: examples/mcp3xxx_mcp3004_single_ended_simpletest.py
:linenos:

.. literalinclude:: ../examples/mcp3xxx_mcp3002_single_ended_simpletest.py
:caption: examples/mcp3xxx_mcp3002_single_ended_simpletest.py
:linenos:

.. literalinclude:: ../examples/mcp3xxx_mcp3008_differential_simpletest.py
:caption: examples/mcp3xxx_mcp3008_differential_simpletest.py
:linenos:

.. literalinclude:: ../examples/mcp3xxx_mcp3004_differential_simpletest.py
:caption: examples/mcp3xxx_mcp3004_differential_simpletest.py
:linenos:
:linenos:

.. literalinclude:: ../examples/mcp3xxx_mcp3002_differential_simpletest.py
:caption: examples/mcp3xxx_mcp3002_differential_simpletest.py
:linenos:
20 changes: 20 additions & 0 deletions examples/mcp3xxx_mcp3002_differential_simpletest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3002 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn

# create the spi bus
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)

# create the cs (chip select)
cs = digitalio.DigitalInOut(board.D5)

# create the mcp object
mcp = MCP.MCP3002(spi, cs)

# create a differential ADC channel between Pin 0 and Pin 1
chan = AnalogIn(mcp, MCP.P0, MCP.P1)

print('Differential ADC Value: ', chan.value)
print('Differential ADC Voltage: ' + str(chan.voltage) + 'V')

0 comments on commit dba64ec

Please sign in to comment.