Chinaunix首页 | 论坛 | 博客
  • 博客访问: 318808
  • 博文数量: 49
  • 博客积分: 4045
  • 博客等级: 上校
  • 技术积分: 1195
  • 用 户 组: 普通用户
  • 注册时间: 2007-06-15 12:56
文章分类

全部博文(49)

文章存档

2013年(29)

2010年(6)

2009年(6)

2008年(8)

我的朋友

分类: 嵌入式

2013-03-11 09:41:08

    ARM异常这里昨天本应该就完成了,加上断网,修电脑,放松一下啥的给耽误了。。。

Clock中start.s虽然拷到了,从0地址开始的地址,但是能正常工作,那是因为PC是一条一条的挨着执行指令的,而且没有发生异常,所以能正常运行。
Vector中的start.s那样就支持了异常发生时的处理,也就是发生异常也能正确运行。
/*个人对以前一个程序执行过程的理解,和这里没关系*/


    上节我们说了异常。中断也是异常中的一种,有FIQ,IRQ,这里只说IRQ。
    6410的中断:总是有一个外部触发点,比如按键中断,我们这里就用按键来说明,,然后中断进入6410soc里的中断控制器,控制器进行识别是那个中断,然后把中断信号发给CPU,CPU从当前模式进入到中断处理模式,处理完中断,顺便清除中断。所以我们在写中断裸机驱动的时候,就按着这个思路一步步设置下来。
    6410有两个VIC(矢量中断控制器),分为VIC0和VIC1,每一个VIC支持32个中断源,总共支持64个中断源。每个中断源有个中断号,从0~63。
    

   当发生一个中断时,我们需要执行相应的ISR,如何让CPU准确的去执行自己的ISR呢?这里就引入以下的这些 矢量地址寄存器,总共有64个,他们的作用就是记录每个中断处理函数的地址。当要执行某个ISR时,硬件就会自动把VICxVECTADDRn中的值付给VIC0ADDRESS这个寄存器……感觉不好描述,再说点重要的,我们直接对着代码分析中断的过程吧。
    
VIC0的基础地址是0x7120_0000 
VIC1的基础地址是0x7130_0000
中断中的所有寄存器的地址都是在这俩个地址的后边加一个偏移,定义这些寄存器的时候需要注意。

啥也不说了,跟个代码走:
这个先不看,是按键中断服务程序。先看下一个程序。
void key_isr(void)
{
        if(EINT0PEND & (1 << 0)){               //判别第0组外部中断的第0个中断是否发生,多个中断用一个I/o引脚。
                EINT0PEND |= (1 << 0);        //清除中断。 
                uprintf("EINT0 happend\n");
        }
        if(EINT0PEND & (1 << 1)){               
                EINT0PEND |= (1 << 1);          
                uprintf("EINT1 happend\n");
        }
        if(EINT0PEND & (1 << 2)){               
                EINT0PEND |= (1 << 2);         
                uprintf("EINT2 happend\n");
        }
        if(EINT0PEND & (1 << 3)){               
                EINT0PEND |= (1 << 3);         
                uprintf("EINT3 happend\n");
        }
        if(EINT0PEND & (1 << 4)){               
                EINT0PEND |= (1 << 4);          
                uprintf("EINT4 happend\n");
        }
        if(EINT0PEND & (1 << 5)){              
                EINT0PEND |= (1 << 5);          
                uprintf("EINT5 happend\n");
        }

}
//这个按键初始化函数就是要设置一个外部中断触发事件
void key_init(void)
{
        GPNCON &= ~(0xfff << 0);
        GPNCON |= (0xaaa << 0);                 //本板子有6个按键,把这些按键设置成外部中断模式。
        EINT0CON0 &= ~(0xfff << 0);//中断中有外部中断,内部中断如串口中断,定时器中断……,而外部中断有9个中断组,按键在第0个中断组中。
        EINT0CON0 |= (0x222 << 0);                      //设置为下降沿触发
        EINT0MASK &= ~(0x3f << 0);              //这里还的使能,让按键到中断控制器之间的开关打开。
        request_irq(0,key_isr);//第一个参数表示,中断号(0~63),第二表示中断后要执行的函数,也就是上面那个函数。
        request_irq(1,key_isr);
}


void do_irq(void)
{
        void (*handle)(void) = 0;
        if(VIC0ADDRESS != 0){
                handle = (void *)VIC0ADDRESS;
        }
        if(VIC1ADDRESS != 0){
                handle = (void *)VIC1ADDRESS;
        }
        if(handle != 0){
                handle();
        }
        VIC0ADDRESS = 0;
        VIC1ADDRESS = 0;
}
void request_irq(int no,void (*handle)(void))
{
        if(no < 32 && no >= 0){
                *(&VIC0VECTADDR0 + no) = (unsigned int)handle;   //这里寄存器的作用上面说过。/*CPU运行中发生一个中断之后就跳到本文章最后的汇编哪里,然后跳到do_irq函数,在这里判断是那个VIC里发生的中断(中断时,硬件自动把VICxVECTADDRn的值赋给VICxADDRESS)然后执行ISR,最后那两句话是清除中断,手册里说写任意值都行*/
                VIC0INTENABLE |= (1 << no);
        }
        if(no < 64 && no >= 32){
                *(&VIC1VECTADDR0 + no - 32) = (unsigned int)handle;
                VIC1INTENABLE |= (1 << (no - 32));
        }
}

/*打开CPU的总中断开关位*/
        mrs     r0,cpsr
        bic     r0,#(1 << 7)
        msr     cpsr,r0  
/*发生中断异常时跳到这里*/
irq:
        mov     sp,#0x1800
        stmfd   sp!,{r0-r12,lr}
        bl      do_irq
        ldmfd   sp!,{r0-r12,pc}^
        b       .
看到这里是不是觉得写得很烂,其实我也感觉很烂,很多功能没有用到,我是觉得初学者一切从简单做起容易成功,二是心急想要进行下一部分,所以就不花时间细研究了,以后慢慢深入!
好在网上我又找到了一篇相关的文章,写的很详细,图文并茂。下一篇文章我转过来,大家细细研究下。。。


阅读(557) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~