/*****************************************************************
* gpio irq
*
* 一直以来都没了解过gpio的irq,如何使用,今天正好了解下。
*  本文从内核和应用层分析gpio的irq,并写验证程序。
*
* 本文部分程序内容源自以下链接,并自己更改进行验证。验证平台freescal imx6.
* http://blog.ittraining.com.tw/2015/05/raspberry-pi-b-pi2-linux-gpio-button.html
* http://m.blog.csdn.net/article/details?id=51187244
* http://blog.csdn.net/gqb_driver/article/details/8620809
* 参考文档:
* kernel/Documentation/gpio.txt
*
* Tony Liu, 2016-5-26, Shenzhen
*****************************************************************/
1.内核中验证
1.1 程序 #include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/interrupt.h> #define LED IMX_GPIO_NR(2, 3)
#define BUTTON IMX_GPIO_NR(3, 23)
#define INT_NAME "BUTTON_INT"
#define DEV_NAME "INTERRUPT" unsigned short int button_irq = 0;
static unsigned long flags = 0;
static int led_trigger = 0; static irqreturn_t button_isr(int irq, void *data)
{
/* 使cpu不接受其他中断 */
local_irq_save(flags);
printk("button_isr !!!!\n");
gpio_set_value(LED, led_trigger);
led_trigger = led_trigger ? (0):(1);
local_irq_restore(flags);
return IRQ_HANDLED;
} int __init gpio_irq_init(void)
{
int ret;
ret = gpio_request(LED, "led");
if (ret) {
printk("get led FAILED!\n");
return ret;
}
gpio_direction_output(LED, 0);
ret = gpio_request(BUTTON, "button");
if (ret) {
printk("get button FAILED!\n");
return ret;
}
button_irq = gpio_to_irq(BUTTON);
if (button_irq < 0) {
printk("gpio_to_irq FAILED!\n");
return -1;
}
printk("irq:%d\n", button_irq);
ret = request_irq(button_irq, button_isr, IRQF_TRIGGER_RISING, INT_NAME, DEV_NAME);
if (ret < 0)
return -1; return ret;
} void __exit gpio_irq_exit(void)
{
gpio_free(LED);
gpio_free(BUTTON);
//需要释放申请的中断,否这下次不能使用,并且id要是申请使跳得内容相同,否则会出错。
free_irq(button_irq, DEV_NAME);
} module_init(gpio_irq_init);
module_exit(gpio_irq_exit); MODULE_LICENSE("GPL"); 1.2 分析
/*
irq:gpio_to_irq获得的中断号
handler: 中断处理函数
*devname: 会在/proc/intertupt中显示
*dev_id: request和free的时候必须相同,否则会出错。可以为NULL
*/
int request_irq(unsigned int irq,
irq_handler_t handler,
unsigned long flags, const char *devname, void *dev_id) //文件系统中查看缩写的dev_id,开头的343是中断号
root@freescale ~$ cat /proc/interrupts
CPU0 CPU1
......
343: 0 0 GPIO BUTTON_INT 2.应用层验证
2.1 验证代码(poll函数) #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h> int main(int argc, char *argv[])
{
int fd, ret;
char value;
struct pollfd pfd;
//打开gpio87,对应imx6的IMX_GPIO_NR(3, 23),我连接了一个按键
system("echo \"87\" > /sys/class/gpio/export");
/*
* none 表示引脚为输入,不是中断引脚
* rising 表示引脚为中断输入,上升沿触发
* falling 表示引脚为中断输入,下降沿触发
* both 表示引脚为中断输入,边沿触发
*/
system("echo \"both\" > /sys/class/gpio/gpio87/edge"); fd = open("/sys/class/gpio/gpio87/value", O_RDWR);
if (fd < 0) {
printf("open file fail\n");
return -1;
}
/* poll要监听的文件描述符号 */
pfd.fd = fd;
/* 监听的文件的事件类型,当配置为中断'edge‘的时候.events必须设置为POLLPRI
   * 详情查看内核中的文档gpio.txt */
pfd.events = POLLPRI | POLLERR;
/* 由于value文件中本来就有数据需要读取,没有读取的话,会被当成一个中断而进行处理 */
//到文件开头读取
ret = lseek(fd, 0, SEEK_SET);
if (ret == -1) {
printf("lseek error\n");
return -1;
}
//读取1字节
ret = read(fd, &value, 1); while (1) {
/* 监听个数1, 等待时间无限 */
ret = poll(&pfd, 1, -1);
if (ret == -1) {
printf("poll error\n");
return -1;
}
/* 监听的时间会保存在revents成员中 */
if (pfd.revents & POLLPRI) {
//文件指针只想文件的开头
ret = lseek(fd, 0, SEEK_SET);
if (ret == -1) {
printf("lseek error\n");
return -1;
}
//读取,结果为字符'0'或者‘1’
read(fd, &value, 1);
printf("value:%c\n", value);
}
if (pfd.revents & POLLERR) {
printf("poll error\n");
}
} close(fd); return 0;
} 2.1 验证代码(select函数) #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h> int main(int argc, char *argv[])
{
int fd[2], ret;
int maxfd;
char value;
fd_set readfd;
fd_set exceptfd;
//打开gpio87,对应imx6的IMX_GPIO_NR(3, 23),我连接了一个按键
system("echo 87 > /sys/class/gpio/export");
//打开gpio94,对应imx6的IMX_GPIO_NR(3, 30),我连接了一个按键
system("echo 94 > /sys/class/gpio/export"); system("echo in > /sys/class/gpio/gpio94/direction");
system("echo in > /sys/class/gpio/gpio87/direction");
/*
* none 表示引脚为输入,不是中断引脚
* rising 表示引脚为中断输入,上升沿触发
* falling 表示引脚为中断输入,下降沿触发
* both 表示引脚为中断输入,边沿触发
*/
system("echo falling > /sys/class/gpio/gpio87/edge");
system("echo falling > /sys/class/gpio/gpio94/edge"); fd[0] = open("/sys/class/gpio/gpio87/value", O_RDWR);
if (fd < 0) {
printf("open file fail\n");
return -1;
} fd[1] = open("/sys/class/gpio/gpio94/value", O_RDWR);
if (fd < 0) {
printf("open file fail\n");
return -1;
} /* 由于value文件中本来就有数据需要读取,没有读取的话,会被当成一个中断而进行处理 */
//到文件开头读取
ret = lseek(fd[0], 0, SEEK_SET);
if (ret == -1) {
printf("lseek error\n");
return -1;
}
//读取1字节
ret = read(fd[0], &value, 1); ret = lseek(fd[1], 0, SEEK_SET);
if (ret == -1) {
printf("lseek error\n");
return -1;
}
//读取1字节
ret = read(fd[1], &value, 1); while (1) {
FD_ZERO(&exceptfd);
FD_SET(fd[0], &exceptfd);
FD_SET(fd[1], &exceptfd);
maxfd = (fd[0] > fd[1] ? fd[0] : fd[1]);
//使用select获取中断,必须将fd放在exceptfd的位置
ret = select(maxfd +1, NULL, NULL, &exceptfd, NULL);
if (ret == -1) {
printf("select operation fail\n");
return ret;
}
if (FD_ISSET(fd[0], &exceptfd)) {
ret = lseek(fd[0], 0, SEEK_SET);
if (ret == -1) {
printf("lseek error\n");
return -1;
}
read(fd[0], &value, 1);
printf("0: value:%c\n", value);
}
if (FD_ISSET(fd[1], &exceptfd)) {
ret = lseek(fd[1], 0, SEEK_SET);
if (ret == -1) {
printf("lseek error\n");
return -1;
} read(fd[1], &value, 1); printf("1: value:%c\n", value); }
}
//关闭文件描述符
close(fd[0]);
close(fd[1]); //操作完毕,释放gpio
system("echo 87 > /sys/class/gpio/unexport");
system("echo 94 > /sys/class/gpio/unexport"); return 0;
} 2.1分析
<1>申请gpio, gpio_request
echo "87" > /sys/class/gpio/export
会在/sys/class/gpio目录下边生成一个gpio87的目录 <2>释放gpio, gpio_free
echo "87" > /sys/class/gpio/unexport <3>申请之后,gpio87目录的内容如下:
root@freescale /sys/class/gpio/gpio87$ ls -l
-rw-r--r-- 1 root root 4096 Jan 1 00:33 active_low
-rw-r--r-- 1 root root 4096 Jan 1 00:33 direction
-rw-r--r-- 1 root root 4096 Jan 1 00:15 edge
drwxr-xr-x 2 root root 0 Jan 1 00:33 power
lrwxrwxrwx 1 root root 0 Jan 1 00:33 subsystem -> ../../../../class/gpio
-rw-r--r-- 1 root root 4096 Jan 1 00:33 uevent
-rw-r--r-- 1 root root 4096 Jan 1 00:15 value
<4>设置输入输出
echo "in" > direction
echo "out" > direction
<5>设置输出值
echo "1" > value //非0值都会当作1
echo "0" > value 详细参考内核的文档:
kernel/Documentation/gpio.txt
如下:
There are three kinds of entry in /sys/class/gpio: - Control interfaces used to get userspace control over GPIOs; - GPIOs themselves; and - GPIO controllers ("gpio_chip" instances). That's in addition to standard files including the "device" symlink. The control interfaces are write-only: /sys/class/gpio/ "export" ... Userspace may ask the kernel to export control of
a GPIO to userspace by writing its number to this file. Example: "echo 19 > export" will create a "gpio19" node
for GPIO #19, if that's not requested by kernel code. "unexport" ... Reverses the effect of exporting to userspace. Example: "echo 19 > unexport" will remove a "gpio19"
node exported using the "export" file. GPIO signals have paths like /sys/class/gpio/gpio42/ (for GPIO #42)
and have the following read/write attributes: /sys/class/gpio/gpioN/ "direction" ... reads as either "in" or "out". This value may
normally be written. Writing as "out" defaults to
initializing the value as low. To ensure glitch free
operation, values "low" and "high" may be written to
configure the GPIO as an output with that initial value. Note that this attribute *will not exist* if the kernel
doesn't support changing the direction of a GPIO, or
it was exported by kernel code that didn't explicitly
allow userspace to reconfigure this GPIO's direction. "value" ... reads as either 0 (low) or 1 (high). If the GPIO
is configured as an output, this value may be written;
any nonzero value is treated as high. If the pin can be configured as interrupt-generating interrupt
and if it has been configured to generate interrupts (see the
description of "edge"), you can poll(2) on that file and
poll(2) will return whenever the interrupt was triggered. If
you use poll(2), set the events POLLPRI and POLLERR. If you
use select(2), set the file descriptor in exceptfds. After
poll(2) returns, either lseek(2) to the beginning of the sysfs
file and read the new value or close the file and re-open it
to read the value. "edge" ... reads as either "none", "rising", "falling", or
"both". Write these strings to select the signal edge(s)
that will make poll(2) on the "value" file return. This file exists only if the pin can be configured as an
interrupt generating input pin. "active_low" ... reads as either 0 (false) or 1 (true). Write
any nonzero value to invert the value attribute both
for reading and writing. Existing and subsequent
poll(2) support configuration via the edge attribute
for "rising" and "falling" edges will follow this
setting. GPIO controllers have paths like /sys/class/gpio/gpiochip42/ (for the
controller implementing GPIOs starting at #42) and have the following
read-only attributes: /sys/class/gpio/gpiochipN/ "base" ... same as N, the first GPIO managed by this chip "label" ... provided for diagnostics (not always unique) "ngpio" ... how many GPIOs this manges (N to N + ngpio - 1) Board documentation should in most cases cover what GPIOs are used for
what purposes. However, those numbers are not always stable; GPIOs on
a daughtercard might be different depending on the base board being used,
or other cards in the stack. In such cases, you may need to use the
gpiochip nodes (possibly in conjunction with schematics) to determine
the correct GPIO number to use for a given signal.

imx6 gpio irq的更多相关文章

  1. gpio irq

    /***************************************************************** * gpio irq * * 一直以来都没了解过gpio的irq, ...

  2. imx6 gpio分析

    本文主要介绍如何配置IOMUX寄存器,设置IO复用寄存器,配置为GPIO功能.参考: http://www.jianshu.com/p/3c2053508342 http://www.embest-t ...

  3. 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(3)

    作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...

  4. 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(1)

    作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...

  5. A20 GPIO中断类型差别结果迥异的问题思考

    A20GPIO中断类型差别结果迥异的问题思考 最近在使用全志A20做开发时,发现在处理中断的时候,用电平触发模式,报中断比较乱,用边沿触发则很稳定,不会乱报.笔者感到比较困惑,笔者用电平触发写的cod ...

  6. Linux中的gpio口使用方法

    Linux中的IO使用方法 应该是新版本内核才有的方法.请参考:./Documentation/gpio.txt文件 提供的API:驱动需要包含 #include <linux/gpio.h&g ...

  7. linux设备驱动程序--gpio控制

    gpio驱动程序 上一章节linux设备驱动程序--创建设备节点章节主要介绍了linux字符设备驱动程序的框架,从这一章节开始我们讲解各种外设的控制,包括gpio,i2c,dma等等,既然是外设,那就 ...

  8. Linux 内核层和 用户层 配置 GPIO 引脚

    Linux BSP 开发的基础就是和GPIO打交道, 下面总结下这几天对某家开发板的GPIO控制的知识. 公司的开发板用的是 DTB  模式 ,首先,进入 dts,dtsi文件查看关于GPIO 的模块 ...

  9. 痞子衡嵌入式:利用GPIO模块来测量i.MXRT1xxx的系统中断延迟时间

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1xxx的系统中断延迟时间. 在 <Cortex-M系统中断延迟及其测量方法简介> 一文里,痞子衡介绍了 Cor ...

随机推荐

  1. Javascript学习笔记:闭包题解(4)

    代码: var val1=0; var val2=0; var val3=0; for(var i1=1;i1<=3;i1++){ var i2=i1; (function(){ var i3= ...

  2. OpenCV2+入门系列(四):计算图像的直方图,平均灰度,灰度方差

    本篇懒得排版,直接在网页html编辑器编辑 在图像处理时,我们常常需要求出图像的直方图.灰度平均值.灰度的方差,这里给出一个opencv2+自带程序,实现这些功能. 直方图 对于直方图,使用cv::c ...

  3. linux运行级别

    也许大家偶然会发现/sbin里有个init命令.你知道它是如何使用的吗? 如果你不喜欢使用图形登录方式,如何能够让用户在控制台下运行startx命令呢? 有时你要维护服务器,暂时不希望别的用户登录系统 ...

  4. 浅谈C#Socket

    好不容易把socket通信搞懂一点,比较喜欢做笔记,嘿嘿~ 希望共同学习,共同进步! socket通信是C#中非常基础的一个知识点,我这里用到的是基于Tcp协议的socket通信.Tcp会有三次握手连 ...

  5. 浅谈 原生javaScript&&react 实现全局触摸按钮(附带对addeventlistener的了解)

    1.采用原生javaACript 实现全局触摸按钮 首先在控制台输出,观察事件有哪些关于触摸的字段可以使用,然后拿这些字段的数据开始来写方法. 因为要做的是全局触摸按钮,我需要拿到的是按钮时时的坐标位 ...

  6. CSS3中的伪类选择器详解

      类选择器和伪类选择器区别 类选择器我们可以随意起名,而伪类选择器是CSS中已经定义好的选择器,不可以随意起名. 伪类选择器以及伪元素 我们把它放到这里 p.aaas{ text-align: le ...

  7. 贪心算法(Greedy Algorithm)

    参考: 五大常用算法之三:贪心算法 算法系列:贪心算法 贪心算法详解 从零开始学贪心算法 一.基本概念: 所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以 ...

  8. i.

    史上最全web.xml配置文件元素详解 一.web.xml配置文件常用元素及其意义预览 <!--servlet API的版本2.3增加了对事件监听程序的支持,事件监听程序在建立.修改和删除会话或 ...

  9. 正则匹配中 ^ $ 和 \b 的区别

    正则匹配中 ^ $ 和 \b 的区别     ^和$分别代表字符串的开始和结束,因此^\d$只能匹配包含一个数字的字符串\b代表单词边界,其前后必须是不同类型的字符,可以组成单词的字符为一种类型,不可 ...

  10. Vue刨坑

    vue常见问题 1.在自定义组件里,你可以像任何普通元素一样用v-for.eg1: <my-component v-for="item in items"></m ...