zoukankan      html  css  js  c++  java
  • 基于OMAPL138的字符驱动_GPIO驱动AD9833(三)之中断申请IRQ

    基于OMAPL138的字符驱动_GPIO驱动AD9833(三)之中断申请IRQ

    0. 导语

    学习进入到了下一个阶段,还是以AD9833为例,这次学习是向设备申请中断,实现触发,在未来很多场景,比如做用户级的SPI传输完毕数据之后,怎么知道从设备要发数据呢,则需要一个IO信号通知主设备来读从设备的数据,那么就需要一个外部的IO中断信号,所以呢,对于中断的处理十分重要,本demo实现这样的一个功能增加一个GPIO口,这个GPIO口接的是一个按键,通过触发信号,进入中断服务函数,在中断服务函数内改变AD9833的波形。以此达到学习实验目的。

    之前的代码都是一样的,在这里尽量剥离AD9833驱动和Linux的代码模板,只写中断相关相关程序。

    效果演示视频: https://v.youku.com/v_show/id_XMzY4MjAwOTA0MA==.html?spm=a2h3j.8428770.3416059.1

    1. 前篇导读:

    1. 基于OMAPL138的字符驱动_GPIO驱动AD9833(一)之ioctl

    2. 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(二)之cdev与read、write

    3. Linux GPIO键盘驱动开发记录_OMAPL138

    原理图:

    2. 申请中断准备

    • 首先需要两个头文件:

    • #include <linux/interrupt.h>

    • #include <linux/irq.h>

    • IO口配置准备
      在此次使用中断中,主要用的是GPIO口,我们使用电平跳变使之进入到中断处理程序中,所以作为IO口,需要配置IO口的方向为输入方向。我的OMAPL138中给的IO口操作使用GPIO_TO_PIN这个宏函数进行,在IO口操作上每个平台都会给定自己的寻IO口的方法,然后使用linux通用gpio_direction_output进行设定该GPIO口为输入方向,如上面的原理图,本demo的驱动使用的GPIO6[1],所以as follow:gpio_direction_output( GPIO_TO_PIN(6, 1) , 0 );

    • 硬件中断号IRQ
      我参考了很多文献,也找了很多书籍,对于硬件中断号码从哪里得到一笔带过,也没有具体说明,不过,经过一下午的努力,我找到了查找中断号码的方法。使用gpio_to_irq这个函数方法可以得到irq。我之前找到手册,看到了手册里面说GPIO6 BANK的IRQ为48号,我尝试加载到内核里面,每次初始化的时候都告诉我中断申请失败,这个号看来不是datasheet给定的48号,在Linux内核里面对于硬件IRQ又进行了重新映射。

    • 中断事件
      在内核中断申请的时候,需要指定中断事件是什么,边沿信号,高电平触发,低电平触发,在irq.h里面定义了:

    	IRQ_TYPE_NONE		= 0x00000000,
    	IRQ_TYPE_EDGE_RISING	= 0x00000001,
    	IRQ_TYPE_EDGE_FALLING	= 0x00000002,
    	IRQ_TYPE_EDGE_BOTH	= (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING),
    	IRQ_TYPE_LEVEL_HIGH	= 0x00000004,
    	IRQ_TYPE_LEVEL_LOW	= 0x00000008,
    	IRQ_TYPE_LEVEL_MASK	= (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH),
    	IRQ_TYPE_SENSE_MASK	= 0x0000000f	
    

    我们需要指定这个事件。

    • 中断的名字
      这个使用#cat /proc/interrupts 查看当前内核中断资源的时候就可以看到你指定注册的名字。

    • 中断服务程序
      这个我们自己定一个函数就可以,然后一会儿使用中断申请的时候将数据传输进去就好。我们在中断服务函数里面进行按键进行波形切换:
    static int key_count = 0;
    static irqreturn_t	ad9833_press_intHandle( int irq, void *dev_id )
    {
    	printk( DRV_NAME "	 press trigger!
    " );
    	if( key_count == 0 )  {
    	    ad9833->set_wave_type( ad9833, SIN );
    	    printk( DRV_NAME "	Set wave is SIN.
    " );
    	}else if( key_count == 2 ) {
    	    ad9833->set_wave_type( ad9833, TRI );
    	    printk( DRV_NAME "	Set wave is TRI.
    " );
    	}else if( key_count == 4 ) {
    	    ad9833->set_wave_type( ad9833, SQU );
    	    printk( DRV_NAME "	Set wave is SQU.
    " );
    	}
    	key_count ++;
    	if( key_count >= 5 )
    	    key_count = 0;
    
    	return	IRQ_RETVAL( IRQ_HANDLED );
    }
    

    3. 申请中断准备

    使用request_irq函数就好,我们在初始化函数里面,申请irq。在申请irq前,为了更好的管理中断函数,我们定义了一个结构体,专门进行irq配置。

    struct gpio_irq_desc {
    
    	int irq;
    	unsigned long flags;
    	char *name;
    
    } press_dev_desc = {
    
    		0,
    		IRQ_TYPE_EDGE_FALLING,
    		"sw6_push_button"
    
    };
    
    

    第一个是irq,我们在向内核申请中断的时候会使用gpio_to_irq进行irq的赋值,flags就是中断事件的触发条件,这里是下降边沿触发,最后一个name就是上面注册号中断分配的名字,初始化程序如下:

    	/*
    	 * interrupt apply
    	 * */
    	press_dev_desc.irq =  gpio_to_irq(ad9833_gpios[3]);
    	ret =	request_irq( press_dev_desc.irq , &ad9833_press_intHandle, press_dev_desc.flags, press_dev_desc.name, (void*)0 );
    	if( ret ) {
    		printk( DRV_NAME "	error %d: IRQ = %d number failed!
    ",ret,gpio_to_irq(ad9833_gpios[3]) );
    		ret = -EBUSY;
    	    unregister_chrdev_region( devno,1 );
    		for( i = 0; i < ARRAY_SIZE(ad9833_gpios); i++)
    		    gpio_free( ad9833_gpios[i] );
    		kfree(ad9833);
            return ret;
    	}
    	printk( DRV_NAME "	iqr apply ok!!
    " );
    	
    

    到此我们就完成了中断配置。

    4. 中断释放

    使用freqq_irq进行释放。这个函数应该放在exit驱动的函数里面。
    free_irq( press_dev_desc.irq, (void*)0 );

    源代码下载

    链接: https://pan.baidu.com/s/1JgPgGP1Ag_oixHmHOy3QEw 密码: 5x84

    参考文献

    [1] 创龙电子科技, OMAPL138的GPIO输出输入
    , 百度文库, 2014年5月8日

    [2] wh_19910525, Linux的 标准GPIO及中断API函数
    , CSDN博客, 2013年12月25日

    [3] wangcong02345, Linux内核---44.关于中断号与中断引脚
    , CSDN博客, 2016年7月9日

    [4] GreenHand#, Linux设备驱动中断机制
    , CNBLOGS, 2016年12月27日

  • 相关阅读:
    人民币格式化 ,分割
    解决IE下页面空白或者报错:[vuex] vuex requires a Promise polyfill in this browser
    js生成图片
    适用于iview的表格转Excel插件
    js金额转大写数字
    webstorm vue cli 热更新不起作用解决办法
    纯css实现 switch开关
    vue 时间戳转 YYYY-MM-DD h:m:s
    Simple2D-20(重构)
    Simple2D-19(音乐播放器)播放器的源码实现
  • 原文地址:https://www.cnblogs.com/sigma0/p/9217675.html
Copyright © 2011-2022 走看看