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
1 2 3 4 5 6 7 | /* 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
1 2 3 4 5 6 7 8 9 10 11 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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」と表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | /* * 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