中断体系结构

时间:2022-09-08 19:08:02

一、

中断体系结构中断体系结构
 1 @******************************************************************************
 2 @ File:head.S
 3 @ 功能:初始化,设置中断模式、管理模式的栈,设置好中断处理函数
 4 @******************************************************************************       
 5 .extern     main
 6 .text 
 7 .global _start 
 8 _start:
 9 
10 @*****************************************
11 HandleDataAbort:
12     b   HandleDataAbort
13 @*************
14 @ 0x14: 保留 @
15 @*************
16 HandleNotUsed:
17     b   HandleNotUsed
18 @***************************
19 @ 0x18: 中断模式的向量地址 @
20 @***************************
21     b   HandleIRQ
22 @*****************************
23 @ 0x1c: 快中断模式的向量地址 @
24 @*****************************
25 HandleFIQ:
26     b   HandleFIQ
27 @*************************************************************************************************************************************************************************************
28 @ 子程序部分,复位和中断 @
29 @*************************************************************************************************************************************************************************************
30 @*************
31 @ 复位子程序 @
32 @*************
33 Reset:                  
34     ldr sp, =4096           @ 下面都是C语言,要先设置栈指针;这些代码直接在stepping中运行,所以先设置栈指针指向4K
35     bl  disable_watch_dog   @ 关看门狗
36     
37     msr cpsr_c, #0xd2       @ MSR: 通用寄存器到状态寄存器的传送指令。 
38                             @ 指令格式:MSR{<cond>} CPSR_<fields>, #<immediate> ; MSR{<cond>} CPSR_<fields>, <Rm> ; 
39                             @ <cond>为指令执行的条件码,当<cond>忽略时指令为无条件执行;<fields>设置状态寄存器中需要操作的位。状态寄存器的32位可以分为4个8位的域: f: 指示bits[31 : 24],又名条件标志位域,
40                             @ s: 指示bits[23 : 16],又名状态标志位域, x: 指示bits[15 : 8], 又名扩展位域,c: 指示bits[7 : 0],又名控制位;后面就是立即数,或者<Rm>寄存器包含将要传送到状态寄存器中的数据。
41                             @ MRS: 状态寄存器到通用寄存器的传送指令。
42                             @ 指令格式:MRS{<cond>}<Rd>, CPSR;<cond>为指令执行的条件码,当<cond>忽略时指令为无条件执行;<Rd>为目标寄存器。
43                             @ 在这里设置状态寄存器CPSR,选择工作模式为中断模式
44                             @ 状态寄存器CPST各位:N[31]结果是否为负数,Z[30]结果是否为0,C[29]进位/借位/移位溢出,V[28]溢出标志,[27:8]保留,I[7]中断禁止位,F[6]快速中断禁止位,T[5]CPU状态位,M4-M0[4:0]选择工作模式
45                             @ M4-M0[4:0]工作模式选择:10000用户模式,10001快中断模式,10010中断模式,10011管理模式,11011未定义指令中止模式,11111系统模式
46                             @ 在这里选择中断模式(IRQ),I、F均置位
47     ldr sp, =3072           @ 设置中断模式栈指针,应该是取一段就行,取的3K
48 
49     msr cpsr_c, #0xd3       @ 进入管理模式0011
50     ldr sp, =4096           @ 设置系统模式栈指针,其实复位之后,CPU就处于管理模式,前面的“ldr sp, =4096”完成同样的功能,此句可省略
51                             @ SPSR程序状态保存寄存器,当切换进入这些工作模式时,SPSR中保存前一个工作模式的CPSR值,这样,当返回前一个工作模式时,可以将SPSR的值回复到CPSR中。
52                             
53 
54     bl  init_led            @ 初始化LED的GPIO管脚,在文件init.c中,设置三个LED对应的引脚为输出
55     bl  init_irq            @ 调用中断初始化函数,在init.c中,用来设置中断的初始化,包括:1、设置开关对应的引脚状态为中断2、对于外部中断EINT11需要设置寄存器使能3、设置优先级4、三个均使能设置
56     msr cpsr_c, #0x5f       @ 设置I[7]=0,I[7]为中断禁止位,设置1为禁止中断模式IRQ,设置0则开启中断模式IRQ
57     
58     ldr lr, =halt_loop      @ 设置返回地址;lr也就是r14连接寄存器,用来保存子程序的返回地址;在汇编中调用c函数时,如果C函数中有返回值,那么调用前就一定要先配置lr的值,也就是执行完C函数之后pc指针指向的地址;
59                             @ ldr lr, =halt_loop,这里的意思就是说,执行C函数之前,先把死循环那里的地址放到lr中,执行完C之后,PC指针就指向了Lr的值,也就死循环的地址,也就是说,执行完C之后,就接着运行死循环啦;
60                             @ 当然,C函数中没有返回值时,也就不必先设置lr的值了,它没有返回,就自然执行完了,就执行下一条指令,当然也就没必要设置了
61     ldr pc, =main           @ 也就相当于跳转到main函数,b指令和bl指令只能跳转32M的范围,所以这里使用向pc赋值的方法进行跳转;b和bl指令只能跳转32M的范围,因为寄存器是32位的,此时的值是24位有符号数,所以是32M
62 halt_loop:                  @死循环;死循环的作用:在最后加个死循环,也就是让程序停留在这里了,这样是很有用的,一方面可以在这个时候查看各个存储器的值,以便检查自己的程序是否正确,另一方面,比如如果是C函数比如用到printf
63     b   halt_loop           @这样之类的函数,如果不加死循环,输出会瞬间消失
64 @*************
65 @ 中断子程序 @
66 @*************
67 HandleIRQ:
68     sub lr, lr, #4                  @ 减法指令sub:SUB R0,R1,R2  R0=R1-R2,SUB R0,R1,#3  R0=R1-3;这里就是lr=lr-4;保存上一次执行的地址,为等会中断完成后返回地址作准备 
69     stmdb   sp!,    { r0-r12,lr }   @ 保存被中断程序的运行环境,即各个寄存器;sp是中断模式的栈(3072);r0-r12和lr保存在中断模式的栈中
70                                    
71     ldr lr, =int_return             @ 设置调用ISR即EINT_Handle函数后的返回地址,在汇编中调用c函数时,如果C函数中有返回值,那么调用前就一定要先配置lr的值,也就是执行完C函数之后pc指针指向的地址;  
72     ldr pc, =EINT_Handle            @ 也就是跳转去执行中断处理的函数EINT_Handle;EINT_Handle函数在interrupt.c中,这就是中断的核心函数,根据按键的不同,去点亮不同的灯
73 int_return:
74     ldmia   sp!,    { r0-r12,pc }^  @ 中断返回, ^表示将spsr的值复制到cpsr
75                                     @ CPSR:程序状态寄存器,cpsr在用户级编程时用于存储条件码。CPSR包含条件码标志,中断禁止位,当前处理器模式以及其他状态和控制信息。
76                                     @ SPSR:程序状态保存寄存器。SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。
View Code

 

二、

中断体系结构中断体系结构
 1 /*
 2  * init.c: 进行一些初始化
 3  */ 
 4 /************************************************************************************************************************************************************************************
 5    函数:init.c
 6 ************************************************************************************************************************************************************************************/
 7 初始部分
 8 /******************/
 9 #include "s3c24xx.h"
10 
11 /*LED1,LED2,LED4对应GPF4、GPF5、GPF6,低电平时灯亮*/
12 #define    GPF4_out    (1<<(4*2))         //GPF4[9:8]=01   ,GPF4设置为输出    
13 #define    GPF5_out    (1<<(5*2))         //GPF5[11:10]=01 ,GPF5设置为输出
14 #define    GPF6_out    (1<<(6*2))         //GPF6[13:12]=01 ,GPF6设置为输出
15 
16 #define    GPF4_msk    (3<<(4*2))         //[9::8]=11        
17 #define    GPF5_msk    (3<<(5*2))         //[11:10]=11
18 #define    GPF6_msk    (3<<(6*2))         //[13:12]=11
19 
20 /* S2,S3,S4对应GPF0、GPF2、GPG3,开关按下时为低电平*/
21 #define GPF0_eint     (0x2<<(0*2))     //GPF[1:0]=10,   GPF0设置为输出
22 #define GPF2_eint     (0x2<<(2*2))     //GPF[5:4]=10,   GPF2设置为输出
23 #define GPG3_eint     (0x2<<(3*2))     //GPF[7:6]=10,   GPF3设置为输出
24 
25 #define GPF0_msk    (3<<(0*2))         //[1:0]=11
26 #define GPF2_msk    (3<<(2*2))         //[5:4]=11
27 #define GPG3_msk    (3<<(3*2))         //[7:6]=11
28 
29 /****************************************
30 关闭WATCHDOG子程序:disable_watch_dog()
31 ****************************************/
32 void disable_watch_dog(void)
33 {
34     WTCON = 0;  // 关闭WATCHDOG很简单,往这个寄存器写0即可
35 }
36 /****************************************
37 设置LED对应引脚为输出子函数:init_led()
38 ****************************************/
39 void init_led(void)
40 {
41     /* LED1,LED2,LED4对应的3根引脚设为输出 */
42     GPFCON &= ~(GPF4_msk | GPF5_msk | GPF6_msk);    //设置输出口是[13:8]进行设置,首先,这些位全部取0;
43     GPFCON |= GPF4_out | GPF5_out | GPF6_out;       //所需要设置的位,全部取0后跟对应的取1设置的相或就行
44 }
45 
46 /*
47  * 初始化GPIO引脚为外部中断
48  * GPIO引脚用作外部中断时,默认为低电平触发、IRQ方式(不用设置INTMOD)
49  */ 
50  /***************************
51  中断初始化子函数:init_irq( )
52  
53  ***************************/  
54 void init_irq()
55 {
56     /*S2,S3对应的2根引脚设为中断引脚 EINT0,ENT2*/
57     GPFCON &= ~(GPF0_msk | GPF2_msk);             //将需要设置的那些位清0
58     GPFCON |= GPF0_eint | GPF2_eint;              //设置引脚为中断
59 
60     // S4对应的引脚设为中断引脚EINT11
61     GPGCON &= ~GPG3_msk;                          
62     GPGCON |= GPG3_eint;
63     
64     // 对于EINT11,需要在EINTMASK寄存器中使能它
65     EINTMASK &= ~(1<<11);                         //对于外部中断4-23,需要设置EINTMASK寄存器数字相同对应的位,0使能中断,1禁止中断,因此这里需要设置第11位为0
66         
67     /* 设定优先级:ARB_SEL0 = 00b, ARB_MODE0 = 0: REQ1 > REQ3,即EINT0 > EINT2,仲裁器1、6无需设置,最终:EINT0 > EINT2 > EINT11即K2 > K3 > K4 */
68     PRIORITY = (PRIORITY & ((~0x01) | (0x3<<7))) | (0x0 << 7) ;    //S2对应中断引脚EINT0,S3对应中断引脚EINT2,S4对应EINT11,EINT0即REQ1,EINT2即REQ3,,对应中断优先级仲裁器ARBITER0,EINT11即为REQ1,对应中断优先级仲裁器ARBITER1;                          
69                                                                    //这里设置ARBITER0[8:7]=00,ARB_MODE0=0中断优先级不变; 所以优先级:REQ1>REQ3,即:S2>S3>S4                          
70     /* EINT0、EINT2、EINT8_23使能 */
71     INTMSK   &= (~(1<<0)) & (~(1<<2)) & (~(1<<5));       //INTMSK是中断屏蔽寄存器,为1时屏蔽,0使能中断,EINT0[0]=0,EINT2[2]=0,EINT8_23[5]=0
72 }
View Code

 

三、

中断体系结构中断体系结构
 1 /************************************************************************************************************************************************************************************
 2    中断程序部分
 3 ************************************************************************************************************************************************************************************/
 4 #include "s3c24xx.h"            //调用头文件中定义的地址                  
 5 
 6 /*******************************
 7 中断处理函数:EINT_Handle()
 8 *******************************/
 9 void EINT_Handle()
10 {
11     unsigned long oft = INTOFFSET;  //中断偏移寄存器:INTOFFSET,中断偏移寄存器中的值表明了是哪个 IRQ 模式的中断请求在 INTPND 寄存器中。此位可以通过清除SRCPND和 INTPND 自动清除
12     unsigned long val;
13 /*
14 switch语法基础:
15 1、基本格式: switch(表达式)
16 { 
17       case 常量表达式1:
18          语句1;
19       break;
20       
21       case 常量表达式2:
22          语句2;
23       break; 
24 
25 ……
26       case 常量表达式n:
27          语句n;
28       break; 
29 
30       default:
31          语句n+1;
32       break;
33 }
34 2、各部分说明:
35    (1)关于表达式: 表达式可以是整型、字符型等表达式。 有一个确定的值(不是逻辑值).
36    (2)关于常量表达式1~n:  只起到一个标号的作用,根据表达式的值来判断, 找到一个相匹配的入口处,程序往下执行。各个case后的常量表达式的值必须互不相同.
37    (3)每个case分支可有多条语句,可不用花括号{ }。
38    (4)各个case 语句只是一个入口标号,并不确定执行的终止点.
39    (5)一般在各个case 语句最后应该加一break语句,  可使程序流程跳出Switch结构.否则会从入口处一直向下执行.
40    (6)各个case和default出现的先后次序,并不影响执行结果.default可以没有.
41 */    
42     switch( oft )                   //oft即为中断偏移寄存器INTOFFSET的值,EINT0偏移量0,EINT2偏移量2,EINT8_23偏移量5,偏移量即偏移寄存器的值
43     {
44         // S2被按下
45         case 0:                     //偏移量为0,中断EINT0,
46         {   
47             GPFDAT |= (0x7<<4);     // 所有LED熄灭
48             GPFDAT &= ~(1<<4);      // LED1点亮
49             break;
50         }
51         
52         // S3被按下
53         case 2:                     // 偏移量为2,中断EINT2    
54         {   
55             GPFDAT |= (0x7<<4);     // 所有LED熄灭
56             GPFDAT &= ~(1<<5);      // LED2点亮
57             break;
58         }
59 
60         // K4被按下
61         case 5:                     // 偏移量为5,中断EINT8_23
62         {   
63             GPFDAT |= (0x7<<4);     // 所有LED熄灭
64             GPFDAT &= ~(1<<6);      // LED4点亮                
65             break;
66         }
67 
68         default:
69             break;
70     }
71 
72     //清中断,此位可以通过清除 SRCPND和 INTPND 自动清除。
73     if( oft == 5 )            
74         EINTPEND = (1<<11);         // EINTPEND(外部中断挂起寄存器),EINT23-EINT4[23:4],0使能中断,1禁止中断,往相对应位写1,清除此位,这里是清除EINT11
75 
76     SRCPND = 1<<oft;                // SRCPND(源挂起寄存器),EINT0[0]、EINT2 [2]:0未请求,1请求;这里应该是说最后如果是EINT0或EINT2话,往对应位写1就清除此位,
77     INTPND = 1<<oft;                // INTMOD(中断模式寄存器),EINT0[0]、EINT2 [2]0 = IRQ ,1 = FIQ,如果某个指定为被设置为 1 ,则在 FIQ(快中断)模式中处理相应中断。否则则在 IRQ 模式中处理;清除,所以写1
78 }
View Code

 

四、

中断体系结构中断体系结构
int main()
{
    while(1);
    return 0;
}
View Code

 

五、

中断体系结构中断体系结构
 1 objs := head.o init.o interrupt.o main.o                   #定义变量objs为包含的所有.o的合集,以后直接$(objs)就相当于使用罗列了所有的它包含的.o文件
 2 int.bin: $(objs)                                           #生成的int.bin依赖于objs中的.o文件
 3     arm-linux-ld -Ttext 0x00000000 -o int_elf $^           #arm-linux-ld用于将多个目标文件、库文件连接成可执行文件;$^表示所有依赖的名字,名字间用空格分开,这里就表示objs中所有的.o文件
 4                                                            #arm-linux-ld 后面接:-Ttext addr(代码段)、-Tdata addr(数据段)、-Tbss addr(bbs段);
 5     arm-linux-objcopy -O binary -S int_elf $@              #arm-linux-objcopy用来复制一个目标文件的内容到另一个文件中,可以使用不同源文件的格式来输出目的文件,即可以进行格式转换
 6                                                            #-O binary表示输出的格式是二进制.bin的文件;-S表示补充源文件中复制重定位信息和符号信息到目标文件中去;
 7                                                            #$@表示规则的目标文件名, 也就是指的int.bin
 8     arm-linux-objdump -D -m arm int_elf > int.dis          #arm-linux-objdump用于显示二进制文件信息,这里用来查看反汇编
 9                                                            #-D对所有的段执行反汇编;-m arm指反汇编结构为arm反汇编;
10     
11 %.o:%.c                                                    #这里意思就是说,生成的.o文件依赖于.c文件;%是通配符,也就是可以代替任意的文件名;
12     arm-linux-gcc -Wall -O2 -c -o $@ $<                    #编译.c生成.o文件;-Wall是编译后显示警告信息;-O2进行一些优化;-c编译生成.o;s@就是int.bin;$<就是表示第一个依赖的文件名,这里就是所有.c的文件
13 
14 %.o:%.S                                                    #将.S的文件全部转换成.o
15     arm-linux-gcc -Wall -O2 -c -o $@ $<                    #这里$<表示所有的.S的文件
16 
17 clean:                                                     #clean用于清除上一次处理的文件;
18     rm -f int.bin int_elf int.dis *.o                       # *.o表示所有的.o文件          
19     
View Code

 

六、

中断体系结构中断体系结构
/************************************************************************************************************************************************************************************
  用于将所有寄存器及变量宏定义地址指针,宏定义处理后,直接使用或处理这个变量,就相当于直接使用或处理了对应的地址的内容
************************************************************************************************************************************************************************************/
看门狗定时器控制寄存器
/**********************/
#define     WTCON           (*(volatile unsigned long *)0x53000000)

/*******************
存储控制器和SDRAM
*******************/
#define     MEM_CTL_BASE    0x48000000
#define     SDRAM_BASE      0x30000000

/**********************
 NAND Flash registers 
 **********************/
#define NFCONF              (*(volatile unsigned int  *)0x4e000000)
#define NFCMD               (*(volatile unsigned char *)0x4e000004)
#define NFADDR              (*(volatile unsigned char *)0x4e000008)
#define NFDATA              (*(volatile unsigned char *)0x4e00000c)
#define NFSTAT              (*(volatile unsigned char *)0x4e000010)

/*******************
GPIO registers
*******************/
#define GPBCON              (*(volatile unsigned long *)0x56000010)
#define GPBDAT              (*(volatile unsigned long *)0x56000014)

#define GPFCON              (*(volatile unsigned long *)0x56000050)
#define GPFDAT              (*(volatile unsigned long *)0x56000054)
#define GPFUP               (*(volatile unsigned long *)0x56000058)

#define GPGCON              (*(volatile unsigned long *)0x56000060)
#define GPGDAT              (*(volatile unsigned long *)0x56000064)
#define GPGUP               (*(volatile unsigned long *)0x56000068)

#define GPHCON              (*(volatile unsigned long *)0x56000070)
#define GPHDAT              (*(volatile unsigned long *)0x56000074)
#define GPHUP               (*(volatile unsigned long *)0x56000078)



/*****************
UART registers
*****************/
#define ULCON0              (*(volatile unsigned long *)0x50000000)
#define UCON0               (*(volatile unsigned long *)0x50000004)
#define UFCON0              (*(volatile unsigned long *)0x50000008)
#define UMCON0              (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0            (*(volatile unsigned long *)0x50000010)
#define UTXH0               (*(volatile unsigned char *)0x50000020)
#define URXH0               (*(volatile unsigned char *)0x50000024)
#define UBRDIV0             (*(volatile unsigned long *)0x50000028)


/*******************
interrupt registes
*******************/
#define SRCPND              (*(volatile unsigned long *)0x4A000000)
#define INTMOD              (*(volatile unsigned long *)0x4A000004)
#define INTMSK              (*(volatile unsigned long *)0x4A000008)
#define PRIORITY            (*(volatile unsigned long *)0x4A00000c)
#define INTPND              (*(volatile unsigned long *)0x4A000010)
#define INTOFFSET           (*(volatile unsigned long *)0x4A000014)
#define SUBSRCPND           (*(volatile unsigned long *)0x4A000018)
#define INTSUBMSK           (*(volatile unsigned long *)0x4A00001c)

/******************************
external interrupt registers
*******************************/
#define EINTMASK            (*(volatile unsigned long *)0x560000a4)
#define EINTPEND            (*(volatile unsigned long *)0x560000a8)
View Code