PC直付I2CをLinuxで使う

PCには複数のI2Cラインが存在し、それらを取り出して使えないものかと常々思っていたのだが、VGAやHDMIの端子から出ていることを知り、実際に信号を取り出して触ってみたので記事にまとめる。

スポンサーリンク

VGA端子からI2C信号を取り出す

VGAの端子は全部で15ピン。今となっては使う機会もめっきり減ったVGAケーブルだが、ピンレイアウトを確認。

Photo

主なピンアサインは以下の通り。

ピン番号信号名備考
1RED赤映像信号
2GREEN緑映像信号
3BLUE青映像信号
6RGND赤GND
7GGND緑GND
8BGND青GND
9KEY+5Vが出ている
10GND
12SDA
15SCL

何故VGAからI2Cが生えているかというと、ディスプレイとPCとの間で解像度などの情報をやりとりするDDC(Display Data Exchange)インターフェースとして使われているから。

インピーダンス検出回路で有効化される

PC搭載のVGAコントローラーにもよると思うが、自分のPCでは映像信号端子に負荷が接続されないとi2cバスが有効にならなかった。赤、青、緑の各映像信号端子(1-6間, 2-7間もしくは3-8間)の特性インピーダンスは75Ωなので、近い値の抵抗(100Ωなど)を取り付けるとi2cバスがi2cdetectコマンドで見えるようになった。

利用可能アドレスが限定されている場合も

VGA端子から引き出したI2CラインにI2Cデバイスを繋いでi2cdetectコマンドを実行すると検出出来ないデバイスがあり、原因が分からず暫く悩んでしまった。ロジアナでバスの信号を監視しながらi2cdetectコマンドを実行したところ、I2Cラインに流れて来るスキャン対象のアドレス自体に以下のような制限がある事に気づいた。

  • 0x21〜0x3F(奇数アドレスのみ)
  • 0x61〜0x7F(奇数アドレスのみ)

ロジアナのプロトコルアナライザを有効にしてバス監視を行った結果は以下のような感じ。偶数アドレスしかスキャンされないため該当するタイミングが空白となりチャートが歯抜けになっている。

スキャン結果

チャートをズームアウトしてしてみると、0x40〜0x5Fの期間もごっそり抜けている様子も観察出来た。
どうやら外に出ているSCL,SDAの物理ラインとPC側のI2Cコントローラーの間にI2Cマルチプレクサのような物が挟まっているようで、残念ながら全てのI2Cスレーブアドレスが使えるのではなさそう。

このあたりもPCに搭載されたVGAコントローラーの仕様に応じて色々ありそうで、注意が必要な所だろう。

i2cデバイスをカーネルドライバで動かす方法

SBCなどデバイスツリーが使えるシステムであれば、i2cバスに関する記述を追加するだけでi2cデバイスのカーネルドライバを有効化する事が出来るのだが、PCではデバイスツリーが使えないためsysfsを使ってカーネルドライバの有効化を行う。

sysfsを用いたカーネルドライバの有効化

例えば、i2c-4にPCF8574がスレーブアドレス0x23で接続されている場合は、以下を実行することでカーネルに認識させる事が出来る。

echo pcf8574 0x23 | sudo tee /sys/bus/i2c/devices/i2c-4/new_device

成功すると、gpiodetectでPCF8674がgpiochipとして認識される。自分の環境では、gpiochip4として認識された。

$ sudo gpiodetect 
gpiochip0 [INT3453:00] (80 lines)
:(略)
gpiochip4 [pcf8574] (8 lines)

gpioinfoで状態を確認出来る。

$ gpioinfo gpiochip4
gpiochip4 - 8 lines:
    line   0:      unnamed       unused  output  active-high 
    line   1:      unnamed       unused  output  active-high 
    line   2:      unnamed       unused  output  active-high 
    line   3:      unnamed       unused  output  active-high 
    line   4:      unnamed       unused   input  active-high 
    line   5:      unnamed       unused   input  active-high 
    line   6:      unnamed       unused   input  active-high 
    line   7:      unnamed       unused   input  active-high 

あとは以前記事にしたgpiodのコマンドラインツールを使ってネイティブGPIOとして制御可能だ。

gpioset gpiochip4 3=1

蛇足だが、カーネルドライバが適用されたスレーブアドレスはi2cdetectによるデバイス検出結果が変化する。PCF8574にカーネルドライバを適用後i2cdetectコマンドで実行すると…

$ i2cdetect -y 4
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- UU -- -- -- -- -- -- -- -- -- -- -- -- 
30: 30 -- 32 -- 34 -- -- -- -- -- -- -- -- 3d -- -- 
:

スレーブアドレス0x23はPCF8574、0x3dはSSD1306で他はDDC用の物。PCF8574のアドレスがUU表示になっており、カーネルドライバが適用されていることの確認にもなる。

カーネルドライバ無効化もsysfs経由で

カーネルドライバを無効化したい時は以下を実行する。

echo 0x23 | sudo tee  /sys/class/i2c-adapter/i2c-4/delete_device 

一般ユーザ権限で使えるようにする

i2cバスやカーネルに認識させたGPIOのパーミッション設定方法を書いておく。

i2cバス

/etc/groupを編集し、i2cグループにユーザ名を追加する。

i2c:x:146:username

ログアウト後、次回ログイン時から有効になる。

GPIO

PCF8574をカーネルに認識させた後、一般ユーザ権限で使えるようにするには、適当なファイル(例えば、/etc/udev/rules.d/98-pcf857x.rules)にudevルールを追加する。

SUBSYSTEM=="gpio", KERNEL=="gpiochip[4-9]*", GROUP="plugdev", MODE="0666"

以下でudevルールを有効化。

sudo udevadm control --reload-rules
sudo udevadm trigger

コネクタを自作してブレッドボードに接続

VGAのメスコネクタにはんだ付けでコネクタを自作し、ブレッドボードに組んだMOSFETによる3.3Vへのレベルシフタ回路を介してPCF8574とSSD1306を接続してみた。SSD1306は普通に使える。

Photo

まとめ

VGAポートから生えているi2cバスならマイコンなどを間に挟まなくてもPCから直接i2cデバイスを制御出来るので非常に手軽。今となってはVGAポートを本来の目的に使う機会も殆ど無いので、電子工作用に専有させても支障が無く、おまけに+5Vの電源も出ているのでちょっとした回路を組んで使うのにも便利。

一点残念なのが、スレーブアドレスが歯抜けになっていて使えるi2cデバイスが限られてしまう点。とはいえ自分のPCではPCF8574のアドレス範囲は問題なく、カーネルドライバでネイティブのGPIOとして使えるようになるのは大きなメリット。特にLinux PCから直接GPIOを使いたい時に重宝しそうだ。

コメント