中々面白そうな IC があったので、ちょいと遊んでみました。
この MCP2221A は、USB から各種通信ができ、しかも GPIO 出力まで対応しているという、単純処理ならマイコン顔負けな IC なわけです。一言で言うなら USB-IO かな?いやそれ以上の機能がありますね。
- USB CDC によって、USB シリアル変換モジュールとして使える
- 何もしなくてもシリアルポートとして認識される。
- I2C が利用可能
- これ以降の機能は USB HID デバイスとして通信を行った場合。
- GPIO としても OK。
- ADC も OK。
- DAC も OK。
- この文句、駄菓子のパッケージで聴いたことあるぞ...?
変な茶番はともかく、結構面白いと思うんですよね。ここでは色々と遊んでみたその過程と一部ハマりどころを記述します。
(最近このブログ、ハマりどころを焦点にしているフシはあるよね)
参考資料
- MCP2221A データシート
- GitHub の libmcp2221a のこの行
- ちょっと古い公式のデータシートで致命的な誤植があったんですよ...(後述)
回路
電源のためにピン接続をします。データシートでは記述がよく分からないのですが、まあ「なんとなく」ででできました。他のサイトで調べても同じような感じなのでまあ大丈夫でしょう(適当)
以下の2通りの接続法がありますが、いずれも結線後に lsusb
をして認識されていれば OK です。
5VをIOから出したい場合
Pin # | Pin Name | Note |
---|---|---|
1 | VDD | VBUS(5V) に接続 |
11 | VUSB | セラコンを介してVSSへ |
12 | D+ | |
13 | D- | |
14 | VSS |
セラコンですが、僕は手持ちの 0.33uF をつなぎました。おそらく内部では3.3V ロジックで動いており、そのための電源生成を IC 内部で行っているものと考えられます。一応この 3.3V は外部に使うことはできるみたいですが、内部のみに使うものと考えるべきなので期待しないほうが良いでしょう。
...ですが、僕は現代に生きる若者なので、3.3V レベルが好きです。
3.3VをIOから出したい場合
Pin # | Pin Name | Note |
---|---|---|
1 | VDD | 外部レギュレータで生成した3.3V に接続 |
11 | VUSB | VDDにショート |
12 | D+ | |
13 | D- | |
14 | VSS |
この IC は VDD の電圧値で IO の High 電圧値が決まるので、ここを 3.3V に落としてしまえばいいということになります。そうすると VUSB が微妙なことになるので、ここを VDD にショートしています。
補足
誤植があります。
Absolute Maximum Ratings で D+, D- の電圧が -0.3V 〜 VUSB + 0.3V と記述されています。これおかしいですよね。
というのも、上の表で示したとおり、VUSB は 常に 3.3V ですので、5V レベルではいけないことになります。
「本当?」って思い、信号線を分圧してみました。するとまんまと動かない。やっぱり誤植なんじゃないですかこれ。おそらく正しくは 5V 程度で対応しているものだと考えられます。
また、古いバージョンのデータシートでは、GPIO 端子のピン機能設定を反映するデータバイトで、送るべきデータ表記が間違っています。これで暫くハマっていましたが、最新のデータシートでは直っていました。秋月の商品ページからダウンロードしたものは間違った版ですので、必ず Microchip のページから最新版をダウンロードしてください。追加ですが、秋月のリンク(2017年のバージョン)は本当にひどくて、誤植のみならず帰ってくるステータスコードの中身も書いてないんですよ。よくこれでリリースしたよな。
やっていこう
それぞれ簡単にですが解説します。
USB to UART
何もしなくていいです。USB シリアルは USB CDC によって自動的に OS の手で仮想 COM ポートとして認識されます。
USB to GPIO
これ以降は、USB HID によるプログラミングが必要です。一般に USB 通信は libusb (あるいは libusb-compat) を使う方法がポピュラー(?)ですが、面倒くさいです。こういう時、僕は hidapi というライブラリを使っています。ドキュメンテーションはこちらです。各自勉強しておいてください(説明の放棄)。
データシートに書いてあるレジスタは 内蔵 Flash に書き込む時のみに参照すべきものです。今回の例では起動後 SRAM を直接イジるので、関係がないことに注意です。
クロック設定やピン方向など、いわゆる「初期化」は SRAM の書き換えが必要だと思ってください。実際の出力値・データの書き込みは内部のペリフェラル(的な所)がやってくれますので、それ用のコマンドを発行します。
また、ステータスレジスタに対応するデータは SRAM 読み出しコマンドで代替できますので、データシートを熟読の上、解釈すると良いと思います。
なお、コンパイルコマンドは例えば以下のようです。
$ gcc -O2 $(pkg-config --cflags --libs hidapi) -Wall -o gp1 gp1.c
なんか GPIO というか、全体的な説明が多くなってしまいましたが、まあそういうわけです。
ソースコードを示します。
USB to I2C
I2C もできちゃいます。こちらは専用のコマンド(0x10)を使います。
通信状況の確認は SRAM を読み出すことで確認できますので、こちらを常時使用。USB HID コマンドを送り、Command Completed のステータスが発行されたとしてもスレーブから ACK を貰ったとは限りません。なので常時 SRAM Read でステータスを確認する必要があります。ここが地味なハマりどころだった。
秋月の AQM1602 で Fuck you!
というきな臭い(というか下品な)メッセージを出すコードは以下。
USB to DAC
なななんとアナログ出力も。こちらは全て SRAM への書き込みコマンドで行います。
難点があるとしたら、DAC 出力ピンの電流ドライブ能力がメチャクチャに低いということですかね...
確認のために赤色 LED + 1kOhm 抵抗を繋いだのですが、最大出力時に 1.7V 弱と、明らかに出力インピーダンスが高かったです。
ですので、実際に LED を光らせる等のことをしたかったら、OPアンプのボルテージフォロワ等の回路を使用してインピーダンス変換を行うことをおすすめします。
USB to ADC
DACに似ています。ADC スタート等のシグナルを送る必要はなく、指定されたコマンドの受信パケット中にデータが格納されます。こちらは特に不便な所とかなし。
〆
ある程度癖はあるものの、USB から直接通信できるのいいですね。個人的には SPI も欲しかったのですが、もしやるとしたら IO パタパタさせて実装するしかなさそうです。
ネット上ではなんかライブラリとか使っているものがあったので、より低レベルな情報の提供ということで本記事を執筆したのでした〜〜