拡張コネクタ外付けの GPIO を操作

何となく I/O 制御の取っ掛かりはつかめたので,次は BeagleBone Black の拡張コネクタ(ボード両端の P8,P9 )に引き出されているピンのうち,GPIO として操作できるものをいじって,入出力を試してみます.

拡張コネクタに引き出されている端子の中には,ボードに実装された他の機能用にすでに割り振られていてそのままでは使えない端子がありますので,まずは,拡張コネクタの中から GPIO として使用できる端子をリファレンスマニュアルなどをもとに確認します.手元の rev.C のボードでのデフォルトで GPIO として使用できる端子をまとめると以下のようになります.これ以外の端子は,すでに MMC や HDMI 用,I2C など用に割当てられていますので,GPIO として使用する際は設定を変更する必要があります.

BBB_ex_pin

端子名の横の番号は,GPIO を制御する際に指定するピン番号で,/sys/class/gpio66 のように,この番号のついたファイルに読み・書きを行なうことでデータの入出力を実現します.今回は,P9 の 11 ~ 15 番端子(GPIO30, 60, 31, 50, 48) に LED を接続して出力の確認用に,P9 16 番端子(GPIO51) にスイッチを接続してデータ入力を確認してみます.実装には,秋月で売られていた BeagleBone ユニバーサルプロトケープを使用しました.

Bone_cape制御プログラムは,基板上の LED 制御のときと同様に,該当する GPIO のファイルを読み書きする形で行います.以下のプログラムで例を示してみます.


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

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>

typedef enum GPIO_DIRECTION_t {
    IN,
    OUT
} GPIO_DIRECTION_t;

typedef enum GPIO_ACTIVE_TRIGGER_t {
    RISING,
    FALLING,
    BOTH
} GPIO_ACTIVE_TRIGGER_t;

typedef struct GPIO_t {
    int num;
    GPIO_DIRECTION_t dir;
    GPIO_ACTIVE_TRIGGER_t trigger;
    int value_fd;
} GPIO_t;

int gpio_open(GPIO_t * gpio, int num, GPIO_DIRECTION_t dir)
{
    int fd;
    FILE *fp;
    char file_path[100];

    fp = fopen("/sys/class/gpio/export", "w");
    if(fp == NULL) {
        return -1;
    }

    fprintf(fp, "%d", num);
    gpio->num = num;
    fclose(fp);

    sprintf(file_path, "/sys/class/gpio/gpio%d/direction", num);
    fp = fopen(file_path, "w");
    if(fp == NULL) {
        return -2;
    }

    if(dir == IN) {
        fprintf(fp, "%s", "in");
    }
    else {
        fprintf(fp, "%s", "out");
    }

    gpio->dir = dir;
    fclose(fp);

    sprintf(file_path, "/sys/class/gpio/gpio%d/value", num);
    fd = open(file_path, O_RDWR | O_SYNC);
    if(fd < 0) {
        return -3;
    }

    gpio->value_fd = fd;

    return 0;
}

int gpio_close(GPIO_t * gpio)
{
    FILE *fp;

    close(gpio->value_fd);

    fp = fopen("/sys/class/gpio/unexport", "w");
    if(fp == NULL) {
        return -1;
    }

    fprintf(fp, "%d", gpio->num);
    fclose(fp);

    return 0;
}

int gpio_out_value(GPIO_t * gpio, int value)
{
    if(gpio->dir != OUT) {
        return -1;
    }

    if(value == 0) {
        write(gpio->value_fd, "0", 1);
    }
    else {
        write(gpio->value_fd, "1", 1);
    }

    lseek(gpio->value_fd, 0, SEEK_SET);

    return 0;
}

int gpio_in_value(GPIO_t * gpio, int * value)
{
    char buff[100];

    if(gpio->dir != IN) {
        return -1;
    }

    read(gpio->value_fd, buff, 100);
    lseek(gpio->value_fd, 0, SEEK_SET);

    *value = atoi(buff);
    return 0;
}

/****************************************************************
* Main
****************************************************************/
int main(void)
{
    int i;
    int count = 0;
    int result;
    int value;

    GPIO_t gpio_p9_11;
    GPIO_t gpio_p9_12;
    GPIO_t gpio_p9_13;
    GPIO_t gpio_p9_14;
    GPIO_t gpio_p9_15;
    GPIO_t gpio_p9_16;

    result = gpio_open(&gpio_p9_11, 30, OUT);
    printf("GPIO P9_11 open : %d\n", result);

    result = gpio_open(&gpio_p9_12, 60, OUT);
    printf("GPIO P9_12 open : %d\n", result);

    result = gpio_open(&gpio_p9_13, 31, OUT);
    printf("GPIO P9_13 open : %d\n", result);

    result = gpio_open(&gpio_p9_14, 50, OUT);
    printf("GPIO P9_14 open : %d\n", result);

    result = gpio_open(&gpio_p9_15, 48, OUT);
    printf("GPIO P9_15 open : %d\n", result);

    result = gpio_open(&gpio_p9_16, 51, IN);
    printf("GPIO P9_16 open : %d\n", result);

    for(i = 0; i < 10000; i++) {
        gpio_out_value(&gpio_p9_11, (count & 0x01) >> 0);
        gpio_out_value(&gpio_p9_12, (count & 0x02) >> 1);
        gpio_out_value(&gpio_p9_13, (count & 0x04) >> 2);
        gpio_out_value(&gpio_p9_14, (count & 0x08) >> 3);
        gpio_out_value(&gpio_p9_15, (count & 0x10) >> 4);

        gpio_in_value(&gpio_p9_16, &value);
        printf("In value = %d\n", value);
        count++;
        usleep(50000);
    }

    result = gpio_close(&gpio_p9_11);
    printf("GPIO P9_11 close : %d\n", result);

    result = gpio_close(&gpio_p9_12);
    printf("GPIO P9_12 close : %d\n", result);

    result = gpio_close(&gpio_p9_13);
    printf("GPIO P9_13 close : %d\n", result);

    result = gpio_close(&gpio_p9_14);
    printf("GPIO P9_14 close : %d\n", result);

    result = gpio_close(&gpio_p9_15);
    printf("GPIO P9_15 close : %d\n", result);

    result = gpio_close(&gpio_p9_16);
    printf("GPIO P9_16 close : %d\n", result);

    return 0;
}

/sys/class/gpio/export に使用する GPIO 番号を書き込み使用可能とした後,,/sys/class/gpio/gpio番号/direction に入出力の方向を指定,出力であれば /sys/class/gpio/gpio番号/value ファイルに出力値を,入力であればここから値を読み取ります.使用後は /sys/class/gpio/unexport で unexport しておきます.

bbb_gpio01[1]

参考文献

参考 URL

BeagleBone Black 技術資料 : http://elinux.org/Beagleboard:BeagleBoneBlack#LATEST_PRODUCTION_FILES_.28C.29

シリコンリナックス社 技術情報 “BeagleBoneBlack の情報” : http://www.si-linux.co.jp/techinfo/index.php?BeagleBoneBlack

Using BeagleBone Black GPIOs : http://www.armhf.com/using-beaglebone-black-gpios/