Adafruit MCP2221A モジュールを使う

完全に宣伝のようです。失礼

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/4697ebef-8772-6d50-1840-c7c83eb1afaa.png)

# これは何？

- USB 2.0 to I2C/UART Protocol Converter with GPIO というチップです。
- PCからPythonを使って手軽にIOにアクセスできる，というのがいいですね。
- ADC/DAC/I2C/UARTも使えます。

# セットアップ

わかりやすい解説がありますのでここでは省略します。

- https://learn.adafruit.com/circuitpython-libraries-on-any-computer-with-mcp2221

実行前に環境変数を確認するのが面倒といえば面倒ですが，それほどでもありません。

要するにCircuitPythonのライブラリーをPC上のPythonから使えるようにして，それを使ってMCP2221Aにアクセスしよう，ということになります。

Pythonでも別のアプローチもあるようです。

- https://qiita.com/usashirou/items/b3e1075c80113900c285

MicrochipからWindows用のCLI等も公開されています。

- https://www.microchip.com/en-us/product/MCP2221A

ここでは主に私のMacで，adafruitのガイドに沿って使うことに関して書きます。

# ADを読んでlogを書いてみる

PCのストレージを使えるので，心置きなくログを書き出せそうですね。

```AD_log.py
import board
from analogio import AnalogIn
import time

AD1 = AnalogIn(board.G1) # 10bit but 16bit comply by CircuitPython

f=open('log.csv','w')
f.write("count,ADC\n")

for i in range(10):
    s=str("%d,%d" % (i, AD1.value>>6))
    print(s)
    f.write(s)
    f.write("\n")
    time.sleep(1)

f.close()
```

実行例 G1端子を半固定抵抗に接続し，手作業で回しています。

```bash
$ python3 AD_log.py
0,0
1,60
2,186
3,333
4,411
5,471
6,600
7,704
8,990
9,1023
$ cat log.csv
count,ADC
0,0
1,60
2,186
3,333
4,411
5,471
6,600
7,704
8,990
9,1023
$
```

- https://learn.adafruit.com/circuitpython-libraries-on-any-computer-with-mcp2221/adc

によれば，`Note that even though the MCP2221's ADC is only 10 bits, the value is scaled to 16 bits to comply with the CircuitPython API.` とのことです。

調べてみましたが，線形性はいいので，使い勝手が良さそうです。G1/G2/G3の3つのピンがADとして使えるとのことです。

# 簡単なGUIアプリを書いてみる

初めてtkinterを使ってみました。

```tk_AD.py
import tkinter as tk

import board
from analogio import AnalogIn

def refresh_message():
    label["text"] = str("\nAD(G1) %.3f[V]" % (3.3*(AD1.value>>6)/1023) )
    root.after(100, refresh_message)

AD1 = AnalogIn(board.G1)

root = tk.Tk()
root.title("Read AD(G1) every 100msec")
root.geometry("400x200")
label = tk.Label(font=("",24, "bold"))
label.pack()
refresh_message()
root.mainloop()
```

実行例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/edf739b6-80e3-7456-4a12-1a3018aaafac.png)

# I2Cを使ってみる

普通にCircuitPythonでI2Cを使う感覚ですね。INA219モジュールを接続しました。

```INA219.py
import board
i2c = board.I2C()

def readRegisterI2C16(a): # a=pointer address
    while not i2c.try_lock():
        pass
    i2c.writeto(0x40, bytes([a]), stop=False)
    d = bytearray(2)
    i2c.readfrom_into(0x40, d)
    i2c.unlock()
    return(d[0] << 8 | d[1])

def writeRegisterI2C16(a, d): # a=pointer address, d=16bit data
    while not i2c.try_lock():
        pass
    i2c.writeto(0x40, bytes([a, int(d)>>8, int(d) & 0xff]), stop=False)
    i2c.unlock()

# convert 2's complement (ref)
# https://note.com/suujyou3/n/n35fca266f7b6

def toSigned16(d):
    return((d>>15) * (2**15) * (-1) + (d & 0x7FFF))

writeRegisterI2C16(5, 40.96 / 0.1) # Rshunt=0.1

print("Voltage: %d[mV]" % ((readRegisterI2C16(2)>>3)*4))
print("Current: %d[mA]" % (toSigned16(readRegisterI2C16(4))))
```

実行例 確認のため，あえて負の電流値になるように接続しています。

```
$ python3 INA219.py
Voltage: 3284[mV]
Current: -4[mA]
$
```

# DACを使ってみる

- G2/G3がDACとして使えます。
- 出力インピーダンスが5kと大きいので要注意です。
- 精度は5ビットと控えめです。CircuitPythonでは16ビットで指定します。`Note that even though the MCP221's DAC is only 5 bits, you set it using a 16 bit value to comply with the CircuitPython API.`
- 上記の方法で，INA219を併用してログを書いてグラフにしてみました。線形を期待してはいけないようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/68563e6e-b284-1781-bf58-bfd13fe893e8.png)

# USB - UART 変換として使う

こちらはスクリプト無しで，接続すればすぐに使えます。

# おしまい

低レベルIOというのでしょうか，ロジックレベル，あるいは 0 - 3.3V の電圧をPCから直接扱うというのは新鮮な感覚ですね。