简单平安 发表于 2017-3-17 11:21:54

RT-Thread中龙芯1C的中断支持不全

RT-Thread的V2.1.0版本中,对龙芯1C的中断支持不全。先来看一下中断分发函数rt_interrupt_dispatch()

void rt_interrupt_dispatch(void *ptreg)
{
    int irq;
    void *param;
    rt_isr_handler_t irq_func;
    static rt_uint32_t status = 0;
    rt_uint32_t c0_status;
    rt_uint32_t c0_cause;
    volatile rt_uint32_t cause_im;
    volatile rt_uint32_t status_im;
    rt_uint32_t pending_im;

    /* check os timer */
    c0_status = read_c0_status();
    c0_cause = read_c0_cause();

    cause_im = c0_cause & ST0_IM;
    status_im = c0_status & ST0_IM;
    pending_im = cause_im & status_im;

    if (pending_im & CAUSEF_IP7)
    {
      rt_hw_timer_handler();
    }

    if (pending_im & CAUSEF_IP2)
    {
      /* the hardware interrupt */
      status = ls1c_hw0_icregs->int_isr;
      if (!status)
            return;

      for (irq = MAX_INTR; irq > 0; --irq)
      {
            if ((status & (1 << irq)))
            {
                status &= ~(1 << irq);

                irq_func = irq_handle_table.handler;
                param = irq_handle_table.param;

                /* do interrupt */
                irq_func(irq, param);

#ifdef RT_USING_INTERRUPT_INFO
                irq_handle_table.counter++;
#endif /* RT_USING_INTERRUPT_INFO */

                /* ack interrupt */
                ls1c_hw0_icregs->int_clr |= (1 << irq);
            }
      }
    }
    else if (pending_im & CAUSEF_IP3)
    {
      rt_kprintf("%s %d\r\n", __FUNCTION__, __LINE__);
    }
    else if (pending_im & CAUSEF_IP4)
    {
      rt_kprintf("%s %d\r\n", __FUNCTION__, __LINE__);
    }
    else if (pending_im & CAUSEF_IP5)
    {
      rt_kprintf("%s %d\r\n", __FUNCTION__, __LINE__);
    }
    else if (pending_im & CAUSEF_IP6)
    {
      rt_kprintf("%s %d\r\n", __FUNCTION__, __LINE__);
    }
}
在fi分支的CAUSEF_IP3,CAUSEF_IP4,CAUSEF_IP5,CAUSEF_IP6中用到了函数rt_kprintf()打印提示消息。可是这是在中断中,用打印函数欠妥吧。这还不是关键,关键是在if的CAUSEF_IP2分支中,变量irq_handle_table的大小为32,如下

也就是说,最多只支持32个中断,可是龙芯1C上GPIO都不止32个,每个GPIO都支持输入中断,即每个GPIO都有一个中断,那还有其它的串口中断,网口等等。
可是问题出在哪里呢?在参考了《龙芯1C处理器用户手册》V1.3、《see mips run 中文版》第二版、《mips linux异常中断代码分析》和linux源码之后,得到如下结论,龙芯1C有五组中断,每组32个,分别对应CAUSEF_IP2,CAUSEF_IP3,CAUSEF_IP4,CAUSEF_IP5,CAUSEF_IP6。
linux中对应源码

static void ls1x_irq_dispatch(int n)
{
        u32 intstatus, irq;

        /* Receive interrupt signal, compute the irq */
        intstatus = (ls1x_icregs+n)->int_isr & (ls1x_icregs+n)->int_en;
        if (intstatus) {
                irq = ffs(intstatus);
                do_IRQ((n<<5) + irq - 1);
        }
}

asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
        unsigned int pending;

        pending = read_c0_cause() & read_c0_status() & ST0_IM;

        if (pending & CAUSEF_IP7) {
                do_IRQ(TIMER_IRQ);
        }
        else if (pending & CAUSEF_IP2) {
                ls1x_irq_dispatch(0);
        }
        else if (pending & CAUSEF_IP3) {
                ls1x_irq_dispatch(1);
        }
        else if (pending & CAUSEF_IP4) {
                ls1x_irq_dispatch(2);
        }
        else if (pending & CAUSEF_IP5) {
                ls1x_irq_dispatch(3);
        }
        else if (pending & CAUSEF_IP6) {
                ls1x_irq_dispatch(4);
        } else {
                spurious_interrupt();
        }
}
顺便还提一下,RT-Thread中函数rtthread_startup()里面拷贝的异常向量大小应该是0x80,不是0x20.即每个异常向量占0x80个字节。

linux中的代码如下








chinesebear 发表于 2017-3-17 13:23:12

:)分析精辟

简单平安 发表于 2017-3-17 16:46:50

smiletan 发表于 2017-3-17 16:19
强烈要求给一个开源龙芯1C的GPIO外部中断例子

我正在研究裸机下怎么实现中断,后面会写个测试例子来测试的,请关注http://git.oschina.net/caogos/OpenLoongsonLib1c

另外,在linux下应该很容易实现按键中断的,百度上应该有很多资料

简单平安 发表于 2017-7-24 11:34:32

git上最新的RT-Thread可以支持所有中断了,包括GPIO中断。
https://github.com/RT-Thread/rt-thread

yzwguet 发表于 2017-7-25 20:55:51

膜拜!向大神致敬!

ratking 发表于 2017-7-26 08:53:21

龙芯1C有五组中断,每组32个。
感谢版主的钻研与分享!
页: [1]
查看完整版本: RT-Thread中龙芯1C的中断支持不全