Raspberry PIのGPIOのデバイスドライバを作成します。「bcm2835 ライブラリによるスイッチ入力とLEDの点滅 」で使用したLEDを点灯させます。
GPIOデバイスドライバ
GPIOポートに接続されたLEDを点灯するため、「Raspberry PIのGPIOのデバイスドライバ – Open 」で作成したデバイスドライのファイル操作構造体「file_operations」に、GPIOの書き込みデバイスドライバ関数「raspi_gpio_write」のアドレスと、GPIOの書き込みデバイスドライバ関数「raspi_gpio_write」を追加します。
デバイスのマイナー番号をGPIOポート番号とする設計ですが、今回は強制的にLEDを点灯させるため、GPIOポート「25」とし、 raspi_gpio_write関数の17行目に「gpio = 25;」を挿入しました。
raspi_gpio_write関数で使用しているgpio_direction_output関数とgpio_set_value関数について次に示します。
- gpio_direction_output
- 入出力制御を出力側にする
- gpio_set_value
- パラメータで指定されたGPIO番号に対して指定された値を出力する
/* File operation structure */ static struct file_operations raspi_gpio_fops = { .owner = THIS_MODULE, .open = raspi_gpio_open, .write = raspi_gpio_write, }; static ssize_t raspi_gpio_write ( struct file *filp, const char *buf, size_t count, loff_t *f_pos) { unsigned int gpio, len = 0, value = 0; char kbuf[BUF_SIZE]; struct raspi_gpio_dev *raspi_gpio_devp = filp->private_data; unsigned long flags; // gpio = iminor(filp->f_path.dentry->d_inode); gpio = 25; len = count < BUF_SIZE ? count-1 : BUF_SIZE-1; if(copy_from_user(kbuf, buf, len) != 0) return -EFAULT; kbuf[len] = '\0'; printk(KERN_INFO "Request from user: %s\n", kbuf); // Check the content of kbuf and set GPIO pin accordingly if (strcmp(kbuf, "out") == 0) { printk(KERN_ALERT "gpio[%d] direction set to ouput\n", gpio); if (raspi_gpio_devp->dir != out) { spin_lock_irqsave(&raspi_gpio_devp->lock, flags); gpio_direction_output(gpio, low); raspi_gpio_devp->dir = out; raspi_gpio_devp->state = low; spin_unlock_irqrestore(&raspi_gpio_devp->lock, flags); } } else if ((strcmp(kbuf, "1") == 0) || (strcmp(kbuf, "0") == 0)) { sscanf(kbuf, "%d", &value); if (raspi_gpio_devp->dir == in) { printk("Cannot set GPIO %d, direction: input\n", gpio); return -EPERM; } if (raspi_gpio_devp->dir == out) { if (value > 0) { spin_lock_irqsave(&raspi_gpio_devp->lock, flags); gpio_set_value(gpio, high); raspi_gpio_devp->state = high; spin_unlock_irqrestore(&raspi_gpio_devp->lock, flags); } else { spin_lock_irqsave(&raspi_gpio_devp->lock, flags); gpio_set_value(gpio, low); raspi_gpio_devp->state = low; spin_unlock_irqrestore(&raspi_gpio_devp->lock, flags); } } } else { printk(KERN_ERR "Invalid value\n"); return -EINVAL; } *f_pos += count; return count; }
ユーザープログラム
ユーザプログラムではWrite関数は2回呼び出します。最初にGPIOに出力してLEDを制御するため、Write関数で”out”を書き込みます。次に、LEDの点灯/消灯を指示します。点灯するか消灯するかは、ユーザープログラムの実行時のパラメータに従います。「1」の場合LEDの点灯、「0」の時LEDの消灯とし、Write関数で文字列のパラメータで与えます。
/* * Name : output_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 4 #define PATH_SIZE 20 int main(int argc, char **argv) { int i = 0, index = 0, value; int fd; char path[PATH_SIZE]; char buf[BUF_SIZE]; if (argc != 2) { printf("Option low/high must be used\n"); exit(EXIT_FAILURE); } // Open all GPIO pins snprintf(path, sizeof(path), "/dev/raspiGpio0"); fd = open(path, O_WRONLY); if (fd < 0) { perror("Error opening GPIO"); exit(EXIT_FAILURE); } // Set direction of GPIO pins to output printf("Set GPIO pins to output, logic level :%s\n", argv[1]); strncpy(buf, "out", 3); buf[3] = '\0'; if (write(fd, buf, sizeof(buf)) < 0) { perror("write, set pin output"); exit(EXIT_FAILURE); } // Set logic state of GPIO pins low/high value = atoi(argv[1]); if (value == 1) { strncpy(buf, "1", 1); buf[1] = '\0'; } else if (value == 0) { strncpy(buf, "0", 1); buf[1] = '\0'; } else { printf("Invalid logic value\n"); exit(EXIT_FAILURE); } if (write(fd, buf, sizeof(buf)) < 0) { perror("write, set GPIO state of GPIO pins"); exit(EXIT_FAILURE); } return EXIT_SUCCESS; }
実行したデバイスドライバのログを次に示します。
# dmesg ・ ・ ・ [ 1204.497443] start gpio_init [ 1204.502487] RaspberryPi GPIO driver initialized [ 1625.097917] GPIOstart open [ 1625.097958] GPIO[0] opened [ 1625.099254] Request from user: out [ 1625.099559] gpio[25] direction set to ouput [ 1625.112248] Request from user: 1
デバイスドライバのraspi_gpio_write関数により、”[ 1625.099559] gpio[25] direction set to ouput”がログされており、GPIOポート25に出力されていいることが確認できます。
実行時のパラメータを次のように与えるとLEDが点灯します。
# ./output_test 1
実行時のパラメータを次のように与えるとLEDが消灯します。
# ./output_test 0