タッチパネル制御にあたり、ふと、LinuxからGPIO入出力がファイルインタフェースなのがなんか気持ち悪い(大げさ)と思っていることを思い出した
そこで、ダイレクトアクセスについて調べてみた
おそらくCPUのレジスタをアクセスすることになると思い、BBBに使用されているCPUのマニュアルを読む
今回試すアクセスはGPIO_49からの入力とGPIO_47への出力
GPIOは32ポート毎にレジスタがあり、49は32×1+17、47は32×1+15でGPIO1ということがわかる
GPIO1の先頭アドレスは 0x4804C000 として各レジスタは
- 入出力設定は +0x134(GPIO_OE 0x4804C134)
- データ取得は +0x138(GPIO_DATAIN 0x4804C138)
- 出力をLOW(0)にするには +0x190(GPIO_CLEARDATAOUT 0x4804C190)
- 出力をHIGH(1)にするには +0x194(GPIO_SETDATAOUT 0x4804C194)
となり、ここをアクセスしてみたら、できた\(^o^)/
GPIO_49ポートから取得する例
#include <stdlib.h> #include <stdio.h> #include <sys/mman.h> #include <fcntl.h> #define GPIO1_START_ADDR 0x4804C000 #define GPIO1_END_ADDR 0x4804DFFF #define GPIO1_SIZE (GPIO1_END_ADDR - GPIO1_START_ADDR) #define GPIO1_OE 0x0134 #define GPIO1_DATAIN 0x0138 #define GPIO_49_BIT 17 // = 49 - 1 x 32 int main(){ volatile void *gpio1_addr = NULL; volatile unsigned int *gpio1oe = NULL; volatile unsigned int *gpio1in = NULL; int fd; if( (fd = open("/dev/mem",O_RDWR)) < 0) exit(1); if( (gpio1_addr = mmap(0, GPIO1_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO1_START_ADDR)) == MAP_FAILED) exit(1); gpio1oe = gpio1_addr + GPIO1_OE; gpio1in = gpio1_addr + GPIO1_DATAIN; *gpio1oe |= 1<<GPIO_49_BIT; printf("GPIO_49 : %d\n",(*gpio1in>> GPIO_49_BIT)&1); close(fd); return 0; }
GPIO_47ポートへ出力する例
#include <stdlib.h> #include <stdio.h> #include <sys/mman.h> #include <fcntl.h> #define GPIO_OE 0x0134 #define GPIO_CLEARDATAOUT 0x190 #define GPIO_SETDATAOUT 0x194 #define GPIO1_START_ADDR 0x4804C000 #define GPIO1_END_ADDR 0x4804DFFF #define GPIO1_SIZE (GPIO1_END_ADDR - GPIO1_START_ADDR) #define GPIO_47_BIT 15 // = 47 - 1 x 32 int main(){ volatile void *gpio1_addr = NULL; volatile unsigned int *gpio1oe = NULL; volatile unsigned int *gpio1out0 = NULL; volatile unsigned int *gpio1out1 = NULL; int fd; if( (fd = open("/dev/mem",O_RDWR)) < 0) exit(1); if( (gpio1_addr = mmap(0, GPIO1_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO1_START_ADDR)) == MAP_FAILED) exit(1); gpio1oe = gpio1_addr + GPIO_OE; gpio1out0 = gpio1_addr + GPIO_CLEARDATAOUT; gpio1out1 = gpio1_addr + GPIO_SETDATAOUT; *gpio1oe &= ~(1<<GPIO_47_BIT); *gpio1out1 = 1<<GPIO_47_BIT; usleep(3000000); *gpio1out0 = 1<<GPIO_47_BIT; close(fd); return 0; }