中断体系结构的实验~TQ2440

     当异常中断发生时,系统执行完当前指令后,将跳转到相应的异常中断处理程序处执

行。当异常中断处理程序执行完成后,程序返回到发生中断指令的下条指令处执行。在进入异

常中断处理程序时,要保存被中断程序的执行现场,从异常中断处理程序退出时,要恢复被中

断程序的执行现场。
 中断的使能在cpsr的I F位,分别允许普通中断和快速中断。
     SRCPND :当一个中断发生后,那么相应的位会被置1,表示一个或一类中断发生了,可以

同时发生多个中断,就会多个位置1.
         INTMSK :中断屏蔽寄存器。FIQ不受其影响
         INTPND :中断发生后,SRCPND中会有位置1,可能好几个(因为同时可能发生几个中

断),这些中断会由优先级仲裁器选出一个最紧迫的,然后吧把INTPND中相应位置1,所以同一

时间只有一位是1。也就是说前面的寄存器置1是表示发生了,只有INTPND置1,CPU才会处理。
         INTOFFSET :用来表示INTPND中哪一位置1了,好让你查询,普通中断跳转时查询用

。清除INTPND、SRCPND时自动清除。
         中断处理之后需要我们写1清除中断,(如果你也许在处理这个中断的时候可以继续

发生此中断,也可以在处理之前清除中断),否则,会被认为没有被处理,会不停的处理这个

中断。清除中断是按照eintpnd srcpnd intpnd的顺序。
 子中断掩码subintmsk
 中断产生的时候:
1.中断模式下的LR寄存器保存上一个模式的的下一条指令地址(lr=pc+4),
2.将CPSR值复制到异常模式的SPSR,以保存现场
3.将CPSR设置为异常模式的数值
4.令PC的数值等于异常模式在异常向量表中的地址,即跳转执行异常向量表中的指令
        中断处理完成之后:
1.将保存在异常模式中的LR的数值减去适当的数值,赋给PC寄存器
2.将SPSR复制给CPSR
  pc和cpsr是通用的,关于寄存器,有一个图标明显的指出哪些寄存器通用,哪些寄存

器有副本,可惜csdn目前不支持图片,以后补上吧
        开启中断之前我们要做的工作:
1,设置好各种模式下的堆栈,因为每种模式都有自己的堆栈
2,写好中断处理函数
3,设置好中断向量表,与中断函数关联起来
4,开启中断使能位cpsr的I F
5,中断产生之后会自动根据中断向量表跳转到对应的处理函数,此时srcpnd的相应位会被置1

,然后检查intmsk对应的中断是否屏蔽,然后会通过优先级仲裁器选出优先级最高的一个中断

,自动让intpnd的相应位置一,intpnd有且只有一位会被置一。我们会读取intoffset的值,判

断出中断源,开始处理中断函数,处理之后清除中断,也可以在中断处理之前清除,视情况而

定。
  代码下班了补上,代码会给出更详细解释。

@led start @2010-01-12 @jay .text .globl _start _start: b reset //@预留着以后扩展中断向量表 int_irq0: b intirq int_irq1: b intirq int_irq2: b intirq int_irq3: b intirq int_irq4: b intirq int_irq5: b intirq int_irq6: b intirq reset: @disable watchdog ldr r0,=0x53000000 mov r1,#0 str r1,[r0] msr cpsr_c,#0xd2 @in usr mode 分别设置好各模式的堆栈 ldr sp,=3072 @setup stack msr cpsr_c,#0xdf @in sys mode ldr sp,=4096 @setup stack @ 其实reset就处于系统模式, bl irq_init msr cpsr_c,#0x5f @enable irq ldr lr,=ledloop ldr pc,=irq_test ledloop: b . intirq: sub lr,lr,#4 @ 计算返回地址,因为返回时pc会加4 stmdb sp!,{r0-r12,lr} @ 保存会使用的寄存器到spsr @ 注意,此时的sp是中断模式的sp ldr lr,=irq_return @设置好返回指针 ldr pc,=eint_key @关联中断函数 irq_return: ldmia sp!,{r0-r12,pc}^ @ ^ 恢复现场

 

#include"led.h" #include"tq2440.h" //中断体系 //初始化gpio为外部中断 void irq_init() { GPFCON =(2<<0)|(2<<2)|(2<<4)|(2<<6); //gpio设为中断模式 //开启屏蔽的中断0~4 为0 eintmask是屏蔽4 23的 INTMSK &=~(0xf); /* 设定优先级 priority arbmod0=0;arbsel0=0; 优先级反转,使能的话就会转动的哦 */ PRIORITY&=(~(1<<0))|(~(1<<7)); } void eint_key() { GPBCON =GPB05OUT | GPB06OUT | GPB07OUT | GPB08OUT ; //gpio 配置输出out //0xEFF, 0xF7F, 0xFBF, 0xFDF unsigned long key; key=INTOFFSET; switch(key){ case 0: GPBDAT=~(1<<5); //k1 break; case 1: GPBDAT=~(1<<6); //k2 break; case 2: GPBDAT=~(1<<7); //k3 break; case 4: GPBDAT=~(1<<8); //k4 break; default: GPBDAT=0; break; } //清除中断,相应位写1 清除中断 SRCPND |=(1<<INTOFFSET); INTPND=INTPND; } /*eint8-23表示外部中断eint8---eint23 INTOFFSET判断中断源,显示哪个中断在INTPND中待决,(0-3可以直接判断出,4--23需要我们再次判断EINTPEND) 返回值为0-31 4-7合用IRQ5,8-23合用IRQ6 INTPEND 表示待决的中断 有且只有一个位置1 有待决的就是1,可以显示0-3和其他中断INT-ADC之类的 .该寄存器值一般是不用设置的. EINTPEND只显示4-23的中断待决 表示外部待决中断 SRCPND */ void irq_test() { while(1); }

 

led和makefle boot.lst 和以前一样  , 所以就不传上来了

你可能感兴趣的:(c,工作,扩展,2010)