Linux中断调试小结

在Linux中使用中断没什么要特别注意的,但最近调一个中断很苦恼,特总结一下。程序上将中断配置好了,打印信息上也没有报错,程序上将该引脚配置成双边沿触发中断,通过cat /proc/interrupts一直没有看到中断触发。拿示波器测量该引脚电平,一是低电平,发现硬件上拉不高该引脚电平,断开io引脚与外部电路的连接,测量外部电路的电压正常,怀疑是gpio内部的设置导致的,该引脚本来的功能是uim2卡的引脚(qcom不建议使用该引脚,默认modem端控制),怀疑是该引脚的配置问题,按照qcom提供的方法,将uim2关掉就可以将该引脚当做普通io使用。配置后,还是出现同样的情况。于是,将该引脚强制接到1.8v上,检测到了中断。这样很明显就是硬件的问题了。后来,硬件那边通过修改电阻,该问题得以解决。

可通过如下方法查看中断发生的次数

adb shell cat /proc/interrupts,如

这里的cpu是4核的,但这里只显示了其中的3个核的中断数,这是因为函数的实现是只显示在线的cpu的中断。

int show_interrupts(struct seq_file *p, void *v)
{
	static int prec;

	unsigned long flags, any_count = 0;
	int i = *(loff_t *) v, j;
	struct irqaction *action;
	struct irq_desc *desc;

	if (i > ACTUAL_NR_IRQS)
		return 0;

	if (i == ACTUAL_NR_IRQS)
		return arch_show_interrupts(p, prec);

	/* print header and calculate the width of the first column */
	if (i == 0) {
		for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec)
			j *= 10;

		seq_printf(p, "%*s", prec + 8, "");
		for_each_online_cpu(j)
			seq_printf(p, "CPU%-8d", j);
		seq_putc(p, '\n');
	}

	irq_lock_sparse();
	desc = irq_to_desc(i);
	if (!desc)
		goto outsparse;

	raw_spin_lock_irqsave(&desc->lock, flags);
	for_each_online_cpu(j)
		any_count |= kstat_irqs_cpu(i, j);
	action = desc->action;
	if (!action && !any_count)
		goto out;

	seq_printf(p, "%*d: ", prec, i);
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));

	if (desc->irq_data.chip) {
		if (desc->irq_data.chip->irq_print_chip)
			desc->irq_data.chip->irq_print_chip(&desc->irq_data, p);
		else if (desc->irq_data.chip->name)
			seq_printf(p, " %8s", desc->irq_data.chip->name);
		else
			seq_printf(p, " %8s", "-");
	} else {
		seq_printf(p, " %8s", "None");
	}
	if (desc->irq_data.domain)
		seq_printf(p, " %*d", prec, (int) desc->irq_data.hwirq);
#ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL
	seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge");
#endif
	if (desc->name)
		seq_printf(p, "-%-8s", desc->name);

	if (action) {
		seq_printf(p, "  %s", action->name);
		while ((action = action->next) != NULL)
			seq_printf(p, ", %s", action->name);
	}

	seq_putc(p, '\n');
out:
	raw_spin_unlock_irqrestore(&desc->lock, flags);
outsparse:
	irq_unlock_sparse();
	return 0;
}

假设这里的中断号是157,只需

root@www:/home/w/桌面# adb shell cat /proc/irq/157/spurious
count 65
unhandled 0
last_unhandled 0 ms

可以看出该中断一共发生了65次。

当然,也可以通过脚本自动打印中断的次数(每隔1s打印一次)

test.sh

while true;echo -e "\n";do adb shell cat /proc/irq/中断号/spurious;sleep 1;done

中断的使用方法

#include <linux/irq.h>
#include <linux/interrupt.h>
#define PIN_NAME "pin"
#define PIN_IRQ_NAME "pin_irq"

static irqreturn_t pin_interrupt_hander(int irq, void *dev_id)
{
       return IRQ_HANDLED;
}

void request_pin_irq(void)
{
    int ret;
    int pin=106;
    int irq;
    ret = gpio_request(pin, PIN_NAME);
    if (ret) {
		pr_err("Requesting GPIO %d failed!\n",pin);
		goto err;
    }
    irq = gpio_to_irq(pin); 
	if(!irq)
		goto err2;
    ret = request_irq(irq, pin_interrupt_hander,flags,PIN_IRQ_NAME, NULL);
	if(ret<0)
		goto err2;
	pr_err("Requesting IRQ %d,IRQ %d succeed!\n",pin,irq);
	return;
err2:
	gpio_free(pin);
err:
	return;
}

flags可选值 

/*
 * These correspond to the IORESOURCE_IRQ_* defines in
 * linux/ioport.h to select the interrupt line behaviour.  When
 * requesting an interrupt without specifying a IRQF_TRIGGER, the
 * setting should be assumed to be "as already configured", which
 * may be as per machine or firmware initialisation.
 */
#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

/*
 * These flags used only by the kernel as part of the
 * irq handling routines.
 *
 * IRQF_SHARED - allow sharing the irq among several devices
 * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur
 * IRQF_TIMER - Flag to mark this interrupt as timer interrupt
 * IRQF_PERCPU - Interrupt is per cpu
 * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing
 * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
 *                registered first in an shared interrupt is considered for
 *                performance reasons)
 * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
 *                Used by threaded interrupts which need to keep the
 *                irq line disabled until the threaded handler has been run.
 * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend.  Does not guarantee
 *                   that this interrupt will wake the system from a suspended
 *                   state.  See Documentation/power/suspend-and-interrupts.txt
 * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set
 * IRQF_NO_THREAD - Interrupt cannot be threaded
 * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device
 *                resume time.
 * IRQF_COND_SUSPEND - If the IRQ is shared with a NO_SUSPEND user, execute this
 *                interrupt handler after suspending interrupts. For system
 *                wakeup devices users need to implement wakeup detection in
 *                their interrupt handlers.
 */
#define IRQF_SHARED		0x00000080
#define IRQF_PROBE_SHARED	0x00000100
#define __IRQF_TIMER		0x00000200
#define IRQF_PERCPU		0x00000400
#define IRQF_NOBALANCING	0x00000800
#define IRQF_IRQPOLL		0x00001000
#define IRQF_ONESHOT		0x00002000
#define IRQF_NO_SUSPEND		0x00004000
#define IRQF_FORCE_RESUME	0x00008000
#define IRQF_NO_THREAD		0x00010000
#define IRQF_EARLY_RESUME	0x00020000
#define IRQF_COND_SUSPEND	0x00040000

#define IRQF_TIMER		(__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)

gpio_to_irq函数在不同上会有差异,有些平台上没有实现。需要在dts添加节点信息,通过
irq_of_parse_and_map函数将gpio号转换成虚拟中断号。

总结如下

1.无法申请中断  gpio占用/申请的触发方式不支持
2.休眠后中断无法使用 参考https://blog.csdn.net/mike8825/article/details/98473014
3.无法检测到中断(cat /proc/interrupts看次数)  gpio配置/硬件连接等

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值