我在使用CONFIG_PREEMPT_RT补丁运行Linux内核(3.8.13)的Freescales imx.233上遇到了一点不一致的IRQ / ISR性能。 我有点惊讶为什么这个处理器(ARM9,454mhz)即使有74kHz的IRQ请求也无法跟上..?
在我的内核配置中,我设置了以下标志:
CONFIG_TINY_PREEMPT_RCU=y
CONFIG_PREEMPT_RCU=y
CONFIG_PREEMPT=y
CONFIG_PREEMPT_RT_BASE=y
CONFIG_HAVE_PREEMPT_LAZY=y
CONFIG_PREEMPT_LAZY=y
CONFIG_PREEMPT_RT_FULL=y
CONFIG_PREEMPT_COUNT=y
CONFIG_DEBUG_PREEMPT=y
在系统上基本没有运行(由buildroot创建),我设置PWM以产生74kHz的脉冲,用作中断。 然后在ISR中,我只触发另一个GPIO输出引脚,并检查输出。 我发现有时候我会错过一个中断 - 你可以在这里看到错过的中断:
而且输出引脚的触发似乎有点不一致,输出引脚通常在“5%窗口”内触发,这可能仍然可以接受。但我担心,当我开始实现数据传输逻辑时,我可能会遇到更多问题,而不仅仅是触发引脚......
我的简单驱动程序代码如下所示:
#needed includes
uint16_t INPUT_IRQ = 39;
uint16_t OUTPUT_GPIO = 38;
struct test_device *device;
//Prototypes
void irqtest_exit(void);
int irqtest_init(void);
void free_device(void);
//Default functions
module_init(irqtest_init);
module_exit(irqtest_exit);
//triggering flag
uint16_t pulse = 0x1;
irqreturn_t irq_handle_function(int irq, void *device_id)
{
pulse = !pulse;
gpio_set_value(OUTPUT_GPIO, pulse);
return IRQ_HANDLED;
}
struct test_device {
int huuhaa;
};
void free_device() {
if (device)
kfree(device);
}
int irqtest_init(void) {
int result = 0;
device = kmalloc(sizeof *device, GFP_KERNEL);
device->huuhaa = 10;
printk("IRB/irqtest_init: Inserting IRQ module\n");
printk("IRB/irqtest_init: Requesting GPIO (%d)\n", INPUT_IRQ);
result = gpio_request_one(INPUT_IRQ, GPIOF_IN, "PWM input");
if (result != 0) {
free_device();
printk("IRB/irqtest_init: Failed to set GPIO (%d) as input.. exiting\n", INPUT_IRQ);
return -EINVAL;
}
result = gpio_request_one(OUTPUT_GPIO, GPIOF_OUT_INIT_LOW , "IR OUTPUT");
if (result != 0) {
free_device();
printk("IRB/irqtest_init: Failed to set GPIO (%d) as output.. exiting\n", OUTPUT_GPIO);
return -EINVAL;
}
//Set our desired interrupt line as input
result = gpio_direction_input(INPUT_IRQ);
if (result != 0) {
printk("IRB/irqtest_init: Failed to set IRQ as input.. exiting\n");
free_device();
return -EINVAL;
}
//Set flags for our interrupt, guessing here..
irq_flags |= IRQF_NO_THREAD;
irq_flags |= IRQF_NOBALANCING;
irq_flags |= IRQF_TRIGGER_RISING;
irq_flags |= IRQF_NO_SOFTIRQ_CALL;
//register interrupt
result = request_irq(gpio_to_irq(INPUT_IRQ), irq_handle_function, irq_flags, "irq testing", device);
if (result != 0) {
printk("IRB/irqtest_init: Failed to reserve GPIO 38\n");
return -EINVAL;
}
printk("IRB/irqtest_init: insert success\n");
return 0;
}
void irqtest_exit(void) {
if (device)
kfree(device);
gpio_free(INPUT_IRQ);
gpio_free(OUTPUT_GPIO);
printk("IRB/irqtest_exit: Removing irqtest module\n");
}
int irqtest_open(struct inode *inode, struct file *filp) {return 0;}
int irqtest_release(struct inode *inode, struct file *filp) {return 0;}
在系统中,我在加载驱动程序后注册了以下中断:
# cat /proc/interrupts
CPU0
16: 36379 - MXS Timer Tick
17: 0 - mxs-spi
18: 2103 - mxs-dma
60: 0 gpio-mxs irq testing
118: 0 - mxs-spi
119: 0 - mxs-dma
120: 0 - RTC alarm
124: 0 - 8006c000.serial
127: 68050 - uart-pl011
128: 151 - ci13xxx_imx
Err: 0
我想知道我向IRQ申报的旗帜是否合适?我注意到,通过这种配置,我再也无法访问控制台了,所以现在内核似乎完全消耗了这个74kHz的触发器。这不可能是正确的吗? 我想这对我来说不是什么大问题,因为这只是在数据传输期间,但我仍然觉得我做错了什么..
另外,我想知道用ioremap映射寄存器是否更有效,并用直接内存写入触发输出?
是否有某种方法可以将中断的优先级提高到更高?或者我可以在数据传输期间以某种方式锁定内核(~400ms),并以某种方式生成我的输出时序吗?
编辑:忘记将/ proc / interrupts输出添加到问题...
答案 0 :(得分:3)
您在这里遇到的是中断抖动。这在Linux上是可以预期的,因为内核会定期禁用各种任务的中断(进入自旋锁,处理中断等)。
无论你是否有PREEMPT_RT,都会发生这种情况,所以期望用常规中断产生74kHz信号是非常不切实际的。
现在,ARM具有更高优先级的中断,称为FIQ,永远不会被屏蔽或禁用。
Linux不使用FIQ,并不是为了处理可以使用FIQ的事实而构建的,因此您将无法使用通用内核框架。
从Linux驱动程序开发的角度来看,只要记住这一点,它就没有什么不同:你必须编写一个处理程序,并将它与IRQ相关联。您还必须插入中断控制器,使其为您要使用的中断生成FIQ(有关如何更改它的详细信息取决于平台。某些平台具有执行此操作的功能(如imx25和mxc_set_irq_fiq) ,有些人没有.imx23 / 28没有,所以你必须手工完成。)
设置fiq处理程序的函数唯一可以使用汇编编写的处理程序,所以你必须在程序集中重写你的处理程序(使用当前的代码,但它应该是微不足道的。)
您可以在Alexandre发布的博客文章(http://free-electrons.com/blog/fiq-handlers-in-the-arm-linux-kernel/)中获取更多详细信息,在那里您可以找到有关它们如何协同工作的工作代码,示例和说明。
答案 1 :(得分:1)
你可以看看我的同事Maxime Ripard在类似的SoC(i.mx28)上使用FIQ所做的事情:
http://free-electrons.com/blog/fiq-handlers-in-the-arm-linux-kernel/
答案 2 :(得分:0)
试试这个标志:
int irq_flags;
...
irq_flags = IRQF_TRIGGER_RISING | IRQF_EARLY_RESUME
我有一个内核3.8.11并且找不到IRQF_NO_SOFTIRQ_CALL定义。它仅适用于3.8.13? 我也没有看到irq_flags定义。它在哪里?