I2C接続のIOエキスパンダPCF8574はI2Cバスの入出力を8ビットのIOポートに変換してくれるIC。
以前Arduinoでの使い方を当ブログでも記事に取り上げた。
このPCF8574にはLinuxカーネルドライバが存在するので、これを使うことでPCF8574のIOポートをLinuxのsysfs経由でGPIOとして叩けるようになる。
ひと昔前のカーネルでは「カーネルドライバを使う」と言うとカスタムカーネルが必要だったが、最近のカーネル(バージョン4.x以降)ではデバイスツリーオーバーレイの仕組みを使って比較的簡単に出来る。
今回はArmbianでデバイスツリーオーバーレイを使いPCF8574を動かす方法を記事にまとめる。
デバイスツリーオーバーレイとは?
デバイスツリーとは、システムのハードウエアとカーネルドライバを関連付ける仕組みで、以前の記事で簡単な解説を行った。
そしてデバイスツリーオーバーレイとは、定義済みのデバイスツリーに対して設定を追加する仕組み。
Armbianなどのディストリビューションではメジャーなハードウエアのカーネルドライバそのものはモジュールの形で既にインストールされており、デバイスツリーオーバーレイによってハードウエアとドライバの対応付けを行うだけで対応ハードウエアを動かすことが出来る。
Armbianでデバイスツリーオーバーレイを使うための具体的な方法はSoCごとに多少違うようだが、Nano Pi Neo2に載っているAllwinner製チップの場合は以下のドキュメントに記載があり、今回の記事も基本的にこのドキュメントに沿った手法で行った。
事前準備
オーバーレイ用のDTSファイルを作るのにあたり、事前にハードウエア情報を確認をしておく。
システム定義のデバイスツリーでI2Cバスのラベルを確認
デバイスツリーオーバーレイでI2Cの設定を追加するためには、I2Cバスのデバイスツリー上のラベルを知る必要がある。Nano Pi Neo2の場合はI2Cバス定義自体が/boot/dtb/allwinner/overlay/sun50i-h5-i2c0.dtboというファイルにオーバーレイで定義されており、このファイルをdtcによる逆コンパイルで確認する。
dtc -I dtb -O dts /boot/dtb/allwinner/overlay/sun50i-h5-i2c0.dtbo
上記コマンドを実行すると以下のような出力が得られ、”i2c0″というラベルで参照出来ることがわかる。
/dts-v1/;
/ {
compatible = "allwinner,sun50i-h5";
fragment@0 {
target-path = "/aliases";
__overlay__ {
i2c0 = "/soc/i2c@1c2ac00";
};
};
:
PCF8574をI2Cバス上で確認する
PCF8574をI2Cバスにデバイスを接続したうえで、i2cdetectコマンドを実行し、対象のデバイスが検出出来るか確認しておく。0x22に検出された。
$ sudo i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- 22 -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
:
PCF8574のデバイスツリーオーバーレイ設定ファイルを作る
収集した情報に基づいて、以下のようなデバイスツリーオーバーレイの設定ファイルを作り、i2c-devices.dtsというファイル名で保存する。
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&i2c0>;
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
pcf8574: pcf8574a@22 {
compatible = "nxp,pcf8574a";
reg = <0x22>;
gpio-controller;
#gpio-cells = <2>;
};
};
};
};
ポイントは、
- 6行目: オーバーレイのターゲットはラベル名”i2c0″
- 11,13行目: PCF8574のI2Cアドレス0x22を指定する
- 12行明: PCF8574のカーネルドライバ”nxp,pcf8574a”を指定する
デバイスツリーオーバイレイの有効化
コンパイルして所定ディレクトリにdtboファイルを配置
ユーザー定義のdtboファイルは/boot/overlay-user/に置く決まりになっている。dtcのコンパイル出力先を/boot/overlay-user/下に指定し、i2c-devices.dtsのコンパイルを実行。
sudo mkdir /boot/overlay-user
sudo dtc -I dts -O dtb -o /boot/overlay-user/i2c-devices.dtbo i2c-devices.dts
有効化
u-boot環境変数ファイル/boot/armbianEnv.txtに以下の一行を追加すると、作成したデバイスツリーオーバーレイの定義が有効化される。
user_overlays=i2c-devices
マイコンを再起動して確認
マイコンを再起動し起動メッセージを確認。適切にドライバが組み込まれるとドライバ名(pcf857x)の後に”probed”の文字列が現れる。
$ dmesg | grep pcf857x
[ 2.863710] pcf857x 0-0022: probed
またPCF8574のドライバが適切に読み込まれれば、i2cdetectを実行した時の表示がUUに変わる。ドライバが読み込めていないと表示が変わらないので、設定が間違っていないかどうかの目安になる。
$ sudo i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- UU -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
:
gpioinfoコマンドを実行すると、SoCのGPIOに加えてgpiochi2にPCF8574のGPIOも検出される。
$ sudo gpioinfo
gpiochip0 - 32 lines:
line 0: unnamed unused input active-high
line 1: unnamed unused input active-high
line 2: unnamed "usb0-vbus" output active-high [used]
:(略)
gpiochip1 - 224 lines:
line 0: unnamed unused input active-high
line 1: unnamed unused input active-high
line 2: unnamed unused input active-high
:(略)
gpiochip2 - 8 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
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
sysfsでPCF8574をGPIOとして操作してみる
sysfsを確認すると、SoCのGPIOデバイスの他にgpiochip504というデバイスが出来ている(PCF8574を接続する前に確認しておくと差分が分かりやすい)。何故504という変な番号が付いているかといえば、GPIO番号が504〜割り当てられているから。
$ ls /sys/class/gpio/
export gpiochip0 gpiochip352 gpiochip504 unexport
sudoだとsysfsに対するリダイレクトがうまく動作しないので、sudo suでrootになってしまう。
sudo su
PCF8574の先頭GPIO504番を有効化する。
echo 504 > /sys/class/gpio/export
出力に設定。
echo out > /sys/class/gpio/gpio504/direction
Highにする。
echo 1 > /sys/class/gpio/gpio504/value
Lowにする。
echo 0 > /sys/class/gpio/gpio504/value
現在値の確認。
cat /sys/class/gpio/gpio504/value
こんな感じで、gpio504〜gpio511の8本が使えるようになる。
Lチカの様子
PCF8574のIOポートにLEDを接続し、sysfsのコマンドライン操作でLチカしている様子の写真。
まとめ
Armbianのデバイスツリーオーバーレイの仕組みで、I2C接続のIOエキスパンダPCF8574をLinuxのsysfs経由でGPIOとして使えるようにした。割と簡単に出来てしまうし、デバイスツリーオーバーレイ自体はArmbian固有の仕組みでもないので、シングルボードコンピュータのGPIOが足りなくなった際にPCF8574で増やすためのテクニックとして広く使えそうだ。
同様の方法で他のI2Cデバイスも使えるようになる筈なので、色々試してみたいと思う。
コメント