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 によって作成されます)。割り込みとして機能する 74kHz のパルスを生成するように PWM を設定しました。次に、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 出力を質問に追加するのを忘れました...