NanoPi 2ベースLinux 3.4コアGPIO駆動
ハードウェア環境
開発ボード:nanopi 2(cpu:A 9 s 5 p 4418)
ソフトウェア環境
カーネルバージョン:linux 3.4.39クロスコンパイラ:arm-linux-gcc version 4.9.3(ctng-1.21.0-229 g-FA)64ビットシステムバージョン
Linux3.4コアGPIO駆動説明
Kernel 2.6.32バージョン以上では、gpioポート管理のライブラリファイル/kernel/drivers/gpio/gpiolibが提供されています.c.
下層チップの具体的な実現
ドライバソース
カーネル構成メニューを変更し、現在の駆動構成を追加します.
カーネル構成リファレンス
カーネルモジュールコンパイル
カーネルモジュールが問題をロードできない
insmodロードで次の問題が発生しました.
エラーメッセージを表示すると、version magicドライバは開発ボードカーネルと一致しません.
カーネルバージョン情報を変更し、-s 5 p 4418をカーネルのFriendlyARMに変更します.
テストプログラムソース
開発ボード:nanopi 2(cpu:A 9 s 5 p 4418)
ソフトウェア環境
カーネルバージョン:linux 3.4.39クロスコンパイラ:arm-linux-gcc version 4.9.3(ctng-1.21.0-229 g-FA)64ビットシステムバージョン
Linux3.4コアGPIO駆動説明
Kernel 2.6.32バージョン以上では、gpioポート管理のライブラリファイル/kernel/drivers/gpio/gpiolibが提供されています.c.
:
1.int gpio_request(unsigned gpio, const char *label)
pin gpio , * label, bit 。
2.void gpio_free(unsigned gpio)
gpio
3.int gpio_direction_input(unsigned gpio)
gpio
4.int gpio_direction_output(unsigned gpio, int value)
gpio value 0 /1
5.void __gpio_set_value(unsigned gpio, int value)
gpio
6.int __gpio_get_value(unsigned gpio)
gpio
下層チップの具体的な実現
drivers/gpio gpiolib GPIO , GPIO gpio_chip , SoC gpio_chip , gpiochip_add() gpio_chip。
ドライバソース
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <mach/platform.h>
#include <mach/devices.h>
#define DEVICE_NAME "4418_relay"
//nanopi2 4418
unsigned int J1_GPIO = PAD_GPIO_C + 11;// GPIO
unsigned int J2_GPIO = PAD_GPIO_C + 12;// GPIO
#define J1_OFF 0x00
#define J1_ON 0x01
#define J2_OFF 0x10
#define J2_ON 0x11
char drv_buf[2];
static int update_relay(void)
{
switch(drv_buf[0]) {
case J1_ON:
gpio_set_value(J1_GPIO, 0); //
return 0;
case J1_OFF:
gpio_set_value(J1_GPIO, 1); //
return 0;
case J2_ON:
gpio_set_value(J2_GPIO, 0); //
return 0;
case J2_OFF:
gpio_set_value(J2_GPIO, 1); //
return 0;
default:
return -EINVAL;
}
}
static int relay_write(struct file *file, const char * buffer, size_t count, loff_t * ppos)
{
unsigned long err;
err = copy_from_user(drv_buf, buffer, 1);
update_relay();
return 1;
}
static struct file_operations dev_fops={
write:relay_write,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init my_relay_init(void)
{
int ret;
gpio_direction_output(J1_GPIO, 1);//
gpio_direction_output(J2_GPIO, 1);//
ret = misc_register(&misc);
printk (DEVICE_NAME"\t#NanoPi2 J1 J2 initialized
");
return ret;
}
static void __exit my_relay_exit(void)
{
misc_deregister(&misc);
}
module_init(my_relay_init);
module_exit(my_relay_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("TONY");
MODULE_DESCRIPTION("91arm.com Relay Driver");
カーネル構成メニューを変更し、現在の駆動構成を追加します.
カーネル構成リファレンス
カーネルモジュールコンパイル
make CROSS_COMPILE=arm-linux- modules
カーネルモジュールが問題をロードできない
insmodロードで次の問題が発生しました.
root@nanopi2:/home/fa# insmod 4418_relay.ko
insmod: ERROR: could not insert module 4418_relay.ko: Invalid module format
エラーメッセージを表示すると、version magicドライバは開発ボードカーネルと一致しません.
root@nanopi2:/home/fa# dmesg |tail
[ 2589.164000] 4418_relay: version magic '3.4.39-s5p4418 SMP preempt mod_unload ARMv7 p2v8 ' should be '3.4.39-FriendlyARM SMP preempt mod_unload ARMv7 p2v8 '
カーネルバージョン情報を変更し、-s 5 p 4418をカーネルのFriendlyARMに変更します.
テストプログラムソース
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#define DEV_FILE "/dev/4418_relay"
#define J1_OFF 0x00
#define J1_ON 0x01
#define J2_OFF 0x10
#define J2_ON 0x11
int main()
{
int fd_dev=-1;
char dat[2];
int cmd;
printf("nanoPi driver Test
");
fd_dev = open(DEV_FILE,O_RDWR);
if(fd_dev<0){
printf("open device err
");
return 0;
}
while(1){
printf("1:J1 OFF 2:J1 ON 3:J2 OFF 4:J2 ON
");
printf("Please input:");
scanf("%d",&cmd);
switch(cmd){
case 1:
dat[0] = J1_OFF;
break;
case 2:
dat[0] = J1_ON;
break;
case 3:
dat[0] = J2_OFF;
break;
case 4:
dat[0] = J2_ON;
break;
default:
break;
}
write(fd_dev,dat,1);
}
return 0;
}