itop4412 设备树 Interrupt

本文详细介绍了设备树配置中断的相关内容,包括在arch/arm/boot/dts/exynos4412-itop-elite.dts中添加text_key节点,配置中断控制器和中断类型。还解析了中断控制器属性、中断号码获取、中断申请函数request_irq()、中断回调函数irq_handler_t以及中断处理流程。此外,提到了软中断tasklet的使用,包括tasklet_init()、tasklet_schedule()和tasklet_kill(),以及工作队列的初始化、调度和注销。整个过程强调了中断处理的效率和中断上下半部的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

itop4412 设备树 Interrupt

设备树配置

  • 在这个目录下面添加:arch/arm/boot/dts/exynos4412-itop-elite.dts

    text_key {
    		compatible = "key_text";
    		pinctrl-names = "default";
    		pinctrl-0 = <&key_text>;
    		interrupt-parent = <&gpx1>;
    		/* 第一个参数表示gpx1 下面的第一个IO口 第二个参数表示
    		 * 第二个参数表示中断类型 include/dt-bindings/interrupt-controller/irq.h
    		 *	#define IRQ_TYPE_NONE		0
    		 *	#define IRQ_TYPE_EDGE_RISING	1
    		 *	#define IRQ_TYPE_EDGE_FALLING	2
    		 *	#define IRQ_TYPE_EDGE_BOTH	(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
    		 *	#define IRQ_TYPE_LEVEL_HIGH	4
    		 *	#define IRQ_TYPE_LEVEL_LOW	8
    		 *  这个文件里面有详细的定义
    		*/
    		interrupts = <1 IRQ_TYPE_EDGE_RISING>; 
    		gpios = <&gpx1 1 GPIO_ACTIVE_LOW>;
    		status = "okay";
    	};
    

    pinctrl-0 要把它配置成输入模式,这点应该不用过多ed解释

  • 详细解释

    • 我们在arch/arm/boot/dts/exynos4412-pinctrl.dtsi 这个目录下面

      gpx1: gpx1 {
      			gpio-controller;
      			#gpio-cells = <2>;
      
      			interrupt-controller;
      			interrupt-parent = <&gic>;
      			interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
      				     <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
      				     <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
      				     <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
      				     <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>,
      				     <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
      				     <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
      				     <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
      			#interrupt-cells = <2>;
      		};
      
      • 可以看到里面有个interrupt-controller 属性,这个属性代表中断控制器,是个空值,也就是说所有继承它的,都归它管理,继承是什么意思呢?,比如我想要gpx1 下面的外部中断,就要在里面写 interrupt-parent = <&gpx1>;
      • interrupt-parent可以看到这个继承gic,这个节点,可以看到gic cells有三个属性,分别是GIC的类型,除了SPI(Shared Peripheral Interrupt)类型的,还有PPI(Private Peripheral Interrupt)类型的。第二个是中断号,这个查数据手册可以看到,最后一个是中断触发的条件。
      • #interrupt-cells = <2> 可以看到这个2是,代表继承我,interrupts 里面的属性是两个,第一个值是 引脚号 第二个是中断类型,具体的看上面那个text_key的描述。

中断的类型

  • 这个部分先放在这…

中断的使用

  • 具体用到的函数

    • request_irq()
      /* 可以看到它直接调用了一个函数,我们不分析它的源码,只看它的参数
       * @Parma1 中断号
       * @Parma2 回调函数,原型:irqreturn_t (*irq_handler_t)(int, void *);
       * @Parma3 中断的类型 
       * @Parma4 中断的名字 可以用cat /proc/interrupts 查看到名字
       * @Parma5 一般是传参的 
      */
      static inline int __must_check
      request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
      	    const char *name, void *dev)
      {
      	return request_threaded_irq(irq, handler, NULL, flags, name, dev);
      }
      
    • irq_handler_t()
      /* 这个是中断的回调函数
       * int 代表中断号,可以根据中断号,来判断
       * void* 表示传进来的参数
      */
      irqreturn_t (*irq_handler_t)(int, void *)
          
      irqreturn_t button_irq_hander(int irqno, void *dev)
      {
          
      }
      
    • free_irq()
      // 这个函数一看名字,就知道是释放中断,注意申请之后,一定要释放
      void *free_irq(unsigned int, void *);
      
  • 使用的流程

    先是通过设备树,获取中断号码,然后申请中断,编写回调函数,卸载模块的时候,应该释放

    回调函数里面处理的问题,应该快速,时间非常短,不能有数据拷贝的工作,如果有数 据拷贝的工作,

    应该用tasklt 或者工作队列,把耗时的操作放到这个地方执行。这样就把中断分为了上半部和下半部。

    • tasklt

      这个就是软中断,不允许休眠,先看下结构体里面有啥

      struct tasklet_struct
      {
      	struct tasklet_struct *next;  // 指向下一个tasklet_struct
      	unsigned long state;          //  状态
      	atomic_t count;               // 计数器,记录tasklet_struct引用次数
      	void (*func)(unsigned long);  // 执行的回调函数
      	unsigned long data;           // 函数参数
      };
      
      tasklet_init()
      /* 初始化一个结构体,也就是上面的结构体
       * @Parma1 要初始化的tasket
       * @Parma2 执行的回调函数
       * @Parma3 函数的参数
      */
      void tasklet_init(struct tasklet_struct *t,
      		  void (*func)(unsigned long), unsigned long data)
      
      tasklet_schedule()
      /* 调度,这个函数主要放在,中断上半段执行完后使用
       * @Parma1 tasket结构体指针
       */
      static inline void tasklet_schedule(struct tasklet_struct *t)
      
      tasklet_kill()
      /* 注销tasket对象
       * @Parma1 tasket结构体指针
      */
      void tasklet_kill(struct tasklet_struct *t);
      
    • 工作队列

      类似kthread_worker,就是创建一个线程

      先看结构体

      struct work_struct {
      	atomic_long_t data;
      	struct list_head entry;
      	work_func_t func;
      #ifdef CONFIG_LOCKDEP
      	struct lockdep_map lockdep_map;
      #endif
      };
      
      INIT_WORK()
      /* 初始化work ,这个地方的函数原型为:
       *   void work_fun(struct work_struct *work)
       *   {
       *       
       *   }
       *
      */
      #define INIT_WORK(_work, _func)				
      	__INIT_WORK((_work), (_func), 0)
      
      schedule_work()
      // 调度器
      static inline bool schedule_work(struct work_struct *work)
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值