ck2952

ck2952

0个粉丝

14

问答

0

专栏

0

资料

ck2952  发布于  2017-10-11 15:37:08
采纳率 0%
14个问答
5242

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;
}

希望大佬指点一下,搞了蛮久都没找到问题。。。。。

我来回答
回答5个
时间排序
认可量排序

ck2952

0个粉丝

14

问答

0

专栏

0

资料

ck2952 2017-11-29 17:10:56
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=79317&ptid=37934]hero 发表于 2017-10-12 08:44[/url]
[/quote]

【已解决】,中断号的问题

qn1522720710

0个粉丝

9

问答

0

专栏

0

资料

qn1522720710 2020-06-04 16:26:37
认可0
楼主大好人,学习了!

微信用户

0个粉丝

87

问答

0

专栏

3

资料

微信用户 2020-06-04 18:13:27
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=81352&ptid=37934]ck2952 发表于 2017-11-29 17:10[/url]
【已解决】,中断号的问题[/quote]

在 dts 里面弄就好了 ,

hero

0个粉丝

1

问答

0

专栏

0

资料

hero 2017-10-12 08:44:58
认可0
:):):):):):):):):):):)

sxsong

0个粉丝

12

问答

0

专栏

1

资料

sxsong 2019-09-08 21:44:31
认可0

好好好!!!!!!!!
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
相关问答
无更多相似问答 去提问
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区