一、实验平台:开发板fs2410,采用三星s3c2410的CPU,无操作系统。
二、实现功能:主程序让D9闪烁,用K1触发中断,点亮D12
三、实验原理:
Fs2410开发板共有56个中断源,其中有24个外部中断,中断产生后,cpu会进入中断模式,程序计数器(PC)会跳转到异常向量表(IRQ中断时跳转到ox18处),执行相应的指令,一般为跳转指令,跳转到中断处理程序,完成相应的功能。
中断产生后,CPU会停止正在运行的程序,转去执行中断程序,处理完中断程序后再返回接着处理被打断的程序。
四、实验现象:
按下开关K1时,D12被点亮,D9保持现有状态不变,松开开关K1时,D12熄灭。D9继续闪烁。
五、实验总结:
1、要清楚中断的流程,如使能中断和清除中断的步骤;
2、请入中断后,首先要保护现场(各共有寄存器的值、返回地址);
3、中断程序完成后,要恢复现场。
六、示例代码:
@******************************************************************************
@ File:head.S
@ 功能:初始化,设置中断模式、系统模式的栈,设置好中断处理函数
@******************************************************************************
.equ MEM_CTL_BASE, 0x48000000
.equ SDRAM_BASE, 0x30000000
.text
.global _start
_start:
@******************************************************************************
@ 初始化向量向量表,本程序中,除Reset和HandleIRQ外,其它异常都没有使用
@******************************************************************************
b Reset
@ 0x04: 未定义指令中止模式的向量地址
HandleUndef:
b HandleUndef
@ 0x08: 管理模式的向量地址,通过SWI指令进入此模式
HandleSWI:
b HandleSWI
@ 0x0c: 指令预取终止导致的异常的向量地址
HandlePrefetchAbort:
b HandlePrefetchAbort
@ 0x10: 数据访问终止导致的异常的向量地址
HandleDataAbort:
b HandleDataAbort
@ 0x14: 保留
HandleNotUsed:
b HandleNotUsed
@ 0x18: 中断模式的向量地址
b HandleIRQ
@ 0x1c: 快中断模式的向量地址
HandleFIQ:
b HandleFIQ
Reset:
@ 关闭WATCHDOG,否则CPU会不断重启
@ 往WATCHDOG寄存器写0即可
mov r1, #0x53000000
mov r2, #0x0
str r2, [r1]
@时钟初始化
pllsetup:
ldr r0,=0x4c000000 @LOCKTIME
ldr r1,=0x00ffffff
str r1,[r0]
ldr r0,=0x4c000014 @CLKDIVN
ldr r1,=0x3
str r1,[r0]
@/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
mrc p15, 0, r1, c1, c0, 0 @/* 读出控制寄存器 */
orr r1, r1, #0xc0000000 @/* 设置为“asynchronous bus mode” */
mcr p15, 0, r1, c1, c0, 0 @/* 写入控制寄存器 */
ldr r0,=0x4c000004 @MPLLCON
ldr r1,=0x5c040
str r1,[r0]
@ 设置存储控制器
@ 设置存储控制器以便使用SDRAM等外设
mov r1, #MEM_CTL_BASE @ 存储控制器的13个寄存器的开始地址
adrl r2, mem_cfg_val @ 这13个值的起始存储地址
add r3, r1, #52 @ 13*4 = 52
1:
ldr r4, [r2], #4 @ 读取设置值,并让r2加4
str r4, [r1], #4 @ 将此值写入寄存器,并让r1加4
cmp r1, r3 @ 判断是否设置完所有13个寄存器
bne 1b @ 若没有写成,继续
@搬运代码到SDRAM
@ 将Steppingstone的4K数据全部复制到SDRAM中去
@ Steppingstone起始地址为0x00000000,SDRAM中起始地址为0x30000000
mov r1, #0
ldr r2, =SDRAM_BASE
mov r3, #4*1024
1:
ldr r4, [r1],#4 @ 从Steppingstone读取4字节的数据,并让源地址加4
str r4, [r2],#4 @ 将此4字节的数据复制到SDRAM中,并让目地地址加4
cmp r1, r3 @ 判断是否完成:源地址等于Steppingstone的未地址?
bne 1b @ 若没有复制完,继续
ldr pc,=on_sdram @让PC跳到SDRAM中继续执行
on_sdram:
@堆栈初始化,初始化IRQ和SYSTEM模式的堆栈
@init_stack:
msr cpsr_c, #0xd2 @ 进入中断模式
ldr sp, =0x33fffc00 @ 设置中断模式栈指针
msr cpsr_c, #0xdf @ 进入系统模式
ldr sp, =0x34000000 @ 设置系统模式栈指针,
@ 其实复位之后,CPU就处于系统模式,
bl eint_init @ 调用中断初始化函数,在init.c中
msr cpsr_c, #0x5f @ 设置I-bit=0,开IRQ中断
ldr lr, =halt_loop @ 设置返回地址
ldr pc, =main @ 调用main函数 相等于bl main
halt_loop:
b halt_loop
HandleIRQ:
sub lr, lr, #4 @ 计算返回地址
stmfd sp!, { r0-r12,lr } @ 保存使用到的寄存器
@ 注意,此时的sp是中断模式的sp
@ 初始值是上面设置的0x33fffc0
@ldr lr, =int_return @ 设置调用ISR即EINT_Handle函数后的返回地址
@ldr pc, =EINT_Handle @ 调用中断服务函数,在interrupt.c中
@int_return:
bl light_on @中断处理函数
ldmfd sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr
.align 4
mem_cfg_val:
@ 存储控制器13个寄存器的设置值
.long 0x22111120 @ BWSCON
.long 0x00000700 @ BANKCON0
.long 0x00000700 @ BANKCON1
.long 0x00000700 @ BANKCON2
.long 0x00000700 @ BANKCON3
.long 0x00000700 @ BANKCON4
.long 0x00000700 @ BANKCON5
.long 0x00018005 @ BANKCON6
.long 0x00018005 @ BANKCON7
.long 0x008E0459 @ REFRESH
.long 0x000000B2 @ BANKSIZE
.long 0x00000030 @ MRSRB6
.long 0x00000030 @ MRSRB7
/*irq.c*/
#define SRCPND (*(volatile unsigned long *)0x4a000000)
#define INTMOD (*(volatile unsigned long *)0x4a000004)
#define INTMASK (*(volatile unsigned long *)0x4a000008)
#define INTPND (*(volatile unsigned long *)0x4a000010)
#define EXTINT2 (*(volatile unsigned long *)0x56000090)
#define EINTMASK (*(volatile unsigned long *)0x560000a4)
#define EINTPEND (*(volatile unsigned long *)0x560000a8)
#define GPECON (*(volatile unsigned long *)0x56000040)
#define GPEDAT (*(volatile unsigned long *)0x56000044)
#define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)
#define GPGCON (*(volatile unsigned long *)0x56000060)
#define GPE11_out (1<<22)
#define GPF4_out (1<<8)
#define GPF5_out (1<<10)
#define GPF6_out (1<<12)
#define GPF7_out (1<<14)
#define GPG11_int (2<<22)
void eint_init(void)
{
GPECON = GPE11_out; //GPE11输出低电平
GPEDAT &= ~(1<<11);
GPGCON = GPG11_int;
EXTINT2 |= (1<<13); //EINT19设为下降沿触发
EINTPEND = 0; //清除所有外部中断挂起状态
SRCPND = 0; //清除所有源挂起状态
INTPND = 0; //清除所有挂起状态
INTMOD = 0; //设置为IRQ模式
EINTMASK &= ~(1<<19); //EINT19允许响应
INTMASK &= ~(1<<5); //EINT8-23允许响应
}
void light_on(void) //中断处理程序
{
if((EINTPEND&(1<<19)) && (SRCPND&(1<<5))){ //有中断请求
GPFDAT &= ~(1<<4); //点亮D12
EINTPEND |= (1<<19); //清中断,写1清0
SRCPND |= (1<<5);
INTPND = INTPND; //清除响应的中断
}
}
void wait(unsigned long dly)
{
for(;dly>0;dly--);
}
int main(void) //主程序,让D9闪烁
{
GPFCON = GPF4_out|GPF5_out|GPF6_out|GPF7_out;
GPFDAT |= 0xf0;
while(1){
GPFDAT &= ~(1<<7);
wait(200000);
GPFDAT |= 0xf0;
wait(200000);
}
return 0;
}