• s5pv210——中断


    1:s5pv210的中断步骤

    (1):建立异常向量表;

    (2):中断初始化;

    (3):使能(如外部中断,写中断处理函数);

    (4):建立中断号与中断处理函数的联系,使能中断;

    当中断发生时,中断处理函数会自动处理中断;

    流程如下:

    2:建立异常向量表:

    s5pv210异常向量表的基地址为0xD003_7400,下图为异常对于基地址的偏移量;

     第一步建立异常向量表:

    代码如下:

    /*
    * s5pv210 裸机
    *
    * 异常向量表初始化
    *
    */

    #define VECTOR_TABLE_BASE 0xD0037400

    #define Reset_offset 0x0
    #define Undef_offset 0x4
    #define SVC_offset 0x8
    #define Prectch_offset 0xC
    #define Data_Abort_offset 0x10
    #define IRQ_offset 0x18
    #define FIQ_offset 0x1C


    #define _PFUNC_Reset (*(unsigned int*)(VECTOR_TABLE_BASE+Reset_offset))
    #define _PFUNC_Undef (*(unsigned int*)(VECTOR_TABLE_BASE+Undef_offset))
    #define _PFUNC_SVC (*(unsigned int*)(VECTOR_TABLE_BASE+SVC_offset))
    #define _PFUNC_Prectch (*(unsigned int*)(VECTOR_TABLE_BASE+Prectch_offset))
    #define _PFUNC_Data_Abort (*(unsigned int*)(VECTOR_TABLE_BASE+Data_Abort_offset))
    #define _PFUNC_IRQ (*(unsigned int*)(VECTOR_TABLE_BASE+IRQ_offset))
    #define _PFUNC_FIQ (*(unsigned int*)(VECTOR_TABLE_BASE+FIQ_offset))

    extern void IRQ_handle(void);


    void Reset_handle(void)
    {

    }
    void Undef_handle(void)
    {

    }

    void SVC_handle(void)
    {

    }
    void Prectch_handle(void)
    {

    }
    void Data_Abort_handle(void)
    {

    }

     

     


    void vector_table_init(void)
    {
    _PFUNC_Reset =   (unsigned int)Reset_handle;
    _PFUNC_Undef =   (unsigned int)Undef_handle;
    _PFUNC_SVC =    (unsigned int)SVC_handle;
    _PFUNC_Prectch = (unsigned int)Prectch_handle;
    _PFUNC_Data_Abort = (unsigned int)Data_Abort_handle;
    _PFUNC_IRQ =     (unsigned int)IRQ_handle;
    _PFUNC_FIQ =     (unsigned int)IRQ_handle; //FIQ、IRQ都是采用IRQ中断

    }

     

    IRQ_handle要写在汇编IRQ_handle.S中;

    代码如下:

    /*
     *
     *
     *
     *
     */
    
    #define IRQ_STACK        0xD0037F80 
        
        .global IRQ_handle
    IRQ_handle:
    
        //设置IRQ的栈
        ldr sp, =IRQ_STACK
    
        //由于三级流水线的存在,pc为此时的程序语句+8,保存的时候要把下一句保存到lr中
        sub lr, lr, #4
        
        //保存现场
        stmd sp! {r0-r12, lr}
        
        //跳转到中断处理函数
        bl isr_handler
        
        //恢复现场
        ldmfd sp! {r0-r8, pc}^

    ARM保存中断时为什么使用 sub lr, lr, #4

    1. 首先要谈流水线,在arm执行过程中一般分为取指,译码,执行阶段

      也就是假设当前                                                                      第一条指令在执行阶段

                                                                  第二条指令在译码阶段

                              第三条指令在取指阶段

      当前正在执行的指令地址为pc-8,第二条就为pc-4,而pc现在真正指向已处于pc位置

    2. 一般pc在发生中断时lr保存的是当前的pc值,这里pc值是多少呢??

         当发生中断肯定保存的pc是第三条指令,而我们从中断返回肯定不是执行第三条指令,而是紧接着的第二条指令,所以应该保存的 lr = pc - 4,

    但是当执行到此位置时pc值已经改变,肯定不对,还好发生中断时 mov lr,pc 所以这里就可以直接使用 sub lr,lr,#4

    ————————————————————未完待续————————————————————————————

    第二部:中断初始化

    相关寄存器:

    使能中断:

    Disable中断

    中断处理函数自动保存地址

     中断处理函数存放地址

    代码实战:

    //清除4个中断处理函数
    void clean_vicaddress(void)
    {
        _REG_VIC0ADDRESS = 0x0;
        _REG_VIC1ADDRESS = 0x0;
        _REG_VIC2ADDRESS = 0x0;
        _REG_VIC3ADDRESS = 0x0;
        
    }
    
    
     
    void interrupt_init(void)
    {
        //第一步初始化中断之前要关闭所有中断
        _REG_VIC0INTENCLEAR = 0xFFFFFFFF;
        _REG_VIC1INTENCLEAR = 0xFFFFFFFF;
        _REG_VIC2INTENCLEAR = 0xFFFFFFFF;
        _REG_VIC3INTENCLEAR = 0xFFFFFFFF;
        
        //第三步:设置中断为IRQ中断
        _REG_VIC0INTSELECT = 0x0;
        _REG_VIC1INTSELECT = 0x0;
        _REG_VIC2INTSELECT = 0x0;
        _REG_VIC3INTSELECT = 0x0;
        
        //第三步:清中断处理函数地址
        clean_vicaddress();
        
    }
    
    void int_disable(unsigned int num)
    {
        if (num < 32) {
            _REG_VIC0INTENCLEAR = (0x1<<num);
        }
        else if (num < 64) {
            _REG_VIC1INTENCLEAR = (0x1<<(num-32));        
        }
        else if (num < 96) {
            _REG_VIC2INTENCLEAR = (0x1<<(num-64));
        }
        else if (num < 128) {
            _REG_VIC3INTENCLEAR = (0x1<<(num-96));
        }
        else {
    
        }
            
    }
     
    void int_enable(unsigned int num)
    {
        if (num < 32) {
            _REG_VIC0INTENABLE = (0x1<<num);
        }
        else if (num < 64) {
            _REG_VIC1INTENABLE = (0x1<<(num-32));        
        }
        else if (num < 96) {
            _REG_VIC2INTENABLE = (0x1<<(num-64));
        }
        else if (num < 128) {
            _REG_VIC3INTENABLE = (0x1<<(num-96));
        }
        else {
            _REG_VIC0INTENABLE = 0xFFFFFFFF;
            _REG_VIC1INTENABLE = 0xFFFFFFFF;
            _REG_VIC2INTENABLE = 0xFFFFFFFF;
            _REG_VIC3INTENABLE = 0xFFFFFFFF;
        }
        
    }
     
    void creat_israddr(unsigned int num, void (*PIRQ_handler)(void))
    {
        
        if (num < 32) {        
            //*( (void (*)(void))(VIC0VECTADDR + 4*num) )= PIRQ_handler;
            *( (volatile unsigned long *)(VIC0VECTADDR + 4*(num-0)) ) = (unsigned)PIRQ_handler;
            
        }
        else if (num < 64) {
            //(void (*)(void))(VIC1VECTADDR + 4*(num-32))= PIRQ_handler;
            *( (volatile unsigned long *)(VIC1VECTADDR + 4*(num-32)) ) = (unsigned)PIRQ_handler;
        }
        else if (num < 96) {
            //(void (*)(void))(VIC2VECTADDR + 4*(num-64))= PIRQ_handler;
            *( (volatile unsigned long *)(VIC2VECTADDR + 4*(num-64)) ) = (unsigned)PIRQ_handler;
        }
        else {
            //(void (*)(void))(VIC3VECTADDR + 4*(num-96))= PIRQ_handler;
            *( (volatile unsigned long *)(VIC3VECTADDR + 4*(num-96)) ) = (unsigned)PIRQ_handler;
        }
            
    }
     
    //判断中断在哪个address中
    
    static int check_int_addr(void)
    {
        if (_REG_VIC0IRQSTATUS) {
            return 0;
        }
        else if (_REG_VIC1IRQSTATUS) {
            return 1;
        }
        else if (_REG_VIC2IRQSTATUS) {
            return 2;
        }
        else if (_REG_VIC3IRQSTATUS) {
            return 3;
        }
        else {
            return -1;
        }
        
    } 
     
    
    void isr_handler(void)
    {
        void (*p_isr)(void) = NULL;
        int i;
        
        i = check_int_addr();
        switch (i) {
            case 0 :
                p_isr = (void (*)(void))_REG_VIC0ADDRESS;
                break;
            case 1 :
                p_isr = (void (*)(void))_REG_VIC1ADDRESS;
                break;
            case 2 :
                p_isr = (void (*)(void))_REG_VIC2ADDRESS;
                break;
            case 3 :
                p_isr = (void (*)(void))_REG_VIC2ADDRESS;
                break;
            default :
                break;
        }
        
        p_isr();
        
    }

    第三部:使能外部中断中断处理函数;

    详细请看

    void int_led_blink(void)
    {
       //中断处理函数 
      led_blink();
      //清楚外部中断挂起,注意写1清挂起 clean_int_pend(); //清
    vicaddress

      clean_vicaddress();
    }

    第四部:建立中断号与中断函数联系,使能中断

    #include "interrupt.h"
    #include "stdio.h"
    extern void led_blink(void);
    extern void led1_on(void);
    extern void vector_table_init(void);
    extern void key_init(void);
    extern void uart_init(void);
    
    int main(void)
    {
        //按键初始化
        key_inter_init();
        
        //异常向量表初始化
        vector_table_init();
        
        //中断初始化
        interrupt_init();
        
        
        //创建函数
        creat_israddr(NUM_EINT2, int_led_blink);
        creat_israddr(NUM_EINT3, int_led_blink);
        creat_israddr(NUM_EINT16_31, int_led_blink);
        
        
        //使能中断
        int_enable(NUM_EINT2);
        int_enable(NUM_EINT3);
        int_enable(NUM_EINT16_31);
        
        
        while (1) {
            printf("a");
        }
        
    }
  • 相关阅读:
    jsonp跨域
    angular总结控制器的三种主要职责: 为应用中的模型设置初始状态 通过$scope对象把数据模型或函数行为暴露给视图 监视模型的变化,做出相应的动作
    url解析
    waterfall.js
    ES6
    前端代码规范
    秒杀倒计时功能实现
    怎样正确写网站title、keywords、description比较标准。
    CSS3动画
    Python3基础 父,子类普通方法重名 子类方法覆盖父类方法
  • 原文地址:https://www.cnblogs.com/biaohc/p/6354068.html
Copyright © 2020-2023  润新知