前言
网上关于NanoPi-K2这块板子的资料少之又少,多方收集资料加试验后,终于摸索出来了通过内核函数控制板子的GPIO的方法,由于本人纯萌新,错漏之处还望海涵~~ 参考文章:三种方式控制NanoPi2的GPIO
定位GPIO位号
函数介绍
首先介绍一下主要用到的内核函数:
gpio_request(unsigned gpio, const char *label);
gpio_direction_output(unsigned gpio,int value);
gpio_set_value(unsigned int gpio, int value);
板子管脚定义
函数我们知道了,关键是如何确定gpio的值呢,直接写GPIOY0?,那是不行的,先来看看开发板的管脚定义: 管脚分布及对应开发板上的位置如图所示
确定管脚位号
本例程中,我使用GPIOY0来演示如何控制LED灯闪烁
1.进入开发板终端,输入:
fa@NanoPi-K2:~$
fa@NanoPi-K2:~$ su
Password:
root@NanoPi-K2:/home/fa#
在root下运行
2.输入下面指令定位到GPIO所在的文件
root@NanoPi-K2:/home/fa# cd /sys/class/gpio
root@NanoPi-K2:/sys/class/gpio# ls
export gpiochip122 gpiochip136 unexport
这里可以看到gpio分了两个块gpiochip122和gpiochip136,但这样还是没有办法明白怎么控制GPIOY0啊,还有其他管脚也不清楚。作为一个萌新,我猜设备树中可能有相关代码。 先从
http://wiki.friendlyarm.com/wiki/index.php/NanoPi_K2/zh#
官方第5.3.1章节中下载内核源码到本地,根据主控的名称厂家找到设备树所在的文件路径:
linux-nanopi-k2-3.14.y\arch\arm64\boot\dts\amlogic\nanopi-k2.dts
打开后观察引用的头文件有这么几行:
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/gxbb.h>
#include <dt-bindings/gpio/gxbb.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/reset/aml_gxbb.h>
#include "mesongxbb.dtsi"
注意gpio关键字,在内核源码中找到头文件,路径如下:
linux-nanopi-k2-3.14.y\include\dt-bindings\gpio\
打开路径下的 gxbb.h头文件:
#ifndef __ARCH_GXBB_GPIO_H__
#define __ARCH_GXBB_GPIO_H__
#define GPIOAO_0 0
#define GPIOAO_1 1
#define GPIOAO_2 2
#define GPIOAO_3 3
#define GPIOAO_4 4
#define GPIOAO_5 5
#define GPIOAO_6 6
#define GPIOAO_7 7
#define GPIOAO_8 8
#define GPIOAO_9 9
#define GPIOAO_10 10
#define GPIOAO_11 11
#define GPIOAO_12 12
#define GPIOAO_13 13
#define GPIOZ_0 0
#define GPIOZ_1 1
#define GPIOZ_2 2
#define GPIOZ_3 3
#define GPIOZ_4 4
#define GPIOZ_5 5
#define GPIOZ_6 6
#define GPIOZ_7 7
#define GPIOZ_8 8
#define GPIOZ_9 9
#define GPIOZ_10 10
#define GPIOZ_11 11
#define GPIOZ_12 12
#define GPIOZ_13 13
#define GPIOZ_14 14
#define GPIOZ_15 15
#define GPIOH_0 16
#define GPIOH_1 17
#define GPIOH_2 18
#define GPIOH_3 19
#define BOOT_0 20
#define BOOT_1 21
#define BOOT_2 22
#define BOOT_3 23
#define BOOT_4 24
#define BOOT_5 25
#define BOOT_6 26
#define BOOT_7 27
#define BOOT_8 28
#define BOOT_9 29
#define BOOT_10 30
#define BOOT_11 31
#define BOOT_12 32
#define BOOT_13 33
#define BOOT_14 34
#define BOOT_15 35
#define BOOT_16 36
#define BOOT_17 37
#define CARD_0 38
#define CARD_1 39
#define CARD_2 40
#define CARD_3 41
#define CARD_4 42
#define CARD_5 43
#define CARD_6 44
#define GPIODV_0 45
#define GPIODV_1 46
#define GPIODV_2 47
#define GPIODV_3 48
#define GPIODV_4 49
#define GPIODV_5 50
#define GPIODV_6 51
#define GPIODV_7 52
#define GPIODV_8 53
#define GPIODV_9 54
#define GPIODV_10 55
#define GPIODV_11 56
#define GPIODV_12 57
#define GPIODV_13 58
#define GPIODV_14 59
#define GPIODV_15 60
#define GPIODV_16 61
#define GPIODV_17 62
#define GPIODV_18 63
#define GPIODV_19 64
#define GPIODV_20 65
#define GPIODV_21 66
#define GPIODV_22 67
#define GPIODV_23 68
#define GPIODV_24 69
#define GPIODV_25 70
#define GPIODV_26 71
#define GPIODV_27 72
#define GPIODV_28 73
#define GPIODV_29 74
#define GPIOY_0 75
#define GPIOY_1 76
#define GPIOY_2 77
#define GPIOY_3 78
#define GPIOY_4 79
#define GPIOY_5 80
#define GPIOY_6 81
#define GPIOY_7 82
#define GPIOY_8 83
#define GPIOY_9 84
#define GPIOY_10 85
#define GPIOY_11 86
#define GPIOY_12 87
#define GPIOY_13 88
#define GPIOY_14 89
#define GPIOY_15 90
#define GPIOY_16 91
#define GPIOX_0 92
#define GPIOX_1 93
#define GPIOX_2 94
#define GPIOX_3 95
#define GPIOX_4 96
#define GPIOX_5 97
#define GPIOX_6 98
#define GPIOX_7 99
#define GPIOX_8 100
#define GPIOX_9 101
#define GPIOX_10 102
#define GPIOX_11 103
#define GPIOX_12 104
#define GPIOX_13 105
#define GPIOX_14 106
#define GPIOX_15 107
#define GPIOX_16 108
#define GPIOX_17 109
#define GPIOX_18 110
#define GPIOX_19 111
#define GPIOX_20 112
#define GPIOX_21 113
#define GPIOX_22 114
#define GPIOCLK_0 115
#define GPIOCLK_1 116
#define GPIOCLK_2 117
#define GPIOCLK_3 118
#define GPIO_TEST_N 119
#define AO 0x10
#define AO2 0x11
#endif
可以看到分为两个块AO Bank和EE Bank 经过实验可以试出AO Bank起始地址为gpiochip122 EE Bank起始地址为gpiochip136 验证方法如下: 将GPIOY_0通过杜邦线连接到LED正极,LED负极连接到开发板GND管脚(6、14、20、30、34都可以) 记下头文件中GPIOY_0的偏移量为75 因此实际地址为 EE Bank基地址加上偏移量75 136+75=211 回到终端,输入:
root@NanoPi-K2:/sys/class/gpio# echo 211 > /sys/class/gpio/export
root@NanoPi-K2:/sys/class/gpio# ls
export gpio211 gpiochip122 gpiochip136 unexport
可以看到导出了一个引脚gpio211 接下来进入该GPIO并设置GPIO方向:
root@NanoPi-K2:/sys/class/gpio# cd gpio211
root@NanoPi-K2:/sys/class/gpio/gpio211# echo out > direction
将管脚设置为输出 然后可以操控该管脚的电平了,输出高电平点亮LED:
root@NanoPi-K2:/sys/class/gpio/gpio211# echo 1 > /sys/class/gpio/gpio211/value
输出低电平关闭LED:
root@NanoPi-K2:/sys/class/gpio/gpio211# echo 0 > /sys/class/gpio/gpio211/value
测试结束,管脚位置确定完毕,不放心的话还有那么多GPIOY可以尝试,这里就不做测试了。 之后记得清除导出的管脚,输入:
root@NanoPi-K2:/sys/class/gpio/gpio211# echo 211 > /sys/class/gpio/unexport
然后就是代码中该如何控制GPIO了
编写及编译 .KO 驱动文件
开发环境搭建
要编译驱动文件,需要相应的编译环境及内源码支持,参考
http://wiki.friendlyarm.com/wiki/index.php/NanoPi_K2/zh# 第5.1章节安装AArch64交叉编译器小节 第5.3.1章节编译Ubuntu内核小节
注意以上操作均要在64位Linux系统下进行,git拉取不方便的话可以下载K2板子分支的ZIP文件,不要在Windows环境下解压,可能导致大小写命名的文件合并导致内核文件缺损,发送到linux系统中再进行解压及后续操作。 环境搭建完成后即可进行驱动编写。
驱动编写
新建一个文件,命名为ledTest.c 代码如下:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/compat.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#define OUTPUT 1
#define INPUT 0
#define HIGH 1
#define LOW 0
#define DEVICE_NAME "LED"
#define SET_VALUE 1
#define GPIOY_BASE 136
unsigned int GPIOY0 = GPIOY_BASE+75;
static int gpio_open(struct inode *inode,struct file *file)
{
gpio_request(GPIOY0,"test");
gpio_direction_output(GPIOY0, 0);
printk("Open:gpio_set_value LOW\n");
gpio_set_value(GPIOY0, LOW);
printk("request GPIOY0\n");
return 0;
}
static int gpio_close(struct inode *inode,struct file *file)
{
printk("close:gpio_set_value LOW\n");
gpio_set_value(GPIOY0, LOW);
gpio_free(GPIOY0);
return 0;
}
static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
if(cmd == SET_VALUE)
{
if(arg == HIGH)
{
gpio_set_value(GPIOY0,HIGH);
printk("gpio_set_value HIGH\n");
}
else if(arg == LOW)
{
gpio_set_value(GPIOY0,LOW);
printk("gpio_set_value LOW\n");
}
}
return -EMSGSIZE;
}
static struct file_operations gpio_fops =
{
.owner = THIS_MODULE,
.open = gpio_open,
.release = gpio_close,
.unlocked_ioctl = gpio_ioctl,
};
static struct miscdevice gpio_dev =
{
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = & gpio_fops,
};
volatile unsigned * GPIOYOUT;
static int gpio_init(void)
{
int ret = 0;
printk("init\n");
ret = misc_register(&gpio_dev);
return ret;
}
static void gpio_exit(void)
{
misc_deregister(&gpio_dev);
printk("exit\n");
}
module_init(gpio_init);
module_exit(gpio_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("YQY");
接下来保存并开始编写Makefile
obj-m:=ledTest.o
mymodule-objs:=ledTest
KDIR:=/home/yan/linux/NanoPi/Kernal/linux-nanopi-k2-3.14.y
MAKE:=make
# EXTRA_CFLAGS += -I$(KDIR)arch/arm/mach-s5p4418/prototype/module
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean
第三行的地址填你自己保存的编译后的内核所在的地址 保存后,在该文件夹下编译驱动即可:
yan@yan-virtual-machine:~/linux/NanoPi/TestMod/led$ make
make -C /home/yan/linux/NanoPi/Kernal/linux-nanopi-k2-3.14.y M=/home/yan/linux/NanoPi/TestMod/led modules
make[1]: Entering directory '/home/yan/linux/NanoPi/Kernal/linux-nanopi-k2-3.14.y'
Building modules, stage 2.
MODPOST 1 modules
make[1]: Leaving directory '/home/yan/linux/NanoPi/Kernal/linux-nanopi-k2-3.14.y'
该目录下生成了驱动文件ledTest.ko
驱动加载
将其拷贝到开发板中即可,文件夹自己定,记得给文件赋予读写权限,简单粗暴就
root@NanoPi-K2:/home/fa/dri# chmod 777 ledTest.ko
下面加载驱动,输入:
root@NanoPi-K2:/home/fa/dri# insmod ledTest.ko
检查 /dev/ 目录下,会发现多出一个名称为 LED 的文件,驱动挂载成功
编写及编译APP文件
新建 ledApp.c 文件,源码如下:
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define HIGH 1
#define LOW 0
#define SET_VALUE 1
int main()
{
int fd = open("/dev/LED",O_RDWR);
if(fd <0)
{
printf("File open filed!\r\n");
}
int i;
for(i=0;i<3;i++)
{
ioctl(fd,SET_VALUE,HIGH);
usleep(100000);
ioctl(fd,SET_VALUE,LOW);
usleep(100000);
}
close(fd);
return 0;
}
保存后编译文件:
yan@yan-virtual-machine:~/linux/NanoPi/TestMod/led.c$ aarch64-linux-gnu-gcc -o ledApp ledApp.c
文件夹下会多出一个ledApp文件,这就是需要的应用文件,拷贝到开发板中,并赋予读写权限:
root@NanoPi-K2:/home/fa# chmod 777 ledApp
运行程序:
root@NanoPi-K2:/home/fa# ./ledApp
即可看到KED快闪3下
第一次写博客,希望各位看官满意哦~~ (^ ^)
|