GPIOダイレクトアクセス

タッチパネル制御にあたり、ふと、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;
}

コメントを残す

メールアドレスが公開されることはありません。