2016-08-12 138 views
1

我想写一个开源的核心驱动程序来控制Linux中的步进电机。在这种情况下,尤其是3D打印机。ARM A7 Linux原始中断处理可能吗?

其基本思想是驱动程序在一个IO端口上预留引脚,然后一次操作这些引脚。它接收一个缓冲区,其中充满了“切换该值,切换该值”,然后使用硬件定时器将这些值发送到端口。

现在的问题是:有没有办法尽可能快地处理特定的硬件中断?

该问题的芯片是Allwinner H3,而且我正在使用该芯片(IRQ 51)的TMR1资源。我可以用它蛮好的,它可以作为一个中断,以及:

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打印机的代码,我非常喜欢更“稳定”的定时器中断。

所以,我的问题是:有没有办法在Linux中有一个非常短的IRQ例程具有最高优先级?甚至根本不关心Linux调度器,只是“这是事情”?基本上是一个原始的IRQ处理程序,忽略了Linux认为它应该是什么?

它运行的核心专用于完成该任务。处理程序将尽可能短:从数组中取出一个u32,将其写入端口,完成。

最好我想拥有一些只是忽略了Linux的其余部分。是的,我知道那不是做这件事的方法。但这是为了一个相当特殊的情况,所以我毫不犹豫地调整了常规内核源以适应这些需求。

哦,这提醒了我,内核是3.4.112与适当的抢占rt补丁。

任何帮助,非常感谢。

问候,

克里斯

+0

你看过RTAI内核吗? Thet驱动像linux-cnc这样的东西,并且应该很容易地满足你的时序要求。 – tofro

+0

我发现引用了RTAI内核,是的。但令人悲伤的问题是,Allwinner芯片的功能仅部分在主流内核中。那里H3不存在。因此,我必须通过旧的3.4.39内核补丁,然后到3.4.112,然后达到抢先版本。 – ChrisK

+0

此外,我不需要一些复杂的RT功能。我想要的(如果可能的话)是GIC中的一个IRQ是在裸机上处理的。在这种情况下,IRQ 51(对于TMR1)几乎没有任何内核交互。 – ChrisK

回答

0

下面是对这个问题的通用解决方案。您可以编写一个内核模块来覆盖现有的中断处理例程,并由您自己的例程替换,您可以在其中处理感兴趣的irq,并将所有irq重定向到现有的内核中断处理例程。 x86 arch可能会得到低级CPU指令来获取中断描述例程的现有地址(lidt)。我相信它也应该可以用于ARM。现在,Linux具有CPU隔离技术isolcpus,通过使用这种技术,您可以将CPU从调度程序域中取出,即在您指定要在该特定CPU上运行的任务(使用taskset)之前,不会在该特定CPU上调度任何任务。将CPU从调度程序域中取出后,可以利用对该隔离CPU仿造中断的技术,可以通过/proc/irq/IRQ_NUMBER/smp_affinity来完成。现在所有的中断都将由该隔离CPU处理,并且100%专用于该中断。通过您自己的IRQ例程,您可以完全控制中断处理。

希望这会有所帮助!