5401
- 收藏
- 点赞
- 分享
- 举报
Hi3536 GPIO中断输入问题
本帖最后由 ck2952 于 2017-10-11 16:03 编辑
各位大佬,我现在在Hi3536开发板上想设置GPIO_0_7中断输入,下降沿触发中断,中断处理程序中需要读取GPIO_0_6管教的输入数据,按照网上一个Hi3515按键中断的例子修改的驱动,目前现象是:驱动加载成功,中断向量注册成功,但是一直无法进中断,麻烦大佬指点一下我的驱动程序哪里有问题
驱动程序如下:
#include
#include /*声明printk()这个内核态的函数*/
#include /*文件系统有关的,结构体file_operations也在fs头文件定义*/
#include /*init和exit相关宏*/
#include
#include
#include /*linux中断定义*/
#include
#include /*包含与中断相关的大部分宏及结构体的定义,request_irq()等*/
#include /*linux中的用户态内存交互函数,copy_from_user(),copy_to_user()等*/
//#include
//#include
#include
#include
#include /*misc混合设备注册与注销*/
#include
#include
#include
#define DEVICE_NAME "gpio_irq"
#define irq_num (44)
#define REG_WRITE(addr, value) ((*(volatile unsigned int *)(addr)) = (value))
#define REG_READ(Addr) (*(volatile unsigned int *)(Addr))
#define GPIO_0_BASE 0x12150000
#define GPIO_0_DIR IO_ADDRESS(GPIO_0_BASE + 0x400) //GPIO 方向控制寄存器
#define GPIO_0_IS IO_ADDRESS(GPIO_0_BASE + 0x404) //GPIO 中断触发寄存器
#define GPIO_0_IEV IO_ADDRESS(GPIO_0_BASE + 0x40C) //GPIO 触发中断条件寄存器
#define GPIO_0_IC IO_ADDRESS(GPIO_0_BASE + 0x41C) //GPIO 中断清除寄存器
#define GPIO_0_IE IO_ADDRESS(GPIO_0_BASE + 0x410) //GPIO 中断屏蔽寄存器
#define GPIO_0_RIS IO_ADDRESS(GPIO_0_BASE + 0x414) //GPIO 原始中断状态寄存器
#define GPIO_SPI_SDI_REG IO_ADDRESS(GPIO_0_BASE + 0x100) //GPIO_0_6 SDI
static volatile char reg_data = 0; ////GPIO_0_6 data
static volatile char reg_sdi = 0; ////GPIO_0_6 SDI
static DECLARE_WAIT_QUEUE_HEAD(sck_waitq); /*定义和初始化一个等待队列头*/
static volatile int ev_press = 0; /*定义一个整形变量,判断按键是否按下*/
static volatile char flag_num = 0;
//定义结构体类型,由它把中断的信息综合起来
struct gpio_irq_desc{
int irq;/*中断号*/
int pin;/*中断标志寄存器,有中断产生时为1,无中断时为0*/
int number;/*编号*/
char *name;/*名称*/
};
static struct gpio_irq_desc gpio_irqs[]={
{44, 2, 1, "gpio_irq"},
};
static void hi3536_pin_cfg(void)
{
/*配置作为普通输入*/
unsigned char regvalue;
regvalue = REG_READ(GPIO_0_DIR);
regvalue &= 0x3f;
REG_WRITE(GPIO_0_DIR, regvalue);
/*GPIO_0_7 管脚中断配置*/
regvalue = REG_READ(GPIO_0_IS);
regvalue &= 0x7f;
REG_WRITE(GPIO_0_IS, regvalue);/*is边沿触发中断*/
regvalue = REG_READ(GPIO_0_IEV);
//regvalue |= 0x80;
regvalue &= 0x7f;
REG_WRITE(GPIO_0_IEV, regvalue);/*iev上升沿触发*/
regvalue = REG_READ(GPIO_0_IC);
regvalue |= 0xff;
REG_WRITE(GPIO_0_IC, regvalue);/*ic清除中断*/
regvalue = REG_READ(GPIO_0_IE);
regvalue |= 0x80;
REG_WRITE(GPIO_0_IE, regvalue);/*ie启用中断*/
}
/*
*read调用的具体函数,由它读取键盘输入的结果,
*实质上就是读取key_values数组的值
*完成键盘输入设备的核心功能,根据标志位ev_press判断是否可读
*如果可读,则读取数据到用户buffer中,如果不可读,
*则进程进入等待队列等待,直到数组可读为止
*等待队列机制,所中断管理中常用的机制。
*/
static int gpio_irq_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
unsigned long err;
#if 1
if(!ev_press) /*ev_press=0,则表示没有数据可读*/
{
if(filp->f_flags & O_NONBLOCK)
return -EAGAIN;
else /*无数据可读时,进程休眠,放进sck_waitq等待队列*/
wait_event_interruptible(sck_waitq, ev_press);
/*
*wait_event_interruptible()函数将进程置为可中断的挂起状态
*反复检查ev_press=1是否成立,如果不成立,则继续休眠。
*条件满足后,即把本程序置为运行态,
*/
}
/*ev_press=1之后,进程退出等待队列。从此处开始运行*/
ev_press = 0; /*置0标志位,表明本次中断已经处理*/
err = copy_to_user(buff, ®_sdi, sizeof(reg_sdi)); /*把按键值传会用户空间*/
#endif
return 0;
}
static irqreturn_t irq_interrupt(int irq, void *dev_id)
{
#if 1
/*对传入的中断资源进行处理,获得中断控制寄存器的值(即是否有数据)
取反后赋值给down,为0时说明有数据,
注意按下依次按钮有两次中断,
对数组可读标志位进行设置,ev_press=1表示数组已经可以读了*/
printk("irq success !\n");
int down;
unsigned char regvalue;
down = 0x80 & REG_READ(GPIO_0_RIS); //获取GPIO_0_7中断状态
regvalue = REG_READ(GPIO_0_IC);
regvalue |= 0xff;
REG_WRITE(GPIO_0_IC, regvalue);/*ic清除中断*/
mdelay(5);
if(down == 0x80)
{
reg_data = REG_READ(GPIO_SPI_SDI_REG);
if((reg_data & 0x40) != 0)
reg_sdi = reg_sdi | (1<<(7-flag_num));
flag_num ++;
if(flag_num == 8)
{
ev_press = 1; /*置1标志位,唤醒等待队列进程,在read函数中使用*/
flag_num = 0;
printk("irq success !\n");
}
/*l
*唤醒休眠的进程,用户空间程序使用调用read函数时,
*如果没有产生中断,进程就会进入休眠状态,一直等待,直到产生中断
*中断产生后,通过wake_up_interruptible()函数唤醒休眠进程
*/
wake_up_interruptible(&sck_waitq);
}
#endif
regvalue = REG_READ(GPIO_0_IE);
regvalue |= 0x80;
REG_WRITE(GPIO_0_IE, regvalue);/*ie启用中断*/
return IRQ_HANDLED; //IRQ_HANDLED=1
}
/*
*poll调用的具体函数,poll实质上是select的调用函数
*如果有按键数据,则select会立刻返回
*如果没有按键数据,则等待
*实质上这是键盘等待输入的机制
*poll_wait()会监测进程队列button_waitq里的进程
*例如button_irq_read所在的进程的标志ev_press置为1了
*那么就不再等待,这实质上就所select函数的运行机制
*/
static unsigned int gpio_irq_poll(struct file *file, struct poll_table_struct *wait)
{
#if 1
/*
*poll调用的具体函数,poll实质上是select的调用函数
*如果有按键数据,则select会立刻返回
*如果没有按键数据,则等待
*实质上这是键盘等待输入的机制。
*select调用是用户程序里面使用的。
*/
unsigned int mask = 0;
poll_wait(file, &sck_waitq, wait);
/*poll_wait会检测button_waitq里的进程*/
if(ev_press)
mask |=POLLIN | POLLRDNORM;
return mask;
#endif
}
static int gpio_irq_open(struct inode *inode,struct file *file)
{
#if 1
int err;/*中断注册返回值*/
hi3536_pin_cfg();/*管脚配置*/
/*注册中断*/
err = request_irq(irq_num, irq_interrupt, IRQF_SHARED,\
"gpio_irq", (void *)&gpio_irqs);
if(err)/*如果注册中断失败,则释放已经成功注册的中断*/
{
return -EBUSY;
}
ev_press = 1;
#endif
return 0;
}
static int gpio_irq_close(struct inode *inode,struct file *file)
{
free_irq(44, (void *)&gpio_irqs);
return 0;
}
int gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned int __user *argp = (unsigned int __user *)arg;
int value;
value = *(unsigned int *)arg;
return 0;
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.open = gpio_irq_open,
.release = gpio_irq_close,
.unlocked_ioctl = gpio_ioctl,
.read = gpio_irq_read,
.poll = gpio_irq_poll, /*用户程序使用select调用的时候才会用到poll*/
};
/*
*misc混合设备注册和注销
*/
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR, /*次设备号*/
.name = DEVICE_NAME, /*设备名*/
.fops = &dev_fops, /*设备文件操作结构体*/
};
static int __init gpio_init(void)
{
int ret;
ret = misc_register(&misc);
if(0 != ret)
{
printk("register device failed !\n");
return -1;
}
printk("register device success !\n");
return 0;
}
static void __exit gpio_exit(void)
{
misc_deregister(&misc);
printk("unregister device success !\n");
}
module_init(gpio_init);
module_exit(gpio_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dong");
测试程序如下:
#include
#include
#include
#include
#include
#include
#include
//#define GPIO_SPI_READ 0x01
//#define GPIO_SPI_WRITE 0x03
int main(int argc , char* argv[])
{
int fd0, fd1;
unsigned char reg_sdi;
/*
fd0 = open("/dev/gpio_spi", 0);
if(fd0 < 0)
{
printf("Open gpio_spi error!\n");
return -1;
}
*/
fd1 = open("/dev/gpio_irq", 0);
if (fd1 < 0)
{
printf("%X\n", fd1);
printf("Open gpio_irq dev error !\n");
return -1;
}
for(;;)
{
int ret, value = 0xaa;
//ret = ioctl(fd0, GPIO_SPI_WRITE, &value);
ret = read(fd1, ®_sdi, sizeof(reg_sdi));
if(ret< 0)
{
perror("read gpio: ");
return -1;
}
printf("read buffer data is : %.2X\n", reg_sdi);
//sleep(1);
}
//close(fd0);
close(fd1);
return 0;
}
希望大佬指点一下,搞了蛮久都没找到问题。。。。。
各位大佬,我现在在Hi3536开发板上想设置GPIO_0_7中断输入,下降沿触发中断,中断处理程序中需要读取GPIO_0_6管教的输入数据,按照网上一个Hi3515按键中断的例子修改的驱动,目前现象是:驱动加载成功,中断向量注册成功,但是一直无法进中断,麻烦大佬指点一下我的驱动程序哪里有问题
驱动程序如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
//#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "gpio_irq"
#define irq_num (44)
#define REG_WRITE(addr, value) ((*(volatile unsigned int *)(addr)) = (value))
#define REG_READ(Addr) (*(volatile unsigned int *)(Addr))
#define GPIO_0_BASE 0x12150000
#define GPIO_0_DIR IO_ADDRESS(GPIO_0_BASE + 0x400) //GPIO 方向控制寄存器
#define GPIO_0_IS IO_ADDRESS(GPIO_0_BASE + 0x404) //GPIO 中断触发寄存器
#define GPIO_0_IEV IO_ADDRESS(GPIO_0_BASE + 0x40C) //GPIO 触发中断条件寄存器
#define GPIO_0_IC IO_ADDRESS(GPIO_0_BASE + 0x41C) //GPIO 中断清除寄存器
#define GPIO_0_IE IO_ADDRESS(GPIO_0_BASE + 0x410) //GPIO 中断屏蔽寄存器
#define GPIO_0_RIS IO_ADDRESS(GPIO_0_BASE + 0x414) //GPIO 原始中断状态寄存器
#define GPIO_SPI_SDI_REG IO_ADDRESS(GPIO_0_BASE + 0x100) //GPIO_0_6 SDI
static volatile char reg_data = 0; ////GPIO_0_6 data
static volatile char reg_sdi = 0; ////GPIO_0_6 SDI
static DECLARE_WAIT_QUEUE_HEAD(sck_waitq); /*定义和初始化一个等待队列头*/
static volatile int ev_press = 0; /*定义一个整形变量,判断按键是否按下*/
static volatile char flag_num = 0;
//定义结构体类型,由它把中断的信息综合起来
struct gpio_irq_desc{
int irq;/*中断号*/
int pin;/*中断标志寄存器,有中断产生时为1,无中断时为0*/
int number;/*编号*/
char *name;/*名称*/
};
static struct gpio_irq_desc gpio_irqs[]={
{44, 2, 1, "gpio_irq"},
};
static void hi3536_pin_cfg(void)
{
/*配置作为普通输入*/
unsigned char regvalue;
regvalue = REG_READ(GPIO_0_DIR);
regvalue &= 0x3f;
REG_WRITE(GPIO_0_DIR, regvalue);
/*GPIO_0_7 管脚中断配置*/
regvalue = REG_READ(GPIO_0_IS);
regvalue &= 0x7f;
REG_WRITE(GPIO_0_IS, regvalue);/*is边沿触发中断*/
regvalue = REG_READ(GPIO_0_IEV);
//regvalue |= 0x80;
regvalue &= 0x7f;
REG_WRITE(GPIO_0_IEV, regvalue);/*iev上升沿触发*/
regvalue = REG_READ(GPIO_0_IC);
regvalue |= 0xff;
REG_WRITE(GPIO_0_IC, regvalue);/*ic清除中断*/
regvalue = REG_READ(GPIO_0_IE);
regvalue |= 0x80;
REG_WRITE(GPIO_0_IE, regvalue);/*ie启用中断*/
}
/*
*read调用的具体函数,由它读取键盘输入的结果,
*实质上就是读取key_values数组的值
*完成键盘输入设备的核心功能,根据标志位ev_press判断是否可读
*如果可读,则读取数据到用户buffer中,如果不可读,
*则进程进入等待队列等待,直到数组可读为止
*等待队列机制,所中断管理中常用的机制。
*/
static int gpio_irq_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
unsigned long err;
#if 1
if(!ev_press) /*ev_press=0,则表示没有数据可读*/
{
if(filp->f_flags & O_NONBLOCK)
return -EAGAIN;
else /*无数据可读时,进程休眠,放进sck_waitq等待队列*/
wait_event_interruptible(sck_waitq, ev_press);
/*
*wait_event_interruptible()函数将进程置为可中断的挂起状态
*反复检查ev_press=1是否成立,如果不成立,则继续休眠。
*条件满足后,即把本程序置为运行态,
*/
}
/*ev_press=1之后,进程退出等待队列。从此处开始运行*/
ev_press = 0; /*置0标志位,表明本次中断已经处理*/
err = copy_to_user(buff, ®_sdi, sizeof(reg_sdi)); /*把按键值传会用户空间*/
#endif
return 0;
}
static irqreturn_t irq_interrupt(int irq, void *dev_id)
{
#if 1
/*对传入的中断资源进行处理,获得中断控制寄存器的值(即是否有数据)
取反后赋值给down,为0时说明有数据,
注意按下依次按钮有两次中断,
对数组可读标志位进行设置,ev_press=1表示数组已经可以读了*/
printk("irq success !\n");
int down;
unsigned char regvalue;
down = 0x80 & REG_READ(GPIO_0_RIS); //获取GPIO_0_7中断状态
regvalue = REG_READ(GPIO_0_IC);
regvalue |= 0xff;
REG_WRITE(GPIO_0_IC, regvalue);/*ic清除中断*/
mdelay(5);
if(down == 0x80)
{
reg_data = REG_READ(GPIO_SPI_SDI_REG);
if((reg_data & 0x40) != 0)
reg_sdi = reg_sdi | (1<<(7-flag_num));
flag_num ++;
if(flag_num == 8)
{
ev_press = 1; /*置1标志位,唤醒等待队列进程,在read函数中使用*/
flag_num = 0;
printk("irq success !\n");
}
/*l
*唤醒休眠的进程,用户空间程序使用调用read函数时,
*如果没有产生中断,进程就会进入休眠状态,一直等待,直到产生中断
*中断产生后,通过wake_up_interruptible()函数唤醒休眠进程
*/
wake_up_interruptible(&sck_waitq);
}
#endif
regvalue = REG_READ(GPIO_0_IE);
regvalue |= 0x80;
REG_WRITE(GPIO_0_IE, regvalue);/*ie启用中断*/
return IRQ_HANDLED; //IRQ_HANDLED=1
}
/*
*poll调用的具体函数,poll实质上是select的调用函数
*如果有按键数据,则select会立刻返回
*如果没有按键数据,则等待
*实质上这是键盘等待输入的机制
*poll_wait()会监测进程队列button_waitq里的进程
*例如button_irq_read所在的进程的标志ev_press置为1了
*那么就不再等待,这实质上就所select函数的运行机制
*/
static unsigned int gpio_irq_poll(struct file *file, struct poll_table_struct *wait)
{
#if 1
/*
*poll调用的具体函数,poll实质上是select的调用函数
*如果有按键数据,则select会立刻返回
*如果没有按键数据,则等待
*实质上这是键盘等待输入的机制。
*select调用是用户程序里面使用的。
*/
unsigned int mask = 0;
poll_wait(file, &sck_waitq, wait);
/*poll_wait会检测button_waitq里的进程*/
if(ev_press)
mask |=POLLIN | POLLRDNORM;
return mask;
#endif
}
static int gpio_irq_open(struct inode *inode,struct file *file)
{
#if 1
int err;/*中断注册返回值*/
hi3536_pin_cfg();/*管脚配置*/
/*注册中断*/
err = request_irq(irq_num, irq_interrupt, IRQF_SHARED,\
"gpio_irq", (void *)&gpio_irqs);
if(err)/*如果注册中断失败,则释放已经成功注册的中断*/
{
return -EBUSY;
}
ev_press = 1;
#endif
return 0;
}
static int gpio_irq_close(struct inode *inode,struct file *file)
{
free_irq(44, (void *)&gpio_irqs);
return 0;
}
int gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned int __user *argp = (unsigned int __user *)arg;
int value;
value = *(unsigned int *)arg;
return 0;
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.open = gpio_irq_open,
.release = gpio_irq_close,
.unlocked_ioctl = gpio_ioctl,
.read = gpio_irq_read,
.poll = gpio_irq_poll, /*用户程序使用select调用的时候才会用到poll*/
};
/*
*misc混合设备注册和注销
*/
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR, /*次设备号*/
.name = DEVICE_NAME, /*设备名*/
.fops = &dev_fops, /*设备文件操作结构体*/
};
static int __init gpio_init(void)
{
int ret;
ret = misc_register(&misc);
if(0 != ret)
{
printk("register device failed !\n");
return -1;
}
printk("register device success !\n");
return 0;
}
static void __exit gpio_exit(void)
{
misc_deregister(&misc);
printk("unregister device success !\n");
}
module_init(gpio_init);
module_exit(gpio_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dong");
测试程序如下:
#include
#include
#include
#include
#include
#include
#include
//#define GPIO_SPI_READ 0x01
//#define GPIO_SPI_WRITE 0x03
int main(int argc , char* argv[])
{
int fd0, fd1;
unsigned char reg_sdi;
/*
fd0 = open("/dev/gpio_spi", 0);
if(fd0 < 0)
{
printf("Open gpio_spi error!\n");
return -1;
}
*/
fd1 = open("/dev/gpio_irq", 0);
if (fd1 < 0)
{
printf("%X\n", fd1);
printf("Open gpio_irq dev error !\n");
return -1;
}
for(;;)
{
int ret, value = 0xaa;
//ret = ioctl(fd0, GPIO_SPI_WRITE, &value);
ret = read(fd1, ®_sdi, sizeof(reg_sdi));
if(ret< 0)
{
perror("read gpio: ");
return -1;
}
printf("read buffer data is : %.2X\n", reg_sdi);
//sleep(1);
}
//close(fd0);
close(fd1);
return 0;
}
希望大佬指点一下,搞了蛮久都没找到问题。。。。。
我来回答
回答5个
时间排序
认可量排序
认可0
认可0
认可0
认可0
认可0
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币
Markdown 语法
- 加粗**内容**
- 斜体*内容*
- 删除线~~内容~~
- 引用> 引用内容
- 代码`代码`
- 代码块```编程语言↵代码```
- 链接[链接标题](url)
- 无序列表- 内容
- 有序列表1. 内容
- 缩进内容
- 图片![alt](url)
相关问答
-
2018-08-08 19:05:56
-
2016-08-02 10:57:33
-
2019-05-14 16:18:59
-
2019-05-14 16:24:15
-
2016-05-24 22:15:16
-
2020-05-14 18:10:06
-
2017-09-17 01:46:14
-
72014-08-07 22:06:30
-
2018-07-24 09:51:32
-
112016-03-21 18:49:07
-
2017-10-18 16:33:34
-
102016-08-04 13:47:50
-
272016-05-05 16:10:52
-
2017-07-20 16:06:20
-
2015-08-13 17:43:27
-
2016-10-11 10:54:13
-
2017-01-22 14:29:26
-
2019-01-02 16:42:10
-
122015-08-20 16:59:33
无更多相似问答 去提问
点击登录
-- 积分
-- E币
提问
—
收益
—
被采纳
—
我要提问
切换马甲
上一页
下一页
悬赏问答
-
5Hi3516CV610 如何使用SD卡升级固件
-
5cat /dev/logmpp 报错 <3>[ vi] [func]:vi_send_frame_node [line]:99 [info]:vi pic queue is full!
-
50如何获取vpss chn的图像修改后发送至vo
-
5FPGA通过Bt1120传YUV422数据过来,vi接收不到数据——3516dv500
-
50SS928 运行PQtools 拼接 推到设备里有一半画面会异常
-
53536AV100的sample_vdec输出到CVBS显示
-
10海思板子mpp怎么在vi阶段改变视频数据尺寸
-
10HI3559AV100 多摄像头同步模式
-
9海思ss928单路摄像头vio中加入opencv处理并显示
-
10EB-RV1126-BC-191板子运行自己编码的程序
举报反馈
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明
提醒
你的问题还没有最佳答案,是否结题,结题后将扣除20%的悬赏金
取消
确认
提醒
你的问题还没有最佳答案,是否结题,结题后将根据回答情况扣除相应悬赏金(1回答=1E币)
取消
确认