Linux中断

1、预备知识

1.1、中断号

  中断号也叫中断线,每个中断都有一个中断号,通过中断号即可区分不同的中断。Linux 内核中使用一个 int 变量表示中断号。

2、中断API函数

2.1、获取设备号

gpio_to_irq函数

int gpio_to_irq(unsigned int gpio)

gpiod_to_irq函数

int gpiod_to_irq(const struct gpio_desc *desc)

2.2、申请中断

/**
 *	request_threaded_irq - allocate an interrupt line
 *	@irq: Interrupt line to allocate
 *	@handler: Function to be called when the IRQ occurs.
 *		  Primary handler for threaded interrupts
 *		  If NULL and thread_fn != NULL the default
 *		  primary handler is installed
 *	@flags: Interrupt type flags
 *	@name: An ascii name for the claiming device
 *	@dev: A cookie passed back to the handler function
 */
int request_irq(unsigned int irq, 
				irq_handler_t handler, 
				unsigned long flags,
	    		const char *name, 
	    		void *dev)
  • 中断处理函数

 作用:当中断发生以后就会执行此中断处理函数
 格式:irqreturn_t (*irq_handler_t)(int, void *);

  • flag
标志描述
IRQF_SHARED多个设备共享一个中断线,共享的所有中断都必须指定此标志。如果使用共享中断的话,request_irq 函数的 dev 参数就是唯一区分他们的标志
IRQF_ONESHOT单次中断,中断执行一次就结束
IRQF_TRIGGER_NONE无触发
IRQF_TRIGGER_RISING上升沿触发
IRQF_TRIGGER_FALLING下降沿触发
IRQF_TRIGGER_HIGH高电平触发
IRQF_TRIGGER_LOW低电平触发
  • dev

1、如果将 flags 设置为 IRQF_SHARED 的话,dev 用来区分不同的中断。
2、一般情况下将dev 设置为设备结构体,dev 会传递给中断处理函数 irq_handler_t 的第二个参数。

2.3、释放中断

/**
 *	free_irq - free an interrupt allocated with request_irq
 *	@irq: Interrupt line to free
 *	@dev_id: Device identity to free
 */
void free_irq(unsigned int irq, void *dev_id)
  • irq:要释放的中断号。
  • dev:如果中断设置为共享(IRQF_SHARED)的话,此参数用来区分具体的中断。

2.4、中断使能与禁止

/**
 *	enable_irq - enable handling of an irq
 *	@irq: Interrupt to enable
 */
void enable_irq(unsigned int irq)
/**
 *	disable_irq - disable an irq and wait for completion
 *	@irq: Interrupt to disable
 */
void disable_irq(unsigned int irq)

3、中断实例

实现内容:
  按下按键触发中断,在中断服务函数中打印触发次数。

  • 设备树
my_key {
	compatible = "my_key";	
	status = "okay";
	pinctrl_names = "default";
	pinctrl-0 = <&pinctrl_key>;
	key-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>;

	/* 中断相关 */
	interrupt-parent = <&gpio1>;
	interrupt = <18 IRQ_TYPE_EDGE_BOTH>;
};
  • 驱动
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>

struct key_type
{
    struct gpio_desc *gpio;
    int irq;
};

struct key_type key_cdev;

/**
 * @brief 中断回调函数
 * 
 */
irqreturn_t key_irq_handler(int irq, void *data)
{
    static int counter = 0;

    /* 打印触发中断次数 */
    printk("key_irq_handler: %d\n", counter);
    counter++;

    return IRQ_RETVAL(IRQ_HANDLED);
}

/**
 * @brief platform驱动-probe函数
 * 
 */
int key_probe(struct platform_device *pdev)
{
    int ret;

    /* 1、获取GPIO */
    key_cdev.gpio = devm_gpiod_get(&pdev->dev, "key", GPIOD_IN);

    /* 2、获取中断号并申请中断 */
    key_cdev.irq = gpiod_to_irq(key_cdev.gpio);
    ret = request_irq(key_cdev.irq, key_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "my_key_irq", &key_cdev);

    return 0;
}

/**
 * @brief platform驱动-remove函数
 * 
 */
int key_remove(struct platform_device *pdev)
{
    /* 释放中断 */
    free_irq(key_cdev.irq, &key_cdev);

    return 0;
}

/**
 * @brief 匹配列表
 * 
 */
struct of_device_id key_match_table[] = {
    {.compatible = "my_key"},
};

/**
 * @brief platform驱动
 * 
 */
struct platform_driver key_itr_driver = {
    .driver = {
        .name = "my_key",
        .of_match_table = key_match_table,
    },
    .probe = key_probe,
    .remove = key_remove,
};

/* 注册平台驱动 */
module_platform_driver(key_itr_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LSW");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vis-Lin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值