Skip to content

Commit 2e47afc

Browse files
authored
Merge pull request #807 from brentru/force-mcp
Add support for "fake" MCP2221
2 parents 48d6a29 + 9f4b4a3 commit 2e47afc

File tree

12 files changed

+265
-13
lines changed

12 files changed

+265
-13
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
"""Pin definitions for the MicroChip MCP2221"""
5+
from adafruit_blinka.microcontroller.fake_mcp2221 import pin
6+
7+
G0 = pin.G0
8+
G1 = pin.G1
9+
G2 = pin.G2
10+
G3 = pin.G3
11+
12+
SCL = pin.SCL
13+
SDA = pin.SDA

src/adafruit_blinka/microcontroller/fake_mcp2221/__init__.py

Whitespace-only changes.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
"""
5+
`analogio` - Analog input and output control
6+
=================================================
7+
See `CircuitPython:analogio` in CircuitPython for more details.
8+
* Author(s): Carter Nelson
9+
"""
10+
11+
from adafruit_blinka.microcontroller.fake_mcp2221.pin import Pin
12+
from adafruit_blinka import ContextManaged
13+
14+
15+
class AnalogIn(ContextManaged):
16+
"""Analog Input Class"""
17+
18+
def __init__(self, pin):
19+
self._pin = Pin(pin.id)
20+
self._pin.init(mode=Pin.ADC)
21+
22+
@property
23+
def value(self):
24+
"""Read the ADC and return the value"""
25+
return self._pin.value()
26+
27+
# pylint: disable=no-self-use
28+
@value.setter
29+
def value(self, value):
30+
# emulate what CircuitPython does
31+
raise AttributeError("'AnalogIn' object has no attribute 'value'")
32+
33+
# pylint: enable=no-self-use
34+
35+
def deinit(self):
36+
del self._pin
37+
38+
39+
class AnalogOut(ContextManaged):
40+
"""Analog Output Class"""
41+
42+
def __init__(self, pin):
43+
self._pin = Pin(pin.id)
44+
self._pin.init(mode=Pin.DAC)
45+
46+
@property
47+
def value(self):
48+
"""Return an error. This is output only."""
49+
# emulate what CircuitPython does
50+
raise AttributeError("unreadable attribute")
51+
52+
@value.setter
53+
def value(self, value):
54+
self._pin.value(value)
55+
56+
def deinit(self):
57+
del self._pin
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
"""Chip Definition for MCP2221"""
5+
6+
7+
class MCP2221:
8+
"""MCP2221 Device Class Definition"""
9+
10+
def __init__(self):
11+
pass # This is a "fake" implementation
12+
13+
def __del__(self):
14+
# try to close the device before destroying the instance
15+
return
16+
17+
# pylint: enable=unused-argument
18+
19+
20+
mcp2221 = MCP2221()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
"""I2C Class for MCP2221"""
5+
import random
6+
from .fake_mcp2221 import mcp2221
7+
8+
9+
class I2C:
10+
"""Custom I2C Class for MCP2221"""
11+
12+
def __init__(self, *, frequency=100000):
13+
self._mcp2221 = mcp2221
14+
self._freq = frequency
15+
16+
@staticmethod
17+
def scan(address_list=None):
18+
"""Mocks an I2C scan.
19+
If address_list is not provided, this function returns a
20+
list of 3 randomly generated I2C addresses from 0x0 to 0x79.
21+
For a stimulus-driven test: If address_list is provided,
22+
this function returns the provided address_list.
23+
"""
24+
if address_list is None:
25+
# Generate a list of 3 randomly generated addresses from 0x0 to 0x79
26+
address_list = []
27+
for _ in range(3):
28+
address_list.append(random.randint(0x0, 0x79))
29+
return address_list
30+
return address_list
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
"""fake_mcp2221 pin names"""
5+
import random
6+
7+
8+
class Pin:
9+
"""A basic Pin class for use with a "fake" MCP2221."""
10+
11+
# pin modes
12+
OUT = 0
13+
IN = 1
14+
ADC = 2
15+
DAC = 3
16+
# pin values
17+
LOW = 0
18+
HIGH = 1
19+
20+
def __init__(self, pin_id=None):
21+
self.id = pin_id
22+
self._mode = None
23+
self._prv_val = False
24+
25+
def init(self, mode=IN, pull=None):
26+
"""Initialize the Pin"""
27+
if self.id is None:
28+
raise RuntimeError("Can not init a None type pin.")
29+
if pull is not None:
30+
raise NotImplementedError("Internal pullups and pulldowns not supported")
31+
if mode in (Pin.IN, Pin.OUT):
32+
# All pins can do GPIO
33+
# mcp2221.gp_set_mode(self.id, mcp2221.GP_GPIO)
34+
# mcp2221.gpio_set_direction(self.id, mode)
35+
self._mode = mode
36+
elif mode == Pin.ADC:
37+
# ADC only available on these pins
38+
if self.id not in (1, 2, 3):
39+
raise ValueError("Pin does not have ADC capabilities")
40+
# mcp2221.gp_set_mode(self.id, mcp2221.GP_ALT0)
41+
# mcp2221.adc_configure()
42+
elif mode == Pin.DAC:
43+
# DAC only available on these pins
44+
if self.id not in (2, 3):
45+
raise ValueError("Pin does not have DAC capabilities")
46+
# mcp2221.gp_set_mode(self.id, mcp2221.GP_ALT1)
47+
# mcp2221.dac_configure()
48+
else:
49+
raise ValueError("Incorrect pin mode: {}".format(mode))
50+
self._mode = mode
51+
52+
def value(self, val=None):
53+
"""Set or return the Pin Value"""
54+
# Digital In / Out
55+
if self._mode in (Pin.IN, Pin.OUT):
56+
# digital read
57+
if val is None:
58+
# The returned value toggles between True and false
59+
self._prv_val = not self._prv_val
60+
return self._prv_val
61+
# digital write
62+
if val in (Pin.LOW, Pin.HIGH):
63+
# We don't need to do anything here - no data is produced
64+
return None
65+
# nope
66+
raise ValueError("Invalid value for pin.")
67+
# Analog In
68+
if self._mode == Pin.ADC:
69+
if val is None:
70+
# Returned value is between 0 and 65535 inclusive
71+
# https://docs.circuitpython.org/en/latest/shared-bindings/analogio/index.html#analogio.AnalogIn.value
72+
self._prv_val = random.randint(0, 65535)
73+
return self._prv_val
74+
# read only
75+
raise AttributeError("'AnalogIn' object has no attribute 'value'")
76+
# Analog Out
77+
if self._mode == Pin.DAC:
78+
if val is None:
79+
# write only
80+
raise AttributeError("unreadable attribute")
81+
# We don't write to the DAC as this is a "fake" implementation
82+
return None
83+
raise RuntimeError(
84+
"No action for mode {} with value {}".format(self._mode, val)
85+
)
86+
87+
88+
# create pin instances for each pin
89+
G0 = Pin(0)
90+
G1 = Pin(1)
91+
G2 = Pin(2)
92+
G3 = Pin(3)
93+
94+
SCL = Pin()
95+
SDA = Pin()

src/analogio.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,23 @@
99
1010
* Author(s): Carter Nelson, Melissa LeBlanc-Williams
1111
"""
12-
12+
import os
1313
import sys
1414

1515
from adafruit_blinka.agnostic import detector
1616

1717
# pylint: disable=ungrouped-imports,wrong-import-position,unused-import
1818

1919
if detector.board.microchip_mcp2221:
20-
from adafruit_blinka.microcontroller.mcp2221.analogio import AnalogIn
21-
from adafruit_blinka.microcontroller.mcp2221.analogio import AnalogOut
20+
if (
21+
"BLINKA_FORCECHIP" in os.environ
22+
and os.environ["BLINKA_FORCEBOARD"] == "MICROCHIP_MCP2221"
23+
):
24+
from adafruit_blinka.microcontroller.fake_mcp2221.analogio import AnalogIn
25+
from adafruit_blinka.microcontroller.fake_mcp2221.analogio import AnalogOut
26+
else:
27+
from adafruit_blinka.microcontroller.mcp2221.analogio import AnalogIn
28+
from adafruit_blinka.microcontroller.mcp2221.analogio import AnalogOut
2229
elif detector.board.greatfet_one:
2330
from adafruit_blinka.microcontroller.nxp_lpc4330.analogio import AnalogIn
2431
from adafruit_blinka.microcontroller.nxp_lpc4330.analogio import AnalogOut

src/board.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818

1919
import sys
20-
20+
import os
2121
import adafruit_platformdetect.constants.boards as ap_board
2222
from adafruit_blinka.agnostic import board_id, detector
2323

@@ -224,7 +224,13 @@
224224
from adafruit_blinka.board.binho_nova import *
225225

226226
elif board_id == ap_board.MICROCHIP_MCP2221:
227-
from adafruit_blinka.board.microchip_mcp2221 import *
227+
if (
228+
"BLINKA_FORCECHIP" in os.environ
229+
and os.environ["BLINKA_FORCEBOARD"] == "MICROCHIP_MCP2221"
230+
):
231+
from adafruit_blinka.board.fake_microchip_mcp2221 import *
232+
else:
233+
from adafruit_blinka.board.microchip_mcp2221 import *
228234

229235
elif board_id == ap_board.GREATFET_ONE:
230236
from adafruit_blinka.board.greatfet_one import *

src/busio.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
1010
* Author(s): cefn
1111
"""
12+
import os
1213

1314
try:
1415
import threading
@@ -50,8 +51,13 @@ def init(self, scl, sda, frequency):
5051
self._i2c = _I2C(frequency=frequency)
5152
return
5253
if detector.board.microchip_mcp2221:
53-
from adafruit_blinka.microcontroller.mcp2221.i2c import I2C as _I2C
54-
54+
if (
55+
"BLINKA_FORCECHIP" in os.environ
56+
and os.environ["BLINKA_FORCEBOARD"] == "MICROCHIP_MCP2221"
57+
):
58+
from adafruit_blinka.microcontroller.fake_mcp2221.i2c import I2C as _I2C
59+
else:
60+
from adafruit_blinka.microcontroller.mcp2221.i2c import I2C as _I2C
5561
self._i2c = _I2C(frequency=frequency)
5662
return
5763
if detector.board.greatfet_one:

src/digitalio.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
1010
* Author(s): cefn
1111
"""
12-
12+
import os
1313
from adafruit_blinka.agnostic import board_id, detector
1414

1515
# pylint: disable=ungrouped-imports,wrong-import-position,unused-wildcard-import,wildcard-import
@@ -127,7 +127,13 @@
127127
elif detector.board.greatfet_one:
128128
from adafruit_blinka.microcontroller.nxp_lpc4330.pin import Pin
129129
elif detector.board.microchip_mcp2221:
130-
from adafruit_blinka.microcontroller.mcp2221.pin import Pin
130+
if (
131+
"BLINKA_FORCECHIP" in os.environ
132+
and os.environ["BLINKA_FORCEBOARD"] == "MICROCHIP_MCP2221"
133+
):
134+
from adafruit_blinka.microcontroller.fake_mcp2221.pin import Pin
135+
else:
136+
from adafruit_blinka.microcontroller.mcp2221.pin import Pin
131137
elif detector.chip.RP2040_U2IF:
132138
from adafruit_blinka.microcontroller.rp2040_u2if.pin import Pin
133139
# MicroPython Chips

0 commit comments

Comments
 (0)