Linuxの流儀でGPIOを監視する

Raspberry PiのGPIOにスイッチをつないでその状態を読み取る実験。これがもしArduinoだったらポートを読み続ければいいのだけれど、Raspberry PiはLinuxの流儀でやる必要がある。手短に言うと時間を長く占有してはいけない。Linuxは難しいことを比較的簡単に実現するかわりに簡単なことを比較的難しくする。

gpio_interrupt_view

先達のやりかたを見るとWiringPiやbcm2835ライブラリでピンに割り込みを設定する例が多い。この場合、割り込み関数で頑張ればいろいろな処理ができる。でも、ピンの変化を捉えるだけなら/sys/class/gpio/ピンの名前/edgeにrisingかfallingかbothを書き込むのが手っ取り早い。割り込み関数を呼び出さないから正確には「イベントを発生するだけ」かも知れないが、似たようなもの。そのイベントはpoll関数(システムコール)で検出できる。

スイッチがGPIO25につながっているとするとソースはこんな感じ。

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <poll.h>

int main(){
int i;
int fd;
int ret;
struct pollfd pfd;
char c;

//Enable gpio25
fd = open(“/sys/class/gpio/export”, O_WRONLY);
write(fd, “25”, 2);
close(fd);

//Set gpio25 as input
fd = open(“/sys/class/gpio/gpio25/direction”, O_WRONLY);
write(fd, “in”, 2);
close(fd);

//Set gpio25 interrupt
fd = open(“/sys/class/gpio/gpio25/edge”, O_WRONLY);
//write(fd, “falling”, 7);
write(fd, “both”, 4);
close(fd);

//Wait for interrupt, repeat 10 times.
fd = open(“/sys/class/gpio/gpio25/value”, O_RDONLY);
pfd.fd = fd;
pfd.events = POLLPRI;
for(i = 0; i < 10; i++){
lseek(fd, 0, SEEK_SET);
ret = poll(&pfd, 1, 3000);
read(fd, &c, 1);
if(ret == 0)
printf(“Timeout\n”);
else
printf(“%d=%c\n”, i, c);
}
close(fd);

//Disable gpio25
fd = open(“/sys/class/gpio/unexport”, O_WRONLY);
write(fd, “25”, 2);
close(fd);

return(0);
}

普通にビルドして管理者の権限で実行。
cc pin.c -o pin
sudo ./pin

実行結果はこんな感じ。

gpio_interrupt

スイッチを押すと0を表示し、離すと1を表示し、何もしないと3秒でTimeoutを表示する。読み取りを10回実行したら終了。ただそれだけのソースに丸1日かかった。原因のひとつはManual pageのpoll関数の説明。timeout引数はブロックする最小時間と書いてある。こちらの日本語訳も同じ。これって最大時間の間違いだよね。

gpio_poll_man

マニュアルは真面目に読むタチだが、マニュアル人間じゃダメってことか。

カテゴリー: RaspBerryPi パーマリンク

Linuxの流儀でGPIOを監視する への2件のフィードバック

  1. 中村正明 より:

    Timeoutが最大時間の件。
    設定時間が経過したら、その後でタイムアウト処理が始まりますよね。
    すると、タイムアウト処理までの時間は、設定値よりほぼ確実に長くなります。
    したがって、設定する値は最小値になると思います。

    最大値を入れるのであれば、ゼロも範囲に入るので、まったく待たず
    すぐにタイムアウト処理させても仕様的にはOKですが、実用性ゼロです。
    だって、待ってほしいのに待たずにタイムアウトしてもよくなってしまうって
    使えんでしょう。

    したがって、最大値ではなく、最小値であっているのではないでしょうか?

    • vintagechips より:

      中村正明さん、こんにちは。私がタイムアウトという表現の解釈を間違えたかもしれませんね。私はユーザーの処理(この例でいうとスイッチを押す)に与えられる時間と捉えてヘンだと思いましたが、Linuxがタイムアウト処理を始める時間と解釈すれば正しいですね。なんだ、そういうことか。ありがとうございました。

コメントを残す