我在运行带有 CONFIG_PREEMPT_RT 补丁的 linux 内核 (3.8.13) 的飞思卡尔 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 映射寄存器并使用直接内存写入触发输出是否更有效?
有什么方法可以提高中断的优先级吗?或者我可以在数据传输期间(约 400 毫秒)以某种方式锁定内核,并以其他方式生成我的输出时间吗?
编辑:忘记在问题中添加 /proc/interrupts 输出...