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