中断处理实验主要在片内SRAM中进行了实验。其中中断的过程主要注意一下,都已经在截图的文字中说明了。
下面看下代码,代码都有很清晰的注释了。
首先是Makefile,可以看出运行的地址从0x00000000开始的片内SRAM中,程序很小,只有272字节,因此没有必要动用SDRAM。
int.bin:head.S init.c
arm-linux-gcc-O2 -c -o head.o head.S
arm-linux-gcc-O2 -c -o init.o init.c
arm-linux-ld-Ttext 0x00000000 head.o init.o -o int_elf
arm-linux-objcopy-O binary -S int_elf int.bin
arm-linux-objdump-D -m arm int_elf > int.dis
clean:
rm-f head.o init.o int.bin int.dis int_elf
下面是汇编主程序
.text
.global _start
_start:
blreset @0x00000000 重启
HandleUndef: @0x00000004 未定义异常
bHandleUndef
HandleSWI: @0x00000008 软中断异常
bHandleSWI
HandlePrefetchAbt: @ 0x0000000C 预取指令处理异常
bHandlePrefetchAbt
HandleDataAbt: @0x00000010 数据访问终止异常
bHandleDataAbt
HandleNoUsed: @0x00000014 未使用异常
bHandleNoUsed
b HandleIRQ @0x00000018 中断异常
HandleFIQ: @0x0000001C 快速中断异常
bHandleFIQ
HandleIRQ:
sublr,lr,#4 @将lr-4,指向
stmdbsp!,{r0-r12,lr} @ 将r0-r12保存,并将lr作为下一个返回地址保存
blhandle_irq @ 由于handle_irq在片内SRAM中,bl的地址范围足够
@ 如果handle_irq在SDRAM中,需要用寻址范围更大的ldrpc,=***,并保存lr作为返回地址
ldmiasp!,{r0-r12,pc}^ @ 将r0-r12恢复,lr恢复到pc中,即相当于跳转到被中断地址了
@^表示当寄存器列表中有pc的时候,将spsr的内容返回到cpsr中
@!表示sp为最后的地址,即自动的修改栈顶指针
reset:
ldrsp,=4096 @设置刚刚开启CPU的栈指针
blclose_watchdog @关闭看门狗
@ blinit_sdram @初始化SDRAM 并没有使用SDRAM,所以,这句话可以屏蔽掉
msrcpsr_c,#0xD2 @进入中断模式
ldrsp,=3074 @设置中断模式下的栈指针
msrcpsr_c,#0xD3 @进入管理模式
ldrsp,=4096 @设置系统模式下的栈指针
blinit_led_int @初始化中断和LED等
msrcpsr_c,#0x53 @开启IRQ中断
loop:
bloop @设置循环
然后是子函数代码
#define GPBCON(*(volatile unsigned long *)0x56000010)
#define GPBDAT(*(volatile unsigned long *)0x56000014)
#define GPGCON(*(volatile unsigned long *)0x56000060)
#define GPGDAT(*(volatile unsigned long *)0x56000064)
#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)
#defineINTOFFSET (*(volatile unsigned long *)0x4A000014)
#defineSUBSRCPND (*(volatile unsigned long *)0X4A000018)
#defineINTSUBMSK (*(volatile unsigned long *)0x4A00001C)
#define EXTINT1(*(volatile unsigned long *)0x5600008c)
#define EINTMASK(*(volatile unsigned long *)0x560000a4)
#define EINTPEND(*(volatile unsigned long *)0x560000a8)
voidclose_watchdog()
{
#definerWTCON (*(volatile unsigned long *)0x53000000)
rWTCON= 0;
}
voidinit_led_int()
{
/*
使用K1,GPG0接口,EINT8外部中断,属于EINT8_23的子中断
LED1作为显示,GPB5
*/
//1初始化LED相关内容GPB5
GPBCON&= ~(3<<10);
GPBCON|= 1<<10; //设置GPB5为输出
GPBDAT&= ~(1<<5); //LED初始化为亮
//2设置中断相关
//2.1将IO设置为外部中断模式
GPGCON&= ~(3<<0);
GPGCON|= 2<<0; //将GPG0设置为EINT8
//2.1设置相应的寄存器,屏蔽中断
//INTMOD默认为0,也就是所有中断均使用IRQ模式
//PRIORITY默认 INTSUBMSK和INTSUBMSK因为子中断没有用到而默认
INTMSK= ~(1<<5); //除了EINT8_23中断的其他中断都被屏蔽
EINTMASK= ~(1<<8); //屏蔽除EINT8的其他中断
EXTINT1&= ~(0xF);
EXTINT1|= 0xA; //设置下降沿触发,滤波
}
voidhandle_irq()
{
if(INTOFFSET== 5)
{
GPBDAT|= 1<<5; //关闭LED
}
SRCPND= 1<<5;
EINTPEND= 1<<8;
INTPND= 1<<5; //清中断位
}
值得一提的是实验使用==语句并没有出现问题,与上一次遇到的情况不同。也不太确定原因。