Raspberry PIのGPIOのデバイスドライバを作成します。「bcm2835 ライブラリによるスイッチ入力とLEDの点滅 」で使用したタクトスイッチから入力させます。
GPIOデバイスドライバ
GPIOポートに接続されたタクトスイッチから接点信号を入力するため、「Raspberry PIのGPIOのデバイスドライバ – Open 」で作成したデバイスドライバーのファイル操作構造体「file_operations」に、GPIOの読み込みデバイスドライバ関数「raspi_gpio_read」のアドレスと、GPIOの読み込みデバイスドライバ関数「raspi_gpio_read」を追加します。
デバイスのマイナー番号をGPIOポート番号とする設計ですが、今回は強制的にタクトスイッチから接点信号を入力するため、GPIOポート「24」とし、raspi_gpio_read関数の7行目に「gpio = 24;」を挿入しました。
raspi_gpio_read関数で使用しているgpio_direction_input関数とgpio_get_value関数について次に示します。
- gpio_direction_input
- 入出力制御を入力側にする。
- gpio_get_value
- パラメータで指定されたGPIO番号から信号レベルを入力して戻り値で呼び出し元に通知する。
また、システム・コールの引数を、ユーザー空間に対して出し入れするために使用できる複数の関数が、用意されています。オプションには、基本型に対応した単純な関数 (get_user や put_user など) や、構造体や配列などのデータ・ブロックを移動させるための関数 (copy_from_user と copy_to_user) が含まれます。
今回使用するput_user 関数は、 呼び出し方法が「put_user(x,ptr);」となり、カーネル変数 (x) が指定する値を、指定されたユーザー空間アドレス (ptr) に移動させます。
ファイル操作構造体file_operations
/* File operation structure */ static struct file_operations raspi_gpio_fops = { .owner = THIS_MODULE, .open = raspi_gpio_open, .read = raspi_gpio_read, .write = raspi_gpio_write, };
GPIOの読み込みデバイスドライバ関数raspi_gpio_read
static ssize_t raspi_gpio_read ( struct file *filp,char *buf,size_t count,loff_t *f_pos){ unsigned int gpio; char byte; // gpio = iminor(filp->f_path.dentry->d_inode); gpio = 24; byte = '0' + gpio_get_value(gpio); put_user(byte, buf); return 1; }
GPIOの書き込みデバイスドライバ関数raspi_gpio_write
static ssize_t raspi_gpio_write ( struct file *filp, const char *buf, size_t count, loff_t *f_pos) { if (strcmp(kbuf, "in") == 0) { if (raspi_gpio_devp->dir != in) { printk(KERN_INFO "Set gpio[%d] direction: input\n", gpio); spin_lock_irqsave(&raspi_gpio_devp->lock, flags); gpio_direction_input(gpio); raspi_gpio_devp->dir = in; spin_unlock_irqrestore(&raspi_gpio_devp->lock, flags); } } else { ・ ・ ・
ユーザープログラム
ユーザプログラムではWrite関数とread関数をそれぞれ1回づつ呼び出します。最初にGPIOからタクトスイッチのデータの入力するため、Write関数で”in”を書き込みます。次に、タクトスイッチから、read関数を用いてスイッチ情報を入力します。タクトスイッチを押してユーザープログラムを実行すると、レベル情報が「Logic level: 1」と表示されます。押さないでユーザープログラムを実行すると、レベル情報が「Logic level: 0」と表示されます。
/* * Name : input_test.c */ #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #define NUM_GPIO_PINS 21 #define MAX_GPIO_NUMBER 32 #define BUF_SIZE 3 #define PATH_SIZE 20 int main(int argc, char **argv) { int i = 0, index = 0; int fd; char path[PATH_SIZE]; char buf[BUF_SIZE]; char readBuf[2]; printf("gpio open\n"); // Open all GPIO pins snprintf(path, sizeof(path), "/dev/raspiGpio0"); fd = open(path, O_RDWR); if (fd < 0) { perror("Error opening GPIO pin"); exit(EXIT_FAILURE); } // Set direction of GPIO pins to input printf("Set pins to input\n"); strncpy(buf, "in", 2); buf[2] = '\0'; if (write(fd, buf, sizeof(buf)) < 0) { perror("write, set pin input"); exit(EXIT_FAILURE); } // Read logic level of GPIO pins and display them to the terminal printf("gpio read\n"); if (read(fd, readBuf, 1) < 1) { perror("read"); exit(EXIT_FAILURE); } readBuf[1] = '\0'; printf("GPIO pin: 24 Logic level: %s\n", readBuf); return EXIT_SUCCESS; }
実行したデバイスドライバのログを次に示します。
# dmesg ・ ・ [ 2500.431564] GPIOstart open [ 2500.431602] GPIO[0] opened [ 2500.433749] Request from user: in [ 2500.433788] Set gpio[24] direction: input
デバイスドライバのraspi_gpio_write関数により、”[ 2500.433788] Set gpio[24] direction: input”がログされており、GPIOポート24がin制御されていることが確認できます。
タクトスイッチを押さないでユーザープログラムを実行すると、次のように「Logic level: 0」が表示されます。
# ./input_test gpio open Set pins to input gpio read GPIO pin: 24 Logic level: 0
タクトスイッチを押してユーザープログラムを実行すると、次のように「Logic level: 1」が表示されます。
# ./input_test gpio open Set pins to input gpio read GPIO pin: 24 Logic level: 1