系统平台:
芯片平台:Freescale i.MX6Q/6DL
OS版本:Android 7.1.2(Linux 4.9.17)
一、内核中使用GPIO
- 修改内核,dtsi中导出GPIO,以下导出了两个GPIO,GPIO3_IO29, GPIO07_IO04。
- 在内核代码中添加linux/gpio.h头文件,导入GPIO相关操作方法。
- 使用GPIO相关操作方法,设置GPIO方法,触发方法,设置相关值等。
以下在last.c中测试将GPIO设置成输出模式,并拉高电平。
From 3aa4328884f1bed27f566352ae2e299bd0834561 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E4=BD=95=E5=AE=9D=E8=99=8E?= <[email protected]>
Date: Fri, 6 Jul 2018 13:27:22 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0GPIO=E5=BC=95=E8=84=9A?=
=?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 4 +++-
sound/last.c | 14 ++++++++++++++
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index f8cbc25..c6b848f 100755
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -816,6 +816,8 @@ tsc@24 {
MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x80000000
MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0
MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x13059
+ MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x80000000
+ MX6QDL_PAD_SD3_DAT0__GPIO7_IO04 0x80000000
MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x13069
MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x13069
MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0
@@ -887,7 +889,7 @@ tsc@24 {
pinctrl_gpio_keys: gpio_keysgrp {
fsl,pins = <
- MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b0
+ /*MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b0*/
/*MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0*/
MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x1b0b0
>;
diff --git a/sound/last.c b/sound/last.c
index 43f2228..52f4f21 100644
--- a/sound/last.c
+++ b/sound/last.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <sound/core.h>
+#include <linux/gpio.h>
static int __init alsa_sound_last_init(void)
{
@@ -34,6 +35,19 @@ static int __init alsa_sound_last_init(void)
}
if (ok == 0)
printk(KERN_INFO " No soundcards found.\n");
+#if 1
+ int ret = 0;
+ ret = gpio_request(93, NULL);
+ if(!ret)
+ ret = gpio_direction_output(93, 0);
+ if(unlikely(ret))
+ {
+ printk("gpio(93) direction output fail\n\n\n");
+ gpio_free(93);
+ return 0;
+ }
+ printk("gpio_direction_output 93 OK\n\n\n");
+#endif
return 0;
}
--
1.9.1
以上代码运行时,实际测量GPIO93电平被拉低。
二、在文件系统中控制GPIO
linux内核提供了一套在用户态配置GPIO的接口,在/sys/class/gpio/目录下:
可以发现其中包含有两个文件export、unexport和若干gpiochipN 类型文件夹
- export:
用于将指定编号的引脚导出,作为GPIO使用 - unexport:
用于将导出的GPIO删除掉 - gpiochipN:
当前芯片中包含的GPIO控制器 - direction:
设置输出还是输入模式
- 设置为输入:echo “in” > direction
- 设置为输出:echo “out” > direction
- value
输出时,控制高低电平;输入时,获取高低电平
- 高电平:echo 1 > value
- 低电平:echo 0 > value
- edge
控制中断触发模式,引脚被配置为中断后可以使用poll()函数监听引脚
- 非中断引脚: echo “none” > edge
- 上升沿触发:echo “rising” > edge
- 下降沿触发:echo “falling” > edge
- 边沿触发:echo “both” > edge
- gpiochipN目录
用来管理和控制一组gpio端口的控制器
- base
和N相同,表示控制器管理的最小的端口编号。 - lable
诊断使用的标志(并不总是唯一的) - ngpio
控制器管理的gpio端口数量(端口范围是:N ~ N+ngpio-1)
- base
使用方法示例
- 添加设备接口GPIO196
echo 196 > export
可以发现,目录下出现了GPIO196,如果执行命令后没有反应,表示当前的GPIO已经用作其他的功能,例如作为IIC的引脚等。
另外在测试中发现,如上面内核中所示,我们在使用中使用了93脚,此时我们echo 93 > export无法将93脚正常导出。 - 设置GPIO196为输出
echo out > gpio196/direction - 删除当前导出的GPIO196
echo 196 > unexport
三、应用程序中操作GPIO
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include "gpio_control.h"
#define BUFFER_MAX 100
#define DIRECTION_MAX 100
#define IN 0
#define OUT 1
#define LOW 0
#define HIGH 1
#define POUT 196
int gpio_export(int pin);
int gpio_unexport(int pin);
int gpio_direction(int pin, int dir);
int gpio_write(int pin, int value);
int gpio_read(int pin);
int main(int argc, char *argv[)
{
int i = 0;
gpio_export(POUT);
gpio_direction(POUT, OUT);
gpio_write(POUT, 1);
for (i = 0; i < 20; i++) {
gpio_write(POUT, i % 2);
usleep(500 * 1000);
}
gpio_unexport(POUT);
return 0;
}
int gpio_export(int pin)
{
char buffer[BUFFER_MAX];
int len;
int fd;
fd = open("/sys/class/gpio/export", O_WRONLY);
if (fd < 0) {
fprintf(stderr, "Failed to open export for writing!\n");
return(-1);
}
len = snprintf(buffer, BUFFER_MAX, "%d", pin);
if (write(fd, buffer, len) < 0) {
fprintf(stderr, "Fail to export gpio!");
return -1;
}
close(fd);
return 0;
}
int gpio_unexport(int pin)
{
char buffer[BUFFER_MAX];
int len;
int fd;
fd = open("/sys/class/gpio/unexport", O_WRONLY);
if (fd < 0) {
fprintf(stderr, "Failed to open unexport for writing!\n");
return -1;
}
len = snprintf(buffer, BUFFER_MAX, "%d", pin);
if (write(fd, buffer, len) < 0) {
fprintf(stderr, "Fail to unexport gpio!");
return -1;
}
close(fd);
return 0;
}
int gpio_direction(int pin, int dir)
{
static const char dir_str[] = "in\0out";
char path[DIRECTION_MAX];
int fd;
snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", pin);
fd = open(path, O_WRONLY);
if (fd < 0) {
fprintf(stderr, "failed to open gpio direction for writing!\n");
return -1;
}
if (write(fd, &dir_str[dir == IN ? 0 : 3], dir == IN ? 2 : 3) < 0) {
fprintf(stderr, "failed to set direction!\n");
return -1;
}
close(fd);
return 0;
}
int gpio_write(int pin, int value)
{
static const char values_str[] = "01";
char path[DIRECTION_MAX];
int fd;
snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", pin);
fd = open(path, O_WRONLY);
if (fd < 0) {
fprintf(stderr, "failed to open gpio value for writing!\n");
return -1;
}
if (write(fd, &values_str[value == LOW ? 0 : 1], 1) < 0) {
fprintf(stderr, "failed to write value!\n");
return -1;
}
close(fd);
return 0;
}
int gpio_read(int pin)
{
char path[DIRECTION_MAX];
char value_str[3];
int fd;
snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", pin);
fd = open(path, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "failed to open gpio value for reading!\n");
return -1;
}
if (read(fd, value_str, 3) < 0) {
fprintf(stderr, "failed to read value!\n");
return -1;
}
close(fd);
return (atoi(value_str));
}
以上可实现规律的拉高拉低GPIO196引脚