Skip to content

Commit dba64ec

Browse files
authored
Merge pull request #20 from 2bndy5/mcp3002-support
MCP3002 support
2 parents 6c16e1c + 9979fa8 commit dba64ec

9 files changed

+221
-76
lines changed

adafruit_mcp3xxx/analog_in.py

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,40 +26,45 @@
2626
differential ADC readings.
2727
2828
* Author(s): Brent Rubell
29+
30+
.. warning::
31+
The ADC chips supported by this library do not use negative numbers. If the resulting
32+
differential read is less than 0, then the returned integer value (and voltage value) is ``0``.
33+
If for some reason the voltage on a channel is greater than the reference voltage or
34+
less than 0, then the returned integer value is ``65472‬`` or ``0`` respectively.
35+
2936
"""
3037

38+
from .mcp3xxx import MCP3xxx
39+
3140
class AnalogIn():
3241
"""AnalogIn Mock Implementation for ADC Reads.
3342
34-
:param ~mcp3004.MCP3004,~mcp3008.MCP3008 mcp: The mcp object.
43+
:param MCP3002,MCP3004,MCP3008 mcp: The mcp object.
3544
:param int positive_pin: Required pin for single-ended.
3645
:param int negative_pin: Optional pin for differential reads.
37-
3846
"""
3947
def __init__(self, mcp, positive_pin, negative_pin=None):
48+
if not isinstance(mcp, MCP3xxx):
49+
raise ValueError("mcp object is not a sibling of MCP3xxx class.")
4050
self._mcp = mcp
4151
self._pin_setting = positive_pin
42-
self._negative_pin = negative_pin
43-
self.is_differential = False
44-
if negative_pin is not None:
45-
self.is_differential = True
46-
self._channels = []
47-
try:
48-
self._pins = self._mcp.MCP3008_DIFF_PINS
49-
except AttributeError:
50-
self._pins = self._mcp.MCP3004_DIFF_PINS
51-
self._pin_setting = self._pins.get((self._pin_setting, self._negative_pin),
52-
"Difference pin not found.")
53-
54-
def __getitem__(self, key):
55-
return self._channels[self._pins[key]]
52+
self.is_differential = negative_pin is not None
53+
if self.is_differential:
54+
self._pin_setting = self._mcp.DIFF_PINS.get((positive_pin, negative_pin), None)
55+
if self._pin_setting is None:
56+
raise ValueError("Differential pin mapping not defined. Please read the "
57+
"documentation for valid differential channel mappings.")
5658

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

6265
@property
6366
def voltage(self):
64-
"""Returns the voltage from the ADC pin as a floating point value."""
67+
"""Returns the voltage from the ADC pin as a floating point value. Due to the 10-bit
68+
accuracy of the chip, returned values range from 0 to (``reference_voltage`` *
69+
65472 / 65535)"""
6570
return (self.value * self._mcp.reference_voltage) / 65535

adafruit_mcp3xxx/mcp3002.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright (c) 2018 Brent Rubell for Adafruit
4+
# Copyright (c) 2019 Brendan Doherty
5+
#
6+
# Permission is hereby granted, free of charge, to any person obtaining a copy
7+
# of this software and associated documentation files (the "Software"), to deal
8+
# in the Software without restriction, including without limitation the rights
9+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
# copies of the Software, and to permit persons to whom the Software is
11+
# furnished to do so, subject to the following conditions:
12+
#
13+
# The above copyright notice and this permission notice shall be included in
14+
# all copies or substantial portions of the Software.
15+
#
16+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
# THE SOFTWARE.
23+
"""
24+
:py:class:`~adafruit_mcp3xxx.MCP3002.MCP3002`
25+
================================================
26+
MCP3002 2-channel, 10-bit, analog-to-digital
27+
converter instance.
28+
29+
* Author(s): Brent Rubell, Brendan Doherty
30+
31+
For proper wiring, please refer to `Package Type diagram
32+
<http://ww1.microchip.com/downloads/en/devicedoc/21294e.pdf#G1.1011678>`_ and `Pin Description
33+
<http://ww1.microchip.com/downloads/en/devicedoc/21294e.pdf#G1.1034774>`_ section of the MCP3002
34+
datasheet.
35+
"""
36+
from .mcp3xxx import MCP3xxx
37+
38+
# MCP3002 Pin Mapping
39+
P0 = 0
40+
P1 = 1
41+
42+
class MCP3002(MCP3xxx):
43+
"""
44+
MCP3002 Differential channel mapping. The following list of available differential readings
45+
takes the form ``(positive_pin, negative_pin) = (channel A) - (channel B)``.
46+
47+
- (P0, P1) = CH0 - CH1
48+
- (P1, P0) = CH1 - CH0
49+
50+
See also the warning in the `AnalogIn`_ class API.
51+
"""
52+
DIFF_PINS = {
53+
(0, 1) : P0,
54+
(1, 0) : P1
55+
}
56+
57+
def read(self, pin, is_differential=False):
58+
self._out_buf[0] = 0x40 | ((not is_differential) << 5) | (pin << 4)
59+
with self._spi_device as spi:
60+
#pylint: disable=no-member
61+
spi.write_readinto(self._out_buf, self._in_buf, out_end=2, in_end=2)
62+
return ((self._in_buf[0] & 0x03) << 8) | self._in_buf[1]

adafruit_mcp3xxx/mcp3004.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
converter instance.
2727
2828
* Author(s): Brent Rubell
29+
30+
For proper wiring, please refer to `Package Types diagram
31+
<https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf#page=1>`_ and `Pin Description section
32+
<https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf#G1.1035093>`_ of the MCP3004/MCP3008
33+
datasheet.
2934
"""
3035

3136
from .mcp3xxx import MCP3xxx
@@ -37,17 +42,24 @@
3742
P3 = 3
3843

3944
class MCP3004(MCP3xxx):
40-
4145
"""
42-
MCP3004 Differential channel mapping.
43-
- 0: CH0 = IN+, CH1 = IN-
44-
- 1: CH1 = IN+, CH0 = IN-
45-
- 2: CH2 = IN+, CH3 = IN-
46-
- 3: CH3 = IN+, CH2 = IN-
46+
MCP3004 Differential channel mapping. The following list of available differential readings
47+
takes the form ``(positive_pin, negative_pin) = (channel A) - (channel B)``.
48+
49+
- (P0, P1) = CH0 - CH1
50+
- (P1, P0) = CH1 - CH0
51+
- (P2, P3) = CH2 - CH3
52+
- (P3, P2) = CH3 - CH2
53+
54+
See also the warning in the `AnalogIn`_ class API.
4755
"""
48-
MCP3004_DIFF_PINS = {
56+
DIFF_PINS = {
4957
(0, 1) : P0,
5058
(1, 0) : P1,
5159
(2, 3) : P2,
5260
(3, 2) : P3
5361
}
62+
63+
def __init__(self, spi_bus, cs, ref_voltage=3.3):
64+
super(MCP3004, self).__init__(spi_bus, cs, ref_voltage=ref_voltage)
65+
self._out_buf[0] = 0x01

adafruit_mcp3xxx/mcp3008.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
converter instance.
2727
2828
* Author(s): Brent Rubell
29+
30+
For proper wiring, please refer to the `Package Types diagram
31+
<https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf#page=1>`_ and `Pin Description section
32+
<https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf#G1.1035093>`_ of the MCP3004/MCP3008
33+
datasheet.
2934
"""
3035

3136
from .mcp3xxx import MCP3xxx
@@ -41,19 +46,22 @@
4146
P7 = 7
4247

4348
class MCP3008(MCP3xxx):
44-
4549
"""
46-
MCP3008 Differential channel mapping.
47-
- 0: CH0 = IN+, CH1 = IN-
48-
- 1: CH1 = IN+, CH0 = IN-
49-
- 2: CH2 = IN+, CH3 = IN-
50-
- 3: CH3 = IN+, CH2 = IN-
51-
- 4: CH4 = IN+, CH5 = IN-
52-
- 5: CH5 = IN+, CH4 = IN-
53-
- 6: CH6 = IN+, CH7 = IN-
54-
- 7: CH7 = IN+, CH6 = IN-
50+
MCP3008 Differential channel mapping. The following list of available differential readings
51+
takes the form ``(positive_pin, negative_pin) = (channel A) - (channel B)``.
52+
53+
- (P0, P1) = CH0 - CH1
54+
- (P1, P0) = CH1 - CH0
55+
- (P2, P3) = CH2 - CH3
56+
- (P3, P2) = CH3 - CH2
57+
- (P4, P5) = CH4 - CH5
58+
- (P5, P4) = CH5 - CH4
59+
- (P6, P7) = CH6 - CH7
60+
- (P7, P6) = CH7 - CH6
61+
62+
See also the warning in the `AnalogIn`_ class API.
5563
"""
56-
MCP3008_DIFF_PINS = {
64+
DIFF_PINS = {
5765
(0, 1) : P0,
5866
(1, 0) : P1,
5967
(2, 3) : P2,
@@ -63,3 +71,7 @@ class MCP3008(MCP3xxx):
6371
(6, 7) : P6,
6472
(7, 6) : P7
6573
}
74+
75+
def __init__(self, spi_bus, cs, ref_voltage=3.3):
76+
super(MCP3008, self).__init__(spi_bus, cs, ref_voltage=ref_voltage)
77+
self._out_buf[0] = 0x01

adafruit_mcp3xxx/mcp3xxx.py

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -40,29 +40,33 @@
4040
* Adafruit CircuitPython firmware for the supported boards:
4141
https://github.com/adafruit/circuitpython/releases
4242
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
43+
44+
.. note:: The ADC chips' input pins (AKA "channels") are aliased in this library
45+
as integer variables whose names start with "P" (eg ``MCP3008.P0`` is channel 0 on the MCP3008
46+
chip). Each module that contains a driver class for a particular ADC chip has these aliases
47+
predefined accordingly. This is done for code readability and prevention of erroneous SPI
48+
commands.
49+
50+
.. important::
51+
The differential reads (comparisons done by the ADC chip) are limited to certain pairs of
52+
channels. These predefined pairs are referenced in this documentation as differential
53+
channel mappings. Please refer to the driver class of your ADC chip (`MCP3008`_,
54+
`MCP3004`_, `MCP3002`_) for a list of available differential channel mappings.
4355
"""
4456

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

48-
49-
from micropython import const
5060
from adafruit_bus_device.spi_device import SPIDevice
5161

52-
# MCP3004/008 data transfer commands
53-
_MCP30084_OUT_BUFF = const(0x00)
54-
_MCP30084_DIFF_READ = const(0x02)
55-
_MCP30084_SINGLE_READ = const(0x3)
56-
57-
5862
class MCP3xxx:
5963
"""
60-
MCP3xxx Interface.
64+
This abstract base class is meant to be inherited by `MCP3008`_, `MCP3004`_,
65+
or `MCP3002`_ child classes.
6166
6267
:param ~adafruit_bus_device.spi_device.SPIDevice spi_bus: SPI bus the ADC is connected to.
6368
:param ~digitalio.DigitalInOut cs: Chip Select Pin.
6469
:param float ref_voltage: Voltage into (Vin) the ADC.
65-
6670
"""
6771
def __init__(self, spi_bus, cs, ref_voltage=3.3):
6872
self._spi_device = SPIDevice(spi_bus, cs)
@@ -72,26 +76,23 @@ def __init__(self, spi_bus, cs, ref_voltage=3.3):
7276

7377
@property
7478
def reference_voltage(self):
75-
"""Returns the MCP3xxx's reference voltage."""
79+
"""Returns the MCP3xxx's reference voltage. (read-only)"""
7680
return self._ref_voltage
7781

7882
def read(self, pin, is_differential=False):
79-
"""SPI Interface for MCP3xxx-based ADCs reads.
83+
"""SPI Interface for MCP3xxx-based ADCs reads. Due to 10-bit accuracy, the returned
84+
value ranges [0, 1023].
8085
8186
:param int pin: individual or differential pin.
8287
:param bool is_differential: single-ended or differential read.
8388
89+
.. note:: This library offers a helper class called `AnalogIn`_ for both single-ended
90+
and differential reads. If you opt to not implement `AnalogIn`_ during differential
91+
reads, then the ``pin`` parameter should be the first of the two pins associated with
92+
the desired differential channel mapping.
8493
"""
85-
command = (_MCP30084_DIFF_READ if is_differential else _MCP30084_SINGLE_READ) << 6
86-
command |= pin << 3
87-
self._out_buf[0] = command
88-
self._out_buf[1] = _MCP30084_OUT_BUFF
89-
self._out_buf[2] = _MCP30084_OUT_BUFF
94+
self._out_buf[1] = ((not is_differential) << 7) | (pin << 4)
9095
with self._spi_device as spi:
9196
#pylint: disable=no-member
92-
spi.write_readinto(self._out_buf, self._in_buf, out_start=0,
93-
out_end=len(self._out_buf), in_start=0, in_end=len(self._in_buf))
94-
result = (self._in_buf[0] & 0x01) << 9
95-
result |= self._in_buf[1] << 1
96-
result |= self._in_buf[2] >> 7
97-
return result
97+
spi.write_readinto(self._out_buf, self._in_buf)
98+
return ((self._in_buf[1] & 0x03) << 8) | self._in_buf[2]

docs/api.rst

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
1-
API
2-
------------
3-
4-
.. automodule:: adafruit_mcp3xxx.mcp3xxx
5-
:members:
6-
7-
.. automodule:: adafruit_mcp3xxx.mcp3004
8-
:members:
9-
:show-inheritance:
10-
11-
.. automodule:: adafruit_mcp3xxx.mcp3008
12-
:members:
13-
:show-inheritance:
14-
15-
.. automodule:: adafruit_mcp3xxx.analog_in
16-
:members:
1+
API
2+
------------
3+
4+
.. automodule:: adafruit_mcp3xxx.mcp3xxx
5+
:members:
6+
7+
.. automodule:: adafruit_mcp3xxx.analog_in
8+
:members:
9+
10+
.. automodule:: adafruit_mcp3xxx.mcp3008
11+
:members:
12+
:show-inheritance:
13+
14+
.. automodule:: adafruit_mcp3xxx.mcp3004
15+
:members:
16+
:show-inheritance:
17+
18+
.. automodule:: adafruit_mcp3xxx.mcp3002
19+
:members:
20+
:exclude-members: read
21+
:show-inheritance:

docs/examples.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,18 @@ Ensure your device works with this simple test.
1111
:caption: examples/mcp3xxx_mcp3004_single_ended_simpletest.py
1212
:linenos:
1313

14+
.. literalinclude:: ../examples/mcp3xxx_mcp3002_single_ended_simpletest.py
15+
:caption: examples/mcp3xxx_mcp3002_single_ended_simpletest.py
16+
:linenos:
17+
1418
.. literalinclude:: ../examples/mcp3xxx_mcp3008_differential_simpletest.py
1519
:caption: examples/mcp3xxx_mcp3008_differential_simpletest.py
1620
:linenos:
1721

1822
.. literalinclude:: ../examples/mcp3xxx_mcp3004_differential_simpletest.py
1923
:caption: examples/mcp3xxx_mcp3004_differential_simpletest.py
20-
:linenos:
24+
:linenos:
25+
26+
.. literalinclude:: ../examples/mcp3xxx_mcp3002_differential_simpletest.py
27+
:caption: examples/mcp3xxx_mcp3002_differential_simpletest.py
28+
:linenos:
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import busio
2+
import digitalio
3+
import board
4+
import adafruit_mcp3xxx.mcp3002 as MCP
5+
from adafruit_mcp3xxx.analog_in import AnalogIn
6+
7+
# create the spi bus
8+
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
9+
10+
# create the cs (chip select)
11+
cs = digitalio.DigitalInOut(board.D5)
12+
13+
# create the mcp object
14+
mcp = MCP.MCP3002(spi, cs)
15+
16+
# create a differential ADC channel between Pin 0 and Pin 1
17+
chan = AnalogIn(mcp, MCP.P0, MCP.P1)
18+
19+
print('Differential ADC Value: ', chan.value)
20+
print('Differential ADC Voltage: ' + str(chan.voltage) + 'V')

0 commit comments

Comments
 (0)