{"id":462,"date":"2021-10-24T14:08:34","date_gmt":"2021-10-24T14:08:34","guid":{"rendered":"https:\/\/andrejacobs.org\/?p=462"},"modified":"2022-04-11T20:22:59","modified_gmt":"2022-04-11T20:22:59","slug":"talk-to-i2c-devices-directly-from-a-mac-using-the-adafruit-mcp2221a-breakout","status":"publish","type":"post","link":"https:\/\/andrejacobs.org\/electronics\/talk-to-i2c-devices-directly-from-a-mac-using-the-adafruit-mcp2221a-breakout\/","title":{"rendered":"Talk to I2C devices directly from a Mac using the Adafruit MCP2221A Breakout"},"content":{"rendered":"\n
Image by Adafruit<\/a><\/p>\n\n\n\n I came across the Adafruit MCP2221A breakout<\/a> while I was ordering some components from The PiHut and what makes this little board amazing is that it allows you to connect a computer directly to I2C devices and thus skip the "middle microcontroller".<\/p>\n The MCP2221A allows you to connect via USB to an I2C bus and also comes with 4x GPIO, 3x ADC and one DAC.<\/p>\n My plan is to use this for testing various I2C devices as well as write the initial software I require directly and then convert it over to the controller of my choice later.<\/p>\n You can buy them from the following links:<\/p>\n I will be following Adafruit’s guide<\/a> on how to set this little fella up on my Mac and most of the code examples come directly from them.<\/p>\n First test is to just do the classic hello world of Electronics and that is to blink an LED. I will be building the circuit from Adafruit<\/a>.<\/p>\n <\/p>\n Image by Carter Nelson: https:\/\/learn.adafruit.com\/assets\/85988<\/a><\/p>\n <\/p>\n <\/p>\n Image by Carter Nelson: https:\/\/learn.adafruit.com\/assets\/86096<\/a><\/p>\n <\/p>\n There is only so much I can fiddle with test hooks before I end up shorting pins and blowing the board up. Time to solder on the supplied header pins.<\/p>\n The Adafruit board nicely came with male header pins and it was only a matter of breaking off 2x 6 pins and I still had 4 pins left over for another project.<\/p>\n Using a breadboard to solder on headers is the best trick in the book!<\/p>\n <\/p>\n After that I reconnected up the blinking LED circuit to test I didn’t fry any non starchy chips in the process. Hooray it all still works!<\/p>\n It is so handy that this little board comes with 3x analog inputs.<\/p>\n To test the analog signal I will be following the Adafruit example of setting up a voltage divider that you can control through a potentiometer. Their example used a 10K pot whereas I will be using a 100K one that happen to have lying around here used in previous experiments.<\/p>\n <\/p>\n Image by Carter Nelson: https:\/\/learn.adafruit.com\/assets\/85993<\/a><\/p>\n <\/p>\n <\/p>\n Adafruit has a really nice tutorial about I2C<\/a> and an example of how to scan for connected I2C devices.<\/p>\n I connected a Grove-16×2 LCD that came as part of the Grove Starter Kit for Raspberry Pi Pico<\/a> using an Adafruit Grove to STEMMA QT \/ Qwiic \/ JST cable<\/a>.<\/p>\n <\/p>\n <\/p>\n <\/p>\nOverview<\/h2>\n
\n
Installing prerequisite software<\/h2>\n
\n
$ python3 --version\nPython 3.9.6\n<\/code><\/pre>\n
\n
$ mkdir -p adafruit\/mcp2221a\n$ cd adafruit\/mcp2221a\n\n# Copied the files from https:\/\/github.com\/andrejacobs\/scripts\/tree\/main\/Python\/base\n$ .\/new-project.sh\n$ source .\/venv\/bin\/activate\n<\/code><\/pre>\n
\n
(venv)$ pip3 install hidapi\n(venv)$ pip3 install adafruit-blinka\n<\/code><\/pre>\n
\n
(venv)$ .\/update-requirements.sh\n\n(venv)$ cat requirements.txt\nAdafruit-Blinka==6.15.0\nAdafruit-PlatformDetect==3.16.1\nAdafruit-PureIO==1.1.9\nhidapi==0.11.0.post2\npyftdi==0.53.3\npyserial==3.5\npyusb==1.2.1\n<\/code><\/pre>\n
\n
source.sh<\/code> that will source the virtual environment as well as set the required Blinka environment variable.<\/li>\n<\/ul>\n
#!\/bin\/bash\nsource venv\/bin\/activate\nexport BLINKA_MCP2221="1"\n<\/code><\/pre>\n
\n
$ source source.sh\n(venv)$ echo $BLINKA_MCP2221\n\n1\n<\/code><\/pre>\n
\n
(venv)$ python3\n>>> import board\n>>> dir(board)\n['G0', 'G1', 'G2', 'G3', 'I2C', 'SCL', 'SDA', '__blinka__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__repo__', '__spec__', '__version__', 'ap_board', 'board_id', 'detector', 'pin', 'sys']\n<\/code><\/pre>\n
\n
# Check all the attached USB devices\n(venv)$ python3\n>>> import hid\n>>> hid.enumerate()\n...\n'release_number': 256, 'manufacturer_string': 'Microchip Technology Inc.', 'product_string': 'MCP2221 USB-I2C\/UART Combo', 'usage_page': 65280, 'usage': 1, 'interface_number': 2}\n\n>>> device = hid.device()\n>>> device.open(0x04D8, 0x00DD)\n>>> # No errors mean it works\n\n# Check the exported environment variable can be read by Python\n>>> import os\n>>> os.environ["BLINKA_MCP2221"]\n'1'\n\n>>> device.close()\n>>> exit()\n<\/code><\/pre>\n
\n
Testing GPIO<\/h2>\n
\n
blink.py<\/code> and run it using
python3 blink.py<\/code><\/li>\n<\/ul>\n
import time\nimport board\nimport digitalio\n \nled = digitalio.DigitalInOut(board.G0)\nled.direction = digitalio.Direction.OUTPUT\n \nwhile True:\n led.value = True\n time.sleep(0.5)\n led.value = False\n time.sleep(0.5)\n<\/code><\/pre>\n
\n
\n
\n
led-switch.py<\/code> and run it using
python3 led-switch.py<\/code>.<\/li>\n<\/ul>\n
import board\nimport digitalio\n\nled = digitalio.DigitalInOut(board.G0)\nled.direction = digitalio.Direction.OUTPUT\n\nbutton = digitalio.DigitalInOut(board.G1)\nbutton.direction = digitalio.Direction.INPUT\n\nwhile True:\n led.value = button.value\n<\/code><\/pre>\n
\n
Soldering on the headers<\/h2>\n
Testing ADC<\/h2>\n
\n
analog.py<\/code> and run it using
python3 analog.py<\/code><\/li>\n<\/ul>\n
import time\nimport board\nfrom analogio import AnalogIn\n\nknob = AnalogIn(board.G1)\n\ndef get_voltage(raw):\n return (raw * 3.3) \/ 65536\n\nwhile True:\n raw = knob.value\n volts = get_voltage(raw)\n print("raw = {:5d} volts = {:5.2f}".format(raw, volts))\n time.sleep(0.5)\n<\/code><\/pre>\n
\n
Time for the money shot: Testing I2C<\/h2>\n
\n
i2c-scan.py<\/code> and run it using
python3 i2c-scan.py<\/code><\/li>\n<\/ul>\n
"""CircuitPython Essentials I2C Scan example"""\n# If you run this and it seems to hang, try manually unlocking\n# your I2C bus from the REPL with\n# >>> import board\n# >>> board.I2C().unlock()\n\nimport time\nimport board\n\ni2c = board.I2C()\n\nwhile not i2c.try_lock():\n pass\n\ntry:\n while True:\n print("I2C addresses found:", [hex(device_address)\n for device_address in i2c.scan()])\n time.sleep(2)\n\nfinally: # unlock the i2c bus when ctrl-c'ing out of the loop\n i2c.unlock()\n<\/code><\/pre>\n
\n
Reading temperature from the EM2101 PC fan controller<\/h3>\n
\n
\n
(venv)$ pip3 install adafruit-circuitpython-emc2101\n<\/code><\/pre>\n
\n
i2c-scan.py<\/code> program.<\/li>\n<\/ul>\n
(venv)$ python3 i2c-scan.py\nI2C addresses found: ['0x4c']\n<\/code><\/pre>\n
\n
temp.py<\/code> that will only be used for reading the internal temperature sensor.<\/li>\n<\/ul>\n
import time\nimport board\nfrom adafruit_emc2101 import EMC2101\n\ni2c = board.I2C()\nemc = EMC2101(i2c)\n\nwhile True:\n print("Internal temperature:", emc.internal_temperature, "C")\n time.sleep(0.5)\n<\/code><\/pre>\n
\n
(venv)$ python3 temp.py\nInternal temperature: 22 C\nInternal temperature: 21 C\nInternal temperature: 22 C\nInternal temperature: 21 C\nInternal temperature: 21 C\nInternal temperature: 21 C\nInternal temperature: 21 C\nInternal temperature: 21 C\n<\/code><\/pre>\n
Conclusion<\/h2>\n