ArmbianのデバイスツリーオーバーレイでPCF8574を動かしGPIOを増やす

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製チップの場合は以下のドキュメントに記載があり、今回の記事も基本的にこのドキュメントに沿った手法で行った。

Allwinner_overlays - Armbian Documentation

事前準備

オーバーレイ用の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チカしている様子の写真。

TinyConsole

まとめ

Armbianのデバイスツリーオーバーレイの仕組みで、I2C接続のIOエキスパンダPCF8574をLinuxのsysfs経由でGPIOとして使えるようにした。割と簡単に出来てしまうし、デバイスツリーオーバーレイ自体はArmbian固有の仕組みでもないので、シングルボードコンピュータのGPIOが足りなくなった際にPCF8574で増やすためのテクニックとして広く使えそうだ。

同様の方法で他のI2Cデバイスも使えるようになる筈なので、色々試してみたいと思う。

コメント