2016-08-12 4 views
1

Linux에서 스테퍼 모터를 제어하기 위해 오픈 소스 코어 드라이버를 작성하고 싶습니다. 이 경우, 특히 3D 프린터의 경우.ARM A7 Linux 원시 인터럽트 처리가 가능합니까?

기본 아이디어는 드라이버가 하나의 IO 포트에 핀을 예약 한 다음 해당 핀을 한 번에 조작한다는 것입니다. 하드웨어 타이머를 사용하여 "this toggle this, toggle that"값으로 가득 찬 버퍼를 수신 한 다음 포트로 방출합니다.

이제 질문은 : 가능한 한 빨리 특정 하드웨어 인터럽트를 처리 할 수있는 방법이 있습니까?

해당 칩이 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 프린터에서 사용할 수있는 코드를 만들고 싶기 때문에 나는 더 "안정적인"타이머 인터럽트를 매우 좋아합니다.

내 질문은 : 가능한 가장 높은 우선 순위가있는 리눅스에서 매우 짧은 IRQ 루틴을 가질 수있는 방법이 있습니까? 또는 Linux 스케줄러에 전혀 신경 쓰지 않고 "그냥 할 수 있습니까?" 기본적으로 원시 IRQ 처리기입니다. Linux가해야한다고 생각하는 것을 무시합니까?

실행되는 코어는 어쨌든 그 작업에만 사용됩니다. 핸들러는 가능한 한 짧을 것입니다. 배열에서 u32를 가져 와서 포트에 쓰고 완료하십시오.

바람직하게는 나머지 리눅스를 모두 무시하고 싶습니다. 네, 그게 그렇게 할 방법이 아니라는 것을 압니다. 그러나 이는 특별한 경우를위한 것이므로, 그러한 요구에 맞게 정규 커널 소스를 채택하는 것에 대해 아무런 불만이 없습니다.

아, 저에게 상기 커널은 3.4.112와 적절한 선점 패치가 있음을 상기시켜줍니다.

도움을 주시면 대단히 감사하겠습니다.

인사말,

크리스 여기

+0

RTAI 커널을 보았습니까? Thet는 linux-cnc와 같은 도구를 사용하며 타이밍 요구 사항에 쉽게 대처해야합니다. – tofro

+0

RTAI 커널에 대한 참조를 발견했습니다. 그러나 다소 슬픈 이슈는 Allwinner 칩을위한 것들이 부분적으로 주류 커널에만 있다는 것입니다. Th H3는 존재하지 않습니다. 따라서, 나는 3.4.39 커널까지 패치를해야한다. 커널은 3.4.112까지 올라 갔고, 그 다음에는 preempt-rt 버전까지 올라 갔다. – ChrisK

+0

또한 정교한 RT 기능이 필요하지 않습니다. 내가 원한다면 (심지어 가능하다면) GIC의 IRQ 하나가 베어 메탈에서 처리된다는 것입니다. 이 경우 IRQ 51 (TMR1의 경우)은 커널 상호 작용이 거의 없거나 전혀 없습니다. – ChrisK

답변

0

이 문제에 대한 일반적인 솔루션입니다. 기존 인터럽트 처리 루틴을 덮어 쓸 커널 모듈을 작성할 수 있으며, 관심있는 irq를 처리하고 모든 irq를 기존 커널 인터럽트 처리 루틴으로 리디렉션 할 수있는 자신의 루틴으로 바뀝니다. 저수준 CPU 명령을 사용하여 인터럽트 설명 루틴 (lidt)의 기존 주소를 가져 오는 x86 arch의 경우 가능합니다. 나는 그것이 ARM에서도 가능해야한다고 생각한다. 리눅스는 CPU 격리 기술을 가지고 있습니다.이 기술을 활용하면 스케줄러 도메인 밖으로 CPU를 가져갈 수 있습니다. 즉, 태스크 세트를 사용하여 특정 CPU에서 실행할 태스크를 지정할 때까지 특정 CPU에서 태스크가 스케줄되지 않습니다. CPU를 스케줄러 도메인 밖으로 가져온 후에는 격리 된 CPU에 인터럽트를 연결하는 기술을 활용할 수 있습니다. /proc/irq/IRQ_NUMBER/smp_affinity을 통해이 작업을 수행 할 수 있습니다. 이제 모든 인터럽트는이 격리 된 CPU에 의해 처리되고 100 %는 해당 인터럽트 전용으로 처리됩니다. IRQ 루틴을 사용하면 인터럽트 처리를 완벽하게 제어 할 수 있습니다.

잘하면이 도움이 될 것입니다!

관련 문제