zoukankan      html  css  js  c++  java
  • [转载].“君让臣死 臣不得不死 不死也得死”的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!

  • 相关阅读:
    linux下启动和关闭网卡命令及DHCP上网
    python 编码问题
    paddlepaddle
    Convolutional Neural Network Architectures for Matching Natural Language Sentences
    deep learning RNN
    Learning Structured Representation for Text Classification via Reinforcement Learning 学习笔记
    Python IO密集型任务、计算密集型任务,以及多线程、多进程
    EM 算法最好的解释
    tensorflow 调参过程
    tensorflow 学习纪录(持续更新)
  • 原文地址:https://www.cnblogs.com/yuphone/p/2004793.html
Copyright © 2011-2022 走看看