zoukankan      html  css  js  c++  java
  • ecos中断机制分析(2)

     mcf52xx系列ISR向量表实际是一个数组cyg_hal_interrupt_handlers[],那么数组里保存的ISR入口地址是什么时候存进去的呢?,原来用户在添加ISR的时候会通过cyg_drv_interrupt_attach()函数,该函数将该ISR的入口地址按中断向量号顺序存入ISR向量表数组。具体实现如下:

    #define HAL_INTERRUPT_ATTACH( _vector_, _isr_, _data_, _object_ )    \
        CYG_MACRO_START                                                  \
        cyg_uint32 _index_;                                              \
        HAL_TRANSLATE_VECTOR((_vector_), _index_);                       \
        if (cyg_hal_interrupt_handlers[_index_]                          \
            ==(CYG_ADDRESS)&hal_arch_default_isr)                        \
        {                                                                \
            cyg_hal_interrupt_handlers[_index_] = (CYG_ADDRESS)(_isr_);  \
            cyg_hal_interrupt_data[_index_] = (CYG_ADDRWORD)(_data_);    \
            cyg_hal_interrupt_objects[_index_] = (CYG_ADDRESS)(_object_);\
        }                                                                   \
        CYG_MACRO_END

    其中HAL_TRANSLATE_VECTOR宏又定义为:

    #define HAL_TRANSLATE_VECTOR(_vector_,_index_)                          \
        CYG_MACRO_START                                                   
     
     \
        switch ((_vector_))                                                 \
        {                                                                   \
        case CYGNUM_HAL_VECTOR_AUTOVEC1 ... CYGNUM_HAL_VECTOR_AUTOVEC7:     \
            (_index_) = ((_vector_) - CYGNUM_HAL_VECTOR_AUTOVEC1);          \
            break;                                                          \
        case CYGNUM_HAL_VECTOR_INTRFIRST ... CYGNUM_HAL_VECTOR_INTRLAST:    \
            (_index_) = ((_vector_)                                         \
                         - CYGNUM_HAL_VECTOR_INTRFIRST                      \
                         + (CYGNUM_HAL_VECTOR_AUTOVEC7                      \
                            - CYGNUM_HAL_VECTOR_AUTOVEC1                    \
                            + 1));                                          \
            break;                                                          \
        default:                                                            \
            CYG_FAIL("Unknown Interrupt!!!");                               \
            (_index_) = (typeof(_index_))-1;                                \
        }                                                                   \
        CYG_MACRO_END

       上面两段宏显示了ISR向量表数组的构成,cyg_hal_interrupt_handlers[0]到cyg_hal_interrupt_handlers[6]为25-31号Autovector interrupts1-7的ISR程序入口地址,cyg_hal_interrupt_handlers[7]到cyg_hal_interrupt_handlers[198]为64-255号User interrupt的ISR程序入口地址。   

       例如产生的是第70号中断,那么是刚才那段汇编程序获得ISR程序入口地址在cyg_hal_interrupt_handlers[] 数组中存放位置?

       当70号中断产生时,MCU将自动压栈32位状态字和PC,因为状态字里VECTOR[7:0]保存了中断向量号,所以根据这个向量号就可以换算出ISR放在cyg_hal_interrupt_handlers[]数组的位置了。  

    hw_vsr_interrupt:

            int_pres_regs        

            move.l #(-64+7)*4,%d0     

    hw_vsr_int_common:                                 

            move.w  int_pres_regs_sz(%sp),%d1    //出栈32位状态字

            and.l   #0x000003fc,%d1      //获取VECTOR[7:0]      

            add.l   %d1,%d0      //d0为ISR程序入口地址在

                                 //cyg_hal_interrupt_handlers[]数组的相对位置

            asr.l   #2,%d1       //d1为中断向量号

       获取了ISR入口地址,接下来该调用ISR了。              

    #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT

            .extern cyg_scheduler_sched_lock        

            addq.l  #1,cyg_scheduler_sched_lock    //将调度器上锁次数增加1

    #endif

            pea     (%sp)                      

            .extern cyg_hal_interrupt_objects     

            lea     cyg_hal_interrupt_objects,%a0   

            move.l  (%a0,%d0.l),-(%sp)

            .extern cyg_hal_interrupt_data         

            lea     cyg_hal_interrupt_data,%a0      

            move.l  (%a0,%d0.l),-(%sp)

            .extern cyg_hal_interrupt_handlers      

            lea     cyg_hal_interrupt_handlers,%a0  

            move.l  (%a0,%d0.l),%a0

            move.l  %d1,-(%sp)                 

      这一段主要为调用static cyg_uint32 isr(CYG_ADDRWORD vector, CYG_ADDRWORD data)以及void interrupt_end(cyg_uint32 isr_ret,
    Cyg_Interrupt *intr,HAL_SavedRegisters  *regs)
    作准备,
     将函数需要的参数*intr,vector和data压栈,此时的堆栈如下图所示:

                        ecos中断机制分析(2)               

            jbsr   (%a0)       //这里调用ISR,返回值作为传入interrupt_end();

                               //的参数isr_ret。          

            addq.l  #4*1,%sp                   

            move.l  %d0,(%sp)  //保存isr_ret,此时堆栈如图所示:

                        ecos中断机制分析(2)

    interrupt_end()函数将根据ISR返回值isr_ret和调度器上锁次数cyg_scheduler_sched_lock来判断是否执行DSR。如果isr_ret等于2(CYG_ISR_CALL_DSR),且cyg_scheduler_sched_lock等于1,在interrupt_end()函数中将执行DSR.         

    #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT

            move.w  (4*3)+int_pres_regs_sz+2(%sp),%d2
            move.w  %d2,%sr
          
    //恢复本次中断前SR[10:8]的值

            and.l   #0x0700,%d2
            lsr.l   #8,%d2
            add.l   %d2,cyg_scheduler_sched_lock
     //处于中断嵌套则使上锁次数大于1

      在调用interrupt_end()之前,首先恢复了本次中断前SR[10:8]的值,如果这个值不为0,说明处于中断嵌套中,因为初始化SR[10:8]为0,只有退到嵌套的最后一层,其中断前SR[10:8]才为0,如果不是0,通过增加 cyg_scheduler_sched_lock的值使interrupt_end()不执行DSR.也即保证DSR不能在中断嵌套的情况下执行,从这里可以看出ecos中断策略是,允许中断嵌套,每个中断分为ISR,DSR两部分,ISR立即执行,DSR在ISR之后进行,如果此时处于中断嵌套,则将推迟DSR处理,将其放在DSR队列里(在interrupt_end()中放置),直到退出中断嵌套,所有积累的DSR才能执行。

            .extern interrupt_end              

            jbsr    interrupt_end     //这里调用interrupt_end()

    http://blog.sina.com.cn/s/blog_48803ff301000ai6.html

  • 相关阅读:
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 最大的元素距离
    Java 第十一届 蓝桥杯 省模拟赛 递增序列
    Java 第十一届 蓝桥杯 省模拟赛 递增序列
    Java 第十一届 蓝桥杯 省模拟赛 最大的元素距离
  • 原文地址:https://www.cnblogs.com/kuainiao/p/2883332.html
Copyright © 2011-2022 走看看