• [转载].“君让臣死 臣不得不死 不死也得死”的NIOS II 9.1 SP1中断问题


    转自:http://www.cnblogs.com/crazybingo/archive/2011/04/03/2004477.html

        快死了,真的快死了,心死了,哀莫大于心死。。。

         因为调摄像头,其中有个模式是“fps切换”,需要用到PIO外部中断,但是以前没写过,反正当年用过51,应该挺简单的,结果,差点让我执行了想死的冲动。。。

         操蛋的代码一直死在中断初始化那边,一次又一次的压抑自己想死的冲动。

         首先NIOS 91用了增强型中断,当然这不是问题的关键,我不详说,看牙缝的博客:http://www.cnblogs.com/yuphone/archive/2010/05/13/1734712.html

         debug 进了中断n次看细节,无奈真想砸电脑,下面是alt_ic_arq_register() 原型以及内部的int alt_irq_register,我不知道为什么这就是所谓的增强型,听说是为了便于以后升级:

    2

    int alt_ic_isr_register(alt_u32 ic_id, alt_u32 irq, alt_isr_func isr, 
      void *isr_context, void *flags) 

        return alt_irq_register(irq, isr_context, isr); 

    int alt_irq_register (alt_u32 id, 
                          void* context, 
                          alt_isr_func handler) 

      int rc = -EINVAL;  
      alt_irq_context status;

      if (id < ALT_NIRQ) 
      { 
        /* 
         * interrupts are disabled while the handler tables are updated to ensure 
         * that an interrupt doesn't occur while the tables are in an inconsistant 
         * state. 
         */

        status = alt_irq_disable_all ();

        alt_irq[id].handler = handler; 
        alt_irq[id].context = context;

        rc = (handler) ? alt_irq_enable (id): alt_irq_disable (id);

        alt_irq_enable_all(status); 
      } 
      return rc; 
    }

         在群里大侠的帮助下,还是NND的不行。。。在与牙缝和o my god的共同协作下,还是不行。。。昏了

         最后不小心试试看是不是多路除了问题,然后单路,竟然可以了,回过头去看SOPC,发现刚好忘了选择Enable bit_clearing。。。这样就行了。

         昏,知其然,不知道其所以然,寻找问题的答案!!!于是和我师父分析为什么???师徒两解决了n久n久,终于解决了师父一年前的问题以后我此刻最难受的郁闷:都是Eanbel bit_clearing惹的祸:

    image 

    意思是说:

         Bit n 在边沿捕获寄存器中,如果捕获了输入(相应的上升沿,下降沿),相应位的位就会被置1 。一个阿窝龙妹妹外设可以读取边沿捕获寄存器,来决定发生在PIO引脚的边沿变化。 如果选项“Enable bit_clearing for edge capture register”被关闭,写任意的值到边沿捕获寄存器将会清除所有寄存器。反之,写一个1到寄存器中一个特别的位,将会使得边沿捕获失去作用。

         根据我的实际测试,验证了以上的一些理论

    (1)Enable bit_clearing 打开的时候:

         因为ds说1 的时候清中断,所以IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_DATA_BASE, 0x03);清了我两个按键的中断,问题成功解决。

    (2)Enable bit_clearing 关闭的时候:

         因为ds说任意值写入都将会清除所有的边沿捕获寄存器,所以IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_DATA_BASE, any vaule);都能使得edgecapture清零,实际测试用了“IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_DATA_BASE, 0x00);”和“IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_DATA_BASE, 0x03);”,都达到了效果。当然习惯性的我们会用0来清零,以至于让人再次产生了误解。

    可是明摆着这些都能达到目的嘛,altera为啥要搞得那么尴尬呢??有必要吗???

         根据我师父的解释,解释如下:

    (1)在一般情况下,外部中断不会同时达到,因此bit_clearing显得没有什么意义,比如我们捕获按键,那个按下就让那个LED亮,同时按下就同时亮,这个完全没问题,直接IOWR_ALTERA_AVALON_PIO_DATA(LED_DATA_BASE, edge_capture);嘛!!!

    (2)但是这不否决中断同步捕获的情况。当中断同步捕获的时候,可以用bit_clearing来干活了,也许可以更加的灵活。因为中断同时达到的时候,PIO当然能够同时捕获两个中断信号,但是此时main()函数里面的执行就很尴尬了,两个中断到底听谁的呢?(你爸妈一个让你帮他做饭,一个让你陪他下棋,妈的老子听谁的,不干了继续玩NIOS2!)

          这相当于verilog中的异步,需要同步处理之后才OK)。因此利用bit_clearing来屏蔽同时捕获中断的位,下一次再屏蔽另一个来让CPU执行命令,给CPU完成一个该听谁的机会,这样也能有效防止CPU死机(TMD老子不干了)。

         因为PIO IRS这个在SOPC中指分配了一个IRQ,所以无所谓单片机中的“中断优先级”的说法,所以只能通过bit_clearing来更完美的分配CPU 的任务。

     

         以上说明基本上解释了以下ZLG的翻译是错了,以前我也对着ds发现过别的error,看来原汁原味的dt就是好!

    image

    最后解释一个为什么在Enable bit_clearing 打开的时候,IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_DATA_BASE,0x00)为什么会死机,程序卡死在初始化这句话中的问题:

         根据altera的dt(我以上分析的(2)),讲到了当打开Enable bit_cleraing的时候,要给相应位写1,才能清除标志位。(网上很多人都是给0清零的,这可能是因为他们没有打开Enbale bit_clearing),但是我们给了0 来清楚edagcapture,这样根本不能清除中断标志,因此一次死在里面(所谓君让臣死,臣不得不死,不死也得死)。只有清除了才可以,根据我的验证,此时写1来清除相应的bit,很好的解决了问题。

         这同时也反驳了牙缝的博客,诱惑了我的致命问题(当然我很感谢本人,因为他对我的帮助远胜过这两天的痛苦,可能人家NC了失误了哈哈):Enable bit_clearing打开了,而清除边沿寄存器的时候却给了0:http://www.cnblogs.com/yuphone/archive/2010/11/25/1887621.html

    image image .

         问题到了现在算是比较清晰了,还以为ALtera自己神经病,最后发现不是软件问题,也不是altera神经病,而是我们没有好好啃ds。

         师父说:“altara是奥托拉,是奥特曼的弟弟,可牛逼了;MOTO是摩托罗拉,是摩托也要用骡来拉,可戳了。。”(师父真是个神!!!)因此不能一直埋怨altera,他们做的事情一般都是有哥根据的。

         下面贴上代码,呵呵,给自己留个底:

    一般情况下,不管你Enable bit_clearing怎么配置,给1 清零永远不会错!!!

    /* 
    * sys_main.c 

    *  Created on: 2011-4-1 
    *      Author: CrazyBingo 
    */

    #include <stdio.h> 
    #include "unistd.h" 
    #include "system.h" 
    #include "alt_types.h" 
    #include "sys/alt_irq.h" 
    //#include "io.h" 
    #include "altera_avalon_pio_regs.h"

    //#include "../inc/my_sopc.h" 
    //#include "../inc/key_scan.h"

    void key_interrupts(void * key_isr_context); 
    void key_interrupts_init(void);

    // 定义全局变量以储存边沿捕获值 
    volatile int edge_capture;

    int main(void) 

        key_interrupts_init();

        while(1) 
        { 
            IOWR_ALTERA_AVALON_PIO_DATA(LED_DATA_BASE, edge_capture); 
        } 
        return 0; 
    }

    //* 按键中断初始化 */ 
    void key_interrupts_init(void) 

        /**//* Recast the edge_capture pointer to match the alt_irq_register() function 
         * prototype. */ 
        void* edge_capture_ptr = (void*) &edge_capture; 
        /**//* Enable all 2 button interrupts. */ 
        IOWR_ALTERA_AVALON_PIO_IRQ_MASK(KEY_DATA_BASE, 0x03); 
        /**//* Reset the edge capture register.Enable bit_clearing turn0 off, write any vaule will take effect */ 
        IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_DATA_BASE, 0x03); //active High always take effect 
        /**//* Register the interrupt handler. */ 
        alt_ic_isr_register 
        ( 
                KEY_DATA_IRQ_INTERRUPT_CONTROLLER_ID,    // 中断控制器标号,从system.h复制 
                KEY_DATA_IRQ,                             // 硬件中断号,从system.h复制 
                key_interrupts,                         // 中断服务子函数 
                edge_capture_ptr,                          // 指向与设备驱动实例相关的数据结构体 
                NULL                                    // flags,保留未用 
        ); 
    }

    //按键中断服务程序(Interrupt service routime),每次下降沿进入中断执行一次 
    void key_interrupts(void * key_isr_context) 

        /**//* Cast context to edge_capture's type. It is important that this be 
         * declared volatile to avoid unwanted compiler optimization. 
         */ 
       volatile int* edge_capture_ptr = (volatile int*) key_isr_context; 
        /**//* Store the value in the Button's edge capture register in *context. */ 
        *edge_capture_ptr = IORD_ALTERA_AVALON_PIO_EDGE_CAP(KEY_DATA_BASE); 
        /**//* Reset the edge capture register. */ 
        IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_DATA_BASE,0x03); 
    }

        终于可以进行我下一步了。。。柳暗花明----有时候,解决为什么比解决怎么做更加的痛苦,但此时解决了师父和牙缝的的失误,同时,我终于可以放松一下了,这阵子因为这个中断,因为Cyclone III PCB,快让我over了,不过终于解决了问题,累着并且开心着。

         听师父的,Go on!

  • 相关阅读:
    第四章 连接管理
    第三章 http报文
    第二章 URL与资源
    第一章 http概述
    html5 canvas 游戏地图绘制
    jqGrid 编辑完数据后能返回到当前位置的方法
    发布APP到app store
    STSDB、NDataBase 对象数据库在不同.net framework下无法读取的解决办法
    System.Json 使用注意
    TiQuery
  • 原文地址:https://www.cnblogs.com/yuphone/p/2004793.html
Copyright © 2020-2023  润新知