linux gpio中断

最近用到gpio中断,gpio中断也是嵌入式系统用的比较多的。

对于GPIO操作 linux 有一套标准的 API,set value、get value之类的,当然也有关于中断的。


关于中断的就是:

static inline int gpio_to_irq(unsigned int gpio)
{
	return __gpio_to_irq(gpio);
}


1 使用gpio中断


在linux模块中使用gpio中断的步骤通常如下


1)实现中断处理函数。

static irqreturn_t myIntHandler(int irq, void *dev_id)
{
	printk("Interrupt IN\n");
	return IRQ_HANDLED
}

2)初始化函数

int xxx_init()
{

	int ret, irqno;
	ret = gpio_request(gpioNo, "mygpiopin");
	if(ret){
		printk("irq pin request io failed.\n");
		return -1;
	}

	irqno= gpio_to_irq(gpioNo);


	ret = request_irq(irqno,myIntHandler , RQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, "myinterrupt", NULL); 
	if(ret) {
		printk(KERN_ERR "can not get irq\n");
		return ret;
	} 
}
就两个函数:
gpio_request  通常用来检测这个gpio是否可用,是否已经在使用了。

gpio_to_irq 转换gpio编号到对应irq号。

之后就是熟悉的request_irq

有时候还会加一个gpio_is_valid,判断一下gpioNo是否合理,通常自己察看芯片手册填入正确gpio number,不需要再再在这里判断一下。

2,gpio中断API的实现过程

简单看一下。

int gpio_request(unsigned gpio, const char *label)
{
	return gpiod_request(gpio_to_desc(gpio), label);
}

先看参数
gpio_to_desc(gpio)

都在gpiolib.c中

static struct gpio_desc *gpio_to_desc(unsigned gpio)
{
	if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio))
		return NULL;
	else
		return &gpio_desc[gpio];
}


这里有个全局的数组,看样子是每一个gpio都在这个数组里有这么一项,这个结构体如下

struct gpio_desc {
	struct gpio_chip	*chip;
	unsigned long		flags;
/* flag symbols are bit numbers */
#define FLAG_REQUESTED	0
#define FLAG_IS_OUT	1
#define FLAG_EXPORT	2	/* protected by sysfs_lock */
#define FLAG_SYSFS	3	/* exported via /sys/class/gpio/control */
#define FLAG_TRIG_FALL	4	/* trigger on falling edge */
#define FLAG_TRIG_RISE	5	/* trigger on rising edge */
#define FLAG_ACTIVE_LOW	6	/* sysfs value has active low */
#define FLAG_OPEN_DRAIN	7	/* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 8	/* Gpio is open source type */

#define ID_SHIFT	16	/* add new flags before this one */

#define GPIO_FLAGS_MASK		((1 << ID_SHIFT) - 1)
#define GPIO_TRIGGER_MASK	(BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))

#ifdef CONFIG_DEBUG_FS
	const char		*label;
#endif
};
主要就是有个 struct gpio_chip类型的指针

回到gpiod_request,其他代码先忽略,主要就两句,就是我加注释的地方

static int gpiod_request(struct gpio_desc *desc, const char *label)
{
	struct gpio_chip	*chip;
	int			status = -EPROBE_DEFER;
	unsigned long		flags;

	if (!desc) {
		pr_warn("%s: invalid GPIO\n", __func__);
		return -EINVAL;
	}

	spin_lock_irqsave(&gpio_lock, flags);

	chip = desc->chip;//取得desc中的struct gpio_chip.
	if (chip == NULL)
		goto done;

	if (!try_module_get(chip->owner))
		goto done;

	/* NOTE:  gpio_request() can be called in early boot,
	 * before IRQs are enabled, for non-sleeping (SOC) GPIOs.
	 */

	if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
		desc_set_label(desc, label ? : "?");
		status = 0;
	} else {
		status = -EBUSY;
		module_put(chip->owner);
		goto done;
	}

	if (chip->request) {
		/* chip->request may sleep */
		spin_unlock_irqrestore(&gpio_lock, flags);
		status = chip->request(chip, gpio_chip_hwgpio(desc));//调用desc[gpio]-〉chip-〉request
		spin_lock_irqsave(&gpio_lock, flags);

		if (status < 0) {
			desc_set_label(desc, NULL);
			module_put(chip->owner);
			clear_bit(FLAG_REQUESTED, &desc->flags);
			goto done;
		}
	}
	if (chip->get_direction) {
		/* chip->get_direction may sleep */
		spin_unlock_irqrestore(&gpio_lock, flags);
		gpiod_get_direction(desc);
		spin_lock_irqsave(&gpio_lock, flags);
	}
done:
	if (status)
		pr_debug("_gpio_request: gpio-%d (%s) status %d\n",
			 desc_to_gpio(desc), label ? : "?", status);
	spin_unlock_irqrestore(&gpio_lock, flags);
	return status;
}

chip-〉request有两个参数,一个是chip另一个是

/*
 * Return the GPIO number of the passed descriptor relative to its chip
 */
static int gpio_chip_hwgpio(const struct gpio_desc *desc)
{
	return desc - &desc->chip->desc[0];
}

看注释也很清楚,gpio号相对于它的chip的偏移。 看来这个struct gpio_chip非常重要,看看这个chip是在哪里赋值到gpio_desc[]这个数组的。
/**
 * gpiochip_add() - register a gpio_chip
 * @chip: the chip to register, with chip->base initialized
 * Context: potentially before irqs or kmalloc will work
 *
 * Returns a negative errno if the chip can't be registered, such as
 * because the chip->base is invalid or already associated with a
 * different chip.  Otherwise it returns zero as a success code.
 *
 * When gpiochip_add() is called very early during boot, so that GPIOs
 * can be freely used, the chip->dev device must be registered before
 * the gpio framework's arch_initcall().  Otherwise sysfs initialization
 * for GPIOs will fail rudely.
 *
 * If chip->base is negative, this requests dynamic assignment of
 * a range of valid GPIOs.
 */
int gpiochip_add(struct gpio_chip *chip)
{
..........略
	if (status == 0) {
		chip->desc = &gpio_desc[chip->base];

		for (id = 0; id < chip->ngpio; id++) {
			struct gpio_desc *desc = &chip->desc[id];
			desc->chip = chip;

			/* REVISIT:  most hardware initializes GPIOs as
			 * inputs (often with pullups enabled) so power
			 * usage is minimized.  Linux code should set the
			 * gpio direction first thing; but until it does,
			 * and in case chip->get_direction is not set,
			 * we may expose the wrong direction in sysfs.
			 */
			desc->flags = !chip->direction_input
				? (1 << FLAG_IS_OUT)
				: 0;
		}
	}

..............略

}

在这个函数里面全局数组gpio_desc被一一赋值了。

而这个gpiochip_add会在底层芯片厂商各自的gpio初始化函数里调用。 位置通常在各厂商各自的gpio-xxx.c

struct gpio_chip也会在那里定义,通常与硬件寄存器相关,不做分析。


gpio_request完了,还有gpio_to_irq,其实是一样的,还是最终会调用,stuct gpio_chip中的to_irq。


反过来说bsp的编写者,初始化之后,只要实现stuct gpio_chip 再调用gpiochip_add,gpio的API就可以供用户使用了。






                
Linux GPIO中断驱动是一种用于在Linux系统中捕捉GPIO引脚中断事件的机制。当GPIO引脚的状态发生变化时,例如从低电平到高电平或从高电平到低电平,系统会自动触发中断,并执行相应的中断处理程序。中断处理程序可以是用户自定义的代码,用于响应GPIO引脚状态的变化并执行相应的操作。这种机制可以用于监测外部设备的状态变化,例如按钮按下、传感器触发等。通过配置中断驱动,可以实现对GPIO引脚中断事件的捕捉和处理。要使用Linux GPIO中断驱动,需要进行以下步骤:首先,通过gpio_to_irq函数将GPIO引脚转换为中断号。然后,在设备树中修改或添加中断节点,并配置中断触发方式和优先级。接下来,编译内核并更新系统。最后,编写用户控件程序来捕捉中断事件并执行相应的操作。通过在/sys/class/gpio目录下操作相应的GPIO引脚目录,可以设置引脚的方向和输出电平值。例如,使用echo命令将引脚暴露为可用接口,然后使用echo命令设置引脚方向为输出,再使用echo命令设置引脚输出电平值为高。通过编写测试代码,可以验证中断驱动的功能和正确性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Linux驱动开发——(使用中断处理)gpio(6)](https://blog.csdn.net/qq_37596943/article/details/103750860)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [linux GPIO中断使用说明 V1.02.pdf](https://download.csdn.net/download/u013497478/12745478)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [zynq操作系统: Linux驱动开发Gpio中断篇](https://blog.csdn.net/qq_42330920/article/details/115615688)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值