2016-08-12 140 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例程,您可以完全控制中斷處理。

希望這會有所幫助!