2016-08-12 2 views
1

Я бы хотел написать драйвер с открытым исходным кодом для управления шаговыми двигателями в Linux. В этом случае, особенно для 3D-принтеров.ARM A7 Возможно использование прерывания Linux без прерывания?

Основная идея заключается в том, что водитель резервирует контакты на одном порту ввода-вывода, а затем управляет этими контактами одновременно. Он получает буфер, полный «переключать это, переключать эти» значения, а затем испускает их на порт, используя аппаратный таймер.

Теперь возникает вопрос: есть ли способ обработать конкретное аппаратное прерывание как можно быстрее?

Этот чип является Allwinner H3, и я использую ресурс TMR1 указанного чипа (IRQ 51). Я могу использовать это просто отлично, и она работает как прерывание, а также:

static irqreturn_t stepCore_timer_interrupt(int irq, void *dev_id) 
{ 
     writel(TMR1_IRQ_PEND, TMR_IRQ_ST_VREG); 
     icnt++; 

     porta_state = readl(PA_VDAT); 
     porta_state &= porta_mask; 

     if(icnt & 0x00000001) 
     { 
      porta_state |= 0x00000001; 
     } 

     writel(porta_state, PA_VDAT); 

     return IRQ_HANDLED; 
} 

static struct irqaction stepCore_timer_irq = { 
     .name = "stepCore_timer", 
     .flags = IRQF_DISABLED | IRQF_NOBALANCING , IRQF_PERCPU, 
     .handler = stepCore_timer_interrupt, 
     .dev_id = NULL, 
}; 

static void stepCore_timer_interrupt_setup(void) 
{ 
    int ret; 
    u32 val; 

    writel(24000000, TMR1_INTV_VALUE_VREG); 
    writel((TMR1_MODE_CONTINUOUS | TMR1_CLK_PRES_1 | TMR1_CLK_SRC_OSC24M), TMR1_CTRL_VREG); 

    ret = setup_irq(SUNXI_IRQ_TIMER1, &stepCore_timer_irq); 
    if (ret) 
      printk("%s: ERROR: failed to install irq %d\n", __func__, SUNXI_IRQ_TIMER1); 
    else 
      printk("%s: irq %d installed\n", __func__, SUNXI_IRQ_TIMER1); 

    ret = irq_set_affinity_hint(SUNXI_IRQ_TIMER1, cpumask_of(3)); 
    if (ret) 
      printk("%s: ERROR: failed to set irq affinity for irq %d\n", __func__, SUNXI_IRQ_TIMER1); 
    else 
      printk("%s: set irq affinity for irq %d\n", __func__, SUNXI_IRQ_TIMER1); 
    /* Enable timer0 interrupt */ 
    val = readl(TMR_IRQ_EN_VREG); 
    writel(val | TMR1_IRQ_EN, TMR_IRQ_EN_VREG); 

} 

TMR1 иначе неиспользованная (на самом деле, я должен был добавить это сам) и до сих пор работает. Однако в обработке довольно простой процедуры IRQ достаточно задержки. Поскольку я хочу создать код, который можно использовать для 3D-принтера, мне очень нравится более «стабильное» прерывание таймера.

Итак, мой вопрос: есть ли способ иметь очень короткую процедуру IRQ в Linux, которая имеет наивысший возможный приоритет? Или даже не заботится о планировщике Linux вообще, и просто «делает это»? В основном, обработчик IRQ, игнорируя то, что Linux думает, что это должно быть?

Ядро, с которым оно работает, предназначено именно для этой задачи. Обработчик будет как можно короче: выберете u32 из массива, напишите его в порт, сделайте.

Желательно, чтобы у меня было что-то, что просто игнорирует остальную часть Linux. Да, я знаю, что это не способ сделать это. Но это предназначено для довольно частного случая, поэтому у меня нет проблем с адаптацией регулярных исходных ядер для удовлетворения этих потребностей.

О, это напоминает мне, ядро ​​3.4.112 с подходящими исправлениями.

Любая помощь очень ценится.

Привет,

Chris

+0

Вы посмотрели ядро ​​RTAI? Thet накопители, такие как linux-cnc, и должны легко справляться с вашими требованиями времени. – tofro

+0

Я нашел referneces для ядра RTAI, да. Но довольно печальная проблема заключается в том, что материал для чипов Allwinner частично присутствует в основном ядре. Th H3 там не существует. Таким образом, я должен исправлять себя через старое ядро ​​3.4.39, которое я встал до 3.4.112, а затем до версии preempt-rt. – ChrisK

+0

Кроме того, у меня нет необходимости в некоторых сложных функциональных возможностях RT. Все, что я хочу (если это возможно), - это то, что один IRQ в GIC обрабатывается на голом металле. В этом случае IRQ 51 (для TMR1), практически не взаимодействующий с ядром. – ChrisK

ответ

0

Вот общее решение этого вопроса. Вы можете написать модуль ядра, который перезапишет существующую процедуру обработки прерываний и будет заменен вашей собственной процедурой, где вы сможете обработать свой интерес и перенаправить все irq в существующую процедуру обработки прерываний ядра. Возможно, для x86-арки вы получите инструкции CPU низкого уровня, чтобы получить существующий адрес процедуры описания прерываний (lidt). Я считаю, что это тоже возможно для ARM. Теперь у Linux есть технология изоляции ЦП isolcpus, используя эту технику, вы можете вывести CPU из домена планировщика, то есть никакая задача не будет запланирована на этом конкретном ЦП, пока вы не укажете задачу, которая будет выполняться на этом конкретном ЦПУ (с использованием набора задач). После того, как вы выберете CPU из домена планировщика, вы можете воспользоваться техникой аффинного прерывания для этого изолированного процессора, вы можете сделать это через /proc/irq/IRQ_NUMBER/smp_affinity. Теперь все ваши прерывания будут обрабатываться этим изолированным процессором и 100% предназначены для этого прерывания. И с вашей собственной процедурой IRQ у вас есть полный контроль над обработкой прерываний.

Надеюсь, это поможет!

Смежные вопросы