複天一流:どんな手を使ってでも問題解決を図るブログ

宮本武蔵の五輪書の教えに従い、どんな手を使ってでも問題解決を図るブログです(特に、科学、数学、工学の問題についてですが)

エルチカへの道:pinctrlでエルチカを実現(5年ぶり)

前回のあらすじ

GPIOというのはラズパイの目玉的機能の一つである。それは、(GPIOを通じて)ラズパイに繋いだ外部機器を、自分で書いたソフトウェアで気軽に操作することができるからである。ラズパイを知るよりも遙か以前のことであるが、Linux(Ubuntu)をインストールしたVAIOにUSB接続した測定器をC言語で操作しようと思ったことがあったのだが、とにかく大変であった(libusbは非常に難しかった)。USBの操作プロトコルと比較すると、pythonのライブラリなどで準備されたGPIOの操作プロトコルは「幼児でもわかるんじゃない?」と思えるほど簡単であった。そして、GPIOの操作を簡単にすることができたのはLinuxsysfsという機能のおかげだった。

ところが、2015年ごろにLinuxがこのsysfsという機能を外すことに決めた。急に消滅したわけではなかったらしいが、少しずつ廃止に向かってことが動いていったらしく、ついに2023年から2024年にかけて「sysfsの廃止」は現実的となったようである。

oedocowboys.sakura.ne.jp

今、ラズパイを利用した「エルチカ」のネット記事を検索しても、sysfsに基づくGPIOの操作方法を紹介しているものがほとんどで、まだ情報アップデートの最中のように見える。2023年にRasPi5が発売されたが、GPIOの操作方法は私がもっている教科書や参考書に書いてある方法とは全く違うものとなってしまった。

今回の私の「ラズパイ再起動」の試みでも、「エルチカくらいまではすっとリハビリできるだろう」と思っていたのだが、その当てがはずれて気軽に再開できず、途方に暮れていたのであった。

しかし、前回の調査で、RPi.GPIOというライブラリ自体はなんとか生き延びており、今回設定したラズパイ4bで利用できるらしいことが判明したので、少々安堵したのである。今回は、なんとか「エルチカ」まで辿り着きたいと考えている。

sysfsのサポートはカーネル2.6まで

Wikipediaを引くとsysfsはカーネル2.6の技術だとある。

今回ラズパイ4bにインストールしたRaspberry PI OS Desktopで採用されているカーネル

% uname -r

6.6.74+rpt-rpi-v8

となっていて、昔から見慣れていた2.xではないことに初めて気がついた。カーネルの履歴を調べると、2.6が最後にリリースされたのは2016年である。つまりsysfsが廃止の方向に決まった頃と一致している。その後、カーネルバージョンは3.x, 4.x, 5.xとどんどん数字が増加し(これは2.xが20年近く続いた頃にLinuxを知り、利用してきたものにとっては驚異的な変化にみえる)、今ついに6.xに到達したのだという。しかも私が今ラズパイで利用しているのは6.6だという!なんということだ。

6.xが最初に登場したのは2023年頃なので、sysfs廃止が現実的となった頃に合致している。ということは、今使っているこのカーネルではecho 4 > /sys/class/gpio/exportなどといった操作はできないのかもしれない。

シェルを使った方法で/sys/class/gpioへの書き込みはできなかった

トランジスタ技術Special:ラズパイI/O制御完全マスタ」という雑誌を以前買った。「2023年夏号」とあるから、ラズパイ5がリリースされる直前の発行だろうと思う。この雑誌でも、まだsysfsを使ったGPIO操作を解説している。ただ、この方法が使えなくなることは予感していたようで、49ページに「/sys/class/gpioが使えなくなったときに備えて」といった内容の記事が掲載されている。39ページでもsysfsの廃止についての解説がある。

ただし、そこには「2023年4月段階では利用できている」と書かれていた。今からほんの2年前には問題なく利用できたようで、ちょっと安心してきた。そこで、2025年3月段階で使えるかどうか確認してみることにした。

まずは、このディレクトリ/sys/class/gpioが存在するか確認してみる。

% ls /sys/class/gpio

export  gpiochip512  gpiochip570  unexport

となって、ちゃんと存在していることが確認できた。これなら使えそうな感じに見える。

次は「4番ピン」を操作するために「使用許可申請」を出してみる。この雑誌によれば、次のようにしてshellで操作可能だという。

% echo 4 > /sys/class/gpio/export

この操作により、gpiochip4というファイルが作成されれば「成功」である。GPIOの4番ピン(これはGPIOの「左列」の上から4番目のピン)を使ってエルチカできるようになる。しかし、返ってきたのはエラーであった。

echo: write error: Invalid argument

パミッションを確認すると

--w--w---- 1 root gpio 4096 Mar 18 22:04 /sys/class/gpio/export

少なくともrootなら書き込めそうである。そこでsudo echo 4 > ....とやってみたが、結果は同じであった。雑誌を見ると、一般ユーザーでも気軽にこの操作はできるような感じに書いてあるし、たしか2019年の年末にラズパイ3Bで操作した時は、何の問題もなく、この操作ができた記憶がある。

やはり、sysfsの廃止は始まっていたのである。

49ページの代替手段raspi-gpioを使ってみる

49ページの記事には「使えなくなった時の代替手段」についての解説がある。それによれば、raspi-gpioというコマンドを使え、とのことである。

% which raspi-gpio

/usr/bin/raspi-gpio

このコマンドはまだ残っているようである。しかし、これまでの流れからすると「油断は禁物」である。 まずは4番ピンの状態を確認することができるそうである。

% raspi-gpio get 4

GPIO 4: level=0 func=OUTPUT pull=UP
[ raspi-gpio is deprecated - try `pinctrl` instead ]

エラーメッセージか!と緊張が走ったが、どうやら欲しい情報は一応得られているようである。ただ、raspi-gpioは「骨董品になった」とも書いてある。どうやら、さらに時代が流れてしまったようだ。仕方ないので、pinctrlでも同じようにやってみた(ここから先は雑誌や教科書といった解説がないので、自分で調べながらの操作である)。

% pinctrl get 4

 4: op -- pu | lo // GPIO4 = output

よりシンプルな表示になっているが、シンプルすぎて意味がよくわからない。ただ、raspi-gpioと同じ意味であろうから、翻訳してみる。

opというのは多分outputということであろう。loというのは電圧レベルがlow、つまり0状態ということであろう。puがpull-upになっているということだと思う。これはスイッチを取り付けた時の抵抗器の位置に相当するものである(これは別の教科書に書いてあった)。我々はいまスイッチは使ってないので、これはpn(pull=NO)にしておいていいだろう。ただ、これもやり方はまだわからない。

雑誌を読むと、状態を変えるにはsetを使うらしいことがわかる。まずはraspi-gpioでやってみる。

% raspi-gpio set 4 pn
% raspi-gpio get 4

GPIO 4: level=0 func=OUTPUT pull=NONE

おー!pull=NONEになった。ここで気になったので、ls /sys/class/gpioとしてみたが、gpiochip4というファイルは作成されていなかった。どうもsysfsは経由していないようだ。異なるファイル操作だが、昔と同じコマンドに「翻訳」しているようである。

今度はpinctrlで情報を見てみよう。

% pinctrl get 4
 4: op    pn | lo // GPIO4 = output

予想通りの結果となっている。次は、pinctrlで電圧をhighにしてみよう。pinctrl -hで調べたらdhとすればよいらしい。

% pinctrl set 4 dh

この段階でLEDが点灯した!5年ぶりだと思う(笑)。

LEDが点灯した(左側)。右側はラズパイの電源ランプの赤LED。

4番ピンの状態を調べてみよう。

% pinctrl get 4
4: op -- pn | hi // GPIO4 = output

確かにhiとなっている。

最後にdlを指定してLEDを消せば、一応「エルチカ」の手動版が成功ということになる。

% pinctrl set 4 dl

% pinctrl get 4

 4: op -- pn | lo // GPIO4 = output

エルチカのシェルスクリプト

ということで、bash版のエルチカ用スクリプトが書けるようになった。 具体的には次のようにすればよい。

#!/bin/bash                                                                                 
pinctrl set 4 op pn dl
for(( i=0; i<10; i++)) {
    pinctrl set 4 dh
    sleep 0.5
    pinctrl set 4 dl
    sleep 0.5
}

sysfsを使っていた時は「後始末」というのをやらねばならなかったが、pinctrlを使っているおかげで、そういう細かい処理はユーザーが気にしなくてよいことになっている。つまり、「やりっぱなし」でOKなのである。