BBB IRQ 驱动分析

一、 说明
Beaglebone Black开发板自带GPIO以及IRQ等驱动程序,所以为驱动的开发提供了极大的便利,在此主要分析内核自带的库文件中相关的函数以及驱动编写的步骤。


二、 IRQ库函数分析
 驱动添加的库函数有:
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
其中,库位于/kernel/kernel/include/linux路径下,
gpio.h库函数包含对IO口操作的相关函数,例如
static inline int gpio_get_value(unsigned int gpio) 获取引脚值
static inline void gpio_set_value(unsigned int gpio, int value)设置引脚值
static inline int gpio_to_irq(unsigned int gpio)把gpio引脚号转换为中断号
static inline int irq_to_gpio(unsigned int irq)把中断号转换为引脚号
static inline int gpio_direction_input(unsigned gpio)引脚方向设置为输入
static inline int gpio_direction_output(unsigned gpio, int value)引脚方向设置为输出
static inline int gpio_get_value(unsigned gpio)获取引脚的状态值
以上这些函数实际上已经完全可以实现GPIO所需的功能需求,换句话说,GPIO需要的驱动函数无非以上这些,当然仅限于IO操作,不涉及中断等
interrupt.h库函数主要包含中断相关的参数宏定义以及相关函数:
中断触发方式宏定义:
#define IRQF_TRIGGER_NONE 0x00000000
#define IRQF_TRIGGER_RISING 0x00000001   上升沿触发
#define IRQF_TRIGGER_FALLING 0x00000002   下降沿触发
#define IRQF_TRIGGER_HIGH 0x00000004 高电平触发
#define IRQF_TRIGGER_LOW 0x00000008        低电平触发
#define IRQF_TRIGGER_MASK (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)        貌似任意信号触发
#define IRQF_TRIGGER_PROBE 0x00000010
函数:
中断申请函数
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
中断释放函数

extern void free_irq(unsigned int, void *)


三、 中断程序分析


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>


#define PIN_A_GPIO 65 // is on 2*32+1 设置中断引脚为GPIO2_1
#define PIN_A_FLAGS GPIOF_IN
#define PIN_A_LABEL "HI_PIN_A"
int k;
static irqreturn_t irq_handler_pin_a (int irq, void *dev_id)  //中断处理函数
{
  printk (KERN_INFO "Hello from irq_handler_pin_a...%d\n",k);
  k++;
  return IRQ_HANDLED;
}
//加载函数,实现中断申请等相关功能
static int __init hello_interrupts_start (void) 
{
  int retval, irq, regval;
  printk (KERN_INFO "Loading hello_interrupts module...\n");
  retval = gpio_request_one(PIN_A_GPIO, PIN_A_FLAGS, PIN_A_LABEL);
printk (KERN_INFO "HI:request GPIO pin#%i for IRQ (%i)\n", PIN_A_GPIO, retval);

irq = gpio_to_irq (PIN_A_GPIO);
retval = request_irq (irq, irq_handler_pin_a, 1/*IRQF_TRIGGER_RISING */, PIN_A_LABEL, NULL);
irq_set_irq_type (irq, IRQ_TYPE_EDGE_BOTH);
 return 0;
}
//驱动卸载
static void __exit hello_interrupts_end(void)
 {
  printk ("HI: Releasing IRQ resources...\n");
  free_irq (gpio_to_irq (PIN_A_GPIO), NULL);
  gpio_free (PIN_A_GPIO);
}
module_init (hello_interrupts_start);
module_exit (hello_interrupts_end);
MODULE_AUTHOR("000");
MODULE_DESCRIPTION("A sample driver using interrupts");
MODULE_LICENSE("GPL");


四、  程序使用的函数分析
1、 retval = gpio_request_one(PIN_A_GPIO, PIN_A_FLAGS, PIN_A_LABEL);
申请一个单独的GPIO,使用flag作为初始参数,函数原型为:
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label); 
flag用来配置下面的特性:
 * GPIOF_DIR_IN          - 配置方向为输入
 * GPIOF_DIR_OUT         -配置方向为输出
 * GPIOF_INIT_LOW    - 做输出引脚,输出低电平
  * GPIOF_INIT_HIGH   - 做输出引脚,输出高电平
Label貌似为名称


2、 gpio_to_irq
原型为:int gpio_to_irq(unsigned gpio);
将GPIO引脚号映射为IRQ号
3、 request_irq
申请IRQ,原型为int   request_irq(unsigned int irq , irq_handler_t hander , unsigned long irqflags , 
                              Const char *devname , void *dev_id )
Irq为申请的中断号
Handler 为向系统登记的中断处理函数,dev_id为传递给该函数的参数
Irqflags为中断处理属性。具体如下:
    IRQF_TRIGGER_RISING上升沿触发 、IRQF_TRIGGER_FALLING下降沿触发 、 IRQF_TRIGGER_HIGH高电平触发 、 IRQF_TRIGGER_LOW低电平触发,dev_id一般设置为NULL
4、 irq_set_irq_type
设置中断触发类型,函数原型为int set_irq_type(unsigned int irq, unsigned int type)
  #define IRQ_TYPE_NONE           0x00000000     未指明类型
    #define IRQ_TYPE_EDGE_RISING    0x00000001     上升沿触发
    #define IRQ_TYPE_EDGE_FALLING   0x00000002     下降沿触发
    #define IRQ_TYPE_EDGE_BOTH      (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
    #define IRQ_TYPE_LEVEL_HIGH     0x00000004     高电平触发
    #define IRQ_TYPE_LEVEL_LOW      0x00000008     低电平触发
    #define IRQ_TYPE_SENSE_MASK     0x0000000f    
    #define IRQ_TYPE_PROBE          0x00000010 

5、 free_irq 释放中断
6、 gpio_free释放之前申请的GPIO


五、测试
 将驱动编译加载后,驱动即运行,中断程序也随之启动,通过查看内核输出(dmesg –k查看),即可看到内核的所有输出,包括驱动加载是的输出以及中断触发是的输出信息,至此,中断测试成功。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章