ユーザープロセスでGPIOの割り込みの通知を受け取る方法
GPIO Sysfs Interface for Userspace
このドキュメントのように、gpioが/sys/class/gpioでアクセス可能なようになっていれば、pollシステムコールでGPIOの割り込み通知を受け取ることができます。
これをGolangでやるには以下のようにします。
GolangでGPIOの割り込みの通知を受け取るサンプル
GPIO28が1から0に変化したときに標準出力にメッセージを表示します。
gpio_sample.go
package main
// Use CGO for struct pollfd
// #include <poll.h>
import "C"
import (
"io/ioutil"
"log"
"os"
"syscall"
"unsafe"
)
func main() {
setup()
loop()
}
func loop() (err error) {
var pfd C.struct_pollfd
f, err := os.Open("/sys/class/gpio/gpio28/value")
if err != nil {
return err
}
defer f.Close()
c := make([]byte, 3)
f.Read(c)
log.Printf("first val=%c\n", c[0])
pfd.fd = C.int(f.Fd())
pfd.events = C.POLLPRI
timeout := 3000
for {
f.Seek(0, os.SEEK_SET)
r1, _, errno := syscall.Syscall(
syscall.SYS_POLL,
uintptr(unsafe.Pointer(&pfd)),
uintptr(1),
uintptr(timeout))
if errno != 0 {
return errno
}
if r1 == 0 {
log.Printf("Timeout\n")
} else {
f.Read(c)
log.Printf("val=%c\n", c[0])
}
}
return
}
func setup() {
ioutil.WriteFile("/sys/class/gpio/export", []byte("28"), 0644)
ioutil.WriteFile("/sys/class/gpio/gpio28/direction", []byte("in"), 0644)
//ioutil.WriteFile("/sys/class/gpio/gpio28/edge", []byte("both"), 0644)
//ioutil.WriteFile("/sys/class/gpio/gpio28/edge", []byte("rising"), 0644)
ioutil.WriteFile("/sys/class/gpio/gpio28/edge", []byte("falling"), 0644)
}
システムコール pollを呼ぶために、カーネルのヘッダ内に定義されているstruct pollfdを使用します。そのためにcgoを使用しました。そのため、これをビルドするときには以下のようにCGO_ENABLED=1 とCCでクロスコンパイラを指定します。
CGO_ENABLED=1 CC=arm-buildroot-linux-gnueabi-gcc GOARCH=arm GOARM=7 go build