MCP2221をLinuxカーネル経由で使う

MCP2221はUARTとi2cおよびアナログ・デジタルI/O4本が備わったUSB接続のプロトコルコンバータIC。以前の記事でPCからCircuitPython経由で使う方法を試したのだが、Linuxのカーネルドライバから直接制御出来る事に気づいたので、使い方をまとめた。

スポンサーリンク

LinuxマシンのUSBに接続するだけでペリフェラルが利用可能に

ブレッドボード上でICに配線(と言っても、電源周りのコンデンサとI2Cのプルアップ抵抗ぐらいだが)し、USBケーブルをUbuntu22.04が稼働中のPCと接続する。

写真

すると、自動でカーネルモジュール(hid_mcp2221.ko)がロードされて使える状態になる。

自分の環境ではi2cは/dev/i2c-5、GPIOは/dev/gpiochip4として認識された。UARTもttyACM0として認識されている。

GPIOの状態確認

GPIOの操作は、以前記事にも取り上げたgpiodのコマンド群(“apt install gpiod”でインストール可能)が使える。

gpioinfoでMCP2221の4ラインを確認。

$ gpioinfo /dev/gpiochip4 
gpiochip4 - 4 lines:
    line   0:      unnamed       unused   input  active-high 
    line   1:      unnamed       unused   input  active-high 
    line   2:      unnamed       unused   input  active-high 
    line   3:      unnamed       unused   input  active-high 

GPIOが4ライン使えるように見えるが…チップ内臓のEEPROMに設定値によってはこのまま使えるとは限らないので、要注意。(次節で示す設定ツールを使って設定が必要)

GPIOとして設定されているラインについては、gpiosetで操作可能だ。ライン0をHighに設定するには、以下を実行する。

gpioset gpiochip4 0=1

Lowに設定するには以下。

gpioset gpiochip4 0=1

こんな感じの操作で、該当のピンにLEDを繋げておけば簡単にLチカ出来る。

カーネルに認識されているので、コマンドラインのみならず以前記事にしたのと同じ方法でプログラミングも可能だ。

i2cドライバは不完全?

MCP2221にi2cデバイスを接続した状態でi2cdetect(“apt install i2c-tools”でインストール可能)でスキャンすると、物によって検出出来たり、出来なかったりと不安定。Pythonコードでプログラミングを試みたものの、まともに動作してくれず実用にならない感じ。

MCP2221設定ツールで機能設定を行う

下記Microchipのサイトから、MCP2221 Utilityをダウンロードする。(要Windows環境)

MCP2221
The MCP2221 is a USB-to-UART/I2C serial converter which enables USB connectivity in applications that have a UART and I ...

ZIPを展開しインストーラからインストールする。デバイスをUSBに接続した状態で、MCP2221 Utilityを実行すると以下のような画面が立ち上がる。

HC

シリアル番号の設定

後述のudevでシリアル番号を検出したい場合、”Serial Number”に適宜値を設定したうえで、”Enumerate with serial number”にチェックを入れる。

GPピンの機能設定

4本のGPピンの機能は、それぞれDesignationドロップダウンで選択を行う。

設定内容を内蔵EEPROMへ保存

画面最下部にある”Configure Device”ボタン押下で内蔵EEPROMへ設定内容が保存される。

udevの設定

udevの設定を行うことで、一般ユーザ権限で各ポートにアクセス出来たり、チップの個体を識別して指定のコマンド(シンボリックリンクの作成など)を実行出来るようになる。

デバイス属性の調べ方

udevルールに記述可能なデバイス属性を調べるには、udevadmコマンドを使う。対象デバイスがgpiochip4の時は、以下のコマンドの実行により関連属性の一覧が得られる。

udevadm info -a -p $(udevadm info -q path -n /dev/gpiochip4)

例えば、以下のような感じで、gpiochip4の関連属性が検出される。(ATTRS{serial}は上記「MCP2221 Utility」で設定を行わないと現れないので注意)

  looking at parent device '/devices/pci0000:00/0000:00:15.0/usb1/1-2':
    KERNELS=="1-2"
    SUBSYSTEMS=="usb"
    :
    ATTRS{idProduct}=="00dd"
    ATTRS{idVendor}=="04d8"
    :
    ATTRS{serial}=="0000218660"
    :

一般ユーザに権限を開放する設定

一般ユーザ権限で各ポートにアクセス出来るようにするためには、udevルールを作成する。
/etc/udev/rules.d/の下に例えば99-mcp2221.rulesなど適当なファイル名で以下のような設定をすると良い。

SUBSYSTEM=="gpio", ATTRS{idProduct}=="00dd", ATTRS{idVendor}=="04d8", GROUP="plugdev", MODE="0666"
SUBSYSTEM=="tty", ATTRS{idProduct}=="00dd", ATTRS{idVendor}=="04d8", GROUP="plugdev", MODE="0666"

するとこんな感じで、一般ユーザにデバイスのパーミッションが開く。

$ ls -l /dev/i2c-5 /dev/gpiochip4 /dev/ttyACM0 
crw-rw-rw- 1 root plugdev 254, 4  9月 19 21:20 /dev/gpiochip4
crw-rw-rw- 1 root plugdev 166, 0  9月 19 21:20 /dev/ttyACM0

シリアル番号を検出してデバイス名を固定する設定

一台のPCに複数のMCP2221を接続した場合、チップに書き込まれたシリアル番号を使ってデバイス名を固定したい場合が出てくるだろう。そんな時はudev属性ATTRS{serial}を使って以下のような設定をすると良い。

SUBSYSTEM=="gpio", ATTRS{idProduct}=="00dd", ATTRS{idVendor}=="04d8", ATTRS{serial}=="0000218660", GROUP="plugdev", MODE="0666", SYMLINK+="gpiochip10"
SUBSYSTEM=="tty", ATTRS{idProduct}=="00dd", ATTRS{idVendor}=="04d8", ATTRS{serial}=="0000218660", GROUP="plugdev", MODE="0666", SYMLINK+="ttyACM10"

すると一般ユーザへのパーミッション開放に加えて所定のデバイス名にシンボリックリンクが張られる。

$ ls -l /dev/i2c-10 /dev/gpiochip10 /dev/ttyACM10
lrwxrwxrwx 1 root root 9  9月 19 21:34 /dev/gpiochip10 -> gpiochip4
lrwxrwxrwx 1 root root 7  9月 19 21:34 /dev/ttyACM10 -> ttyACM0

ADC/DACはIIOデバイスとして認識される

殆ど情報が無いので詳細はよく分からないのだが、GP PinをADC(A/Dコンバータ)およびDAC(D/Aコンバータ)として設定した場合は、IIOデバイスとして認識される。iio_infoコマンドで、システムによる検出状態は確認出来る。

$ iio_info 
Library version: 0.24 (git tag: v0.24)
:
IIO context has 1 devices:
    iio:device0: mcp2221
        2 channels found:
            voltage0:  (input)
            2 channel-specific attributes found:
                attr  0: raw value: 175
                attr  1: scale value: 4
            voltage0:  (output)
            2 channel-specific attributes found:
                attr  0: raw value: 8
                attr  1: scale value: 32
        No trigger on this device

情報不足でraw valueとかscaleとかの意味が一切分からずorz

iio_readdevおよびiio_writedevといったコマンドでADCやDACへの値の読み書きが出来るようだが、これじゃ実用にはならないかな…。

まとめ

LinuxのPCにUSBで繋ぐだけで、手軽にカーネルドライバ経由でi2cやGPIOが使えるようになれば便利そうと思ったのだが、肝心のカーネルドライバが不完全でまともに使えそうなのはGPIOとUARTだけという印象。

別記事でカーネルドライバではなくPythonモジュールを使ってのプログラミング方法をまとめたので、実用的な方法はそちらで。

コメント