Common Lispの系譜を継ぐuLispをラズパイPico2マイコン上で練習中。前回はSPIにメモリを接続しました。今回はI2Cバスにメモリを接続です。しかし読み書きの前にI2Cポート・スキャンからです。まあ、uLispの例題そのまま走らせるだけなんだけれども。一応、実機波形を確認。I2Cバス動いてますなあ。
※Lispと一緒 投稿順 index はこちら
※実機確認は Raspberry Pi Pico2で行ってます。
※使用させていただいとります uLisp のバージョンは 4.6b (Arm用)です。
過去回でのラズパイPicoへの接続例
別シリーズの以下の過去回で同じシリアルEEPROMをラズパイPico(RP2040)に接続してみてます。
MicroPython的午睡(17) ラズパイPico、I2CでシリアルEEPROM接続
RP2040でもRP2350でもI2Cインタフェースはほとほぼ同じなのですが、uLispでは選択できるIO端子番号に制限あり、上記とまったく同じ回路とはいきませぬ。
uLispでのI2Cチャネル
RP2040でもRP2350でもハードウエアのI2Cは2回路搭載されています。ハード的には各回路とも複数のGPIO端子から端子をアサインできるようになってますが、uLispではキメウチの端子のみです。対応が以下に。
I2C機能端子 | I2C0 | I2C1 |
---|---|---|
SCL | GP5 | GP27 |
SDA | GP4 | GP26 |
なお、SPI同様 with-i2c というスペシャルフォームでI2Cシリアル・ストリームと変数をバインドするのですが、何も指定しないデフォルトはI2C0の方が選択されます。
24LC64、I2C接続 64kb EEPROM
I2Cスキャンは、I2Cのアドレスに「書きこんでみた」ときにACKが返ってくるのか否かで該当アドレスにデバイスが存在するか否かを判断してます。何かデバイスを接続しないとACKが返ってこないので、今回接続したのは以下のEEPROMです。
MICROCHIP 24LC64 64Kb I2C compatible 2-wire Serial EEPROM
デバイスのI2Cアドレス(7ビット)は0x50~0x57のうちの1個です。下位3ビットはチップにA0、A1、A2端子が出ているのでそこで決定します。
Pico2への接続回路図
今回はuLispのデフォルト値でI2C0に接続なので、以下のような回路となります。I2Cアドレスは0x50(10進で80)としてあります。
WPは使用してません。
I2Cポートスキャナ
I2Cのポートスキャナ用の関数は以下のuLispの解説ページに掲載されてます。
以下です。随分簡単だね。
(defun scan () (dotimes (p 127) (with-i2c (str p) (when str (print p)))))
上記の関数を定義した上で、以下のように scan を呼んでやります。
上の回路が正しく動いていれば、上記のように80(十進、16進では0x50)とACKの返ってきたアドレスが分かります。もしI2Cバスに複数個のデバイス接続されていれば複数個のアドレスが返ります。ううむ、ちゃんと検出されているぞなもし。
0x50へスキャンかけているときの波形が以下に。黄色がSCL、青色がSDAです。
黄色の立ち上がりエッジで7ビット分青の値を読んでいけば 0101000(ここまでデバイスのアドレス 0x50)、その次の1ビットがR/Wですが0なのでWrite、そして末尾のSCL9発目のところは、デバイス側が駆動していてこれがACKです。デバイスが不在であればプルアップ抵抗によってここはHighとなり、デバイスがお返事をしている場合はLowです。クロックの立下りとともにデバイスはACKの駆動を止めるので一度青がHighにプルアップされてます。その後はSTOPコンディション(黄色がハイになってから青色がハイに戻る。)
なお、上記のscan関数だと、オシロで上のような波形を捕まえにくいので、以下のようなtest関数を作ってループで回して上記のような波形を得てます。
(defun test () (with-i2c (str 80) (when str (print 80)))) (loop (test) (delay 500))
I2Cもなんとかなりそう?