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