实验目的
1,实现KEY1/LEY2/KE3三个按键,中断触发打印一句话
2,实现KEY1/LEY2/KE3三个按键按下之后,灯的状态取反
1,异常源:异常源引发处理器进入对应的异常模式
2,异常模式 === 异常源 ===
FIQ FIQ类型异常源
IRQ IRQ类型异常源
SVC reset(复位异常源)
swi(软中断指令)
ABORT data abort(取数据中止)
prefetch abort(取指令中止)
UNDEF UNDEF未定义异常源
3,五种异常模式,对应7中异常源,根据不同的异常源,进入不同的异常模式,执行异常处理函数,异常源具有优先级,复位的优先级最高
1:概念:异常向量表就是内存的一块寻址空间,共32个字节,分为8份,存放7中异常源,一份保留,地址是固定的,不可以随意修改。通过指定异常向量表的基地址和偏移地址,就可以找到相应的异常源,执行异常处理程序
2:为什么引入异常向量表:每个人编写的程序入口(函数名)不一致,但是可以通过地址指定异常处理异常程序的入口一致
分为4大步,3小步:
1,保存CPSR寄存器中的值到SPSR_
2,修改CPSR寄存器的值
1>修改CPSR寄存器中的T位(状态位),T=0,当前的状态为arm状态,指向arm指令集
2>根据需要,禁止相应的 I / F中断位
3>修改CPSR寄存器中第 [4:0] 位,为对应异常模式
3,保存函数的返回地址到LR寄存器中
4,修改PC指向异常向量表
分为两步
1,将LR寄存器中的值,恢复给PC
2,将SPER_
指令码:SWI
指令格式:SWI 终端号(0 ~ 0xFFFFFF)
验证流程实例代码:
.text
.global _start
_start:
@1.构建异常向量表
b reset
b undef_interrupt
b software_interrupt
b prefetch_dataabort
b data_abort
b .
b irq
b fiq
reset:
@2.系统一上电,程序运行在SVC模式
@1> 初始化SVC模式下,栈指针
ldr sp,=0x40000800
@3.从SVC模式切换到user模式
msr cpsr,#0xD0
@4.user模式下代码
@1> 初始化user模式下,栈指针
ldr sp,=0x40000700
mov r0,#0x1
mov r1,#0x2
@4.执行软中断指令 ===> 保存现场(四大步三小步)
swi 2
add r0,r0,r1 @ r0 = 0x3
b stop
undef_interrupt:
software_interrupt:
@压栈保存现场
stmfd sp!,{r0-r12,lr}
mov r0,#0x3
mov r1,#0x4
add r0,r0,r1 @ r0 = 0x7
@出栈恢复现场
ldmfd sp!,{r0-r12,pc}^
@^:将SPSR_寄存器中的值,给到CPSR寄存器中
prefetch_dataabort:
data_abort:
irq:
fiq:
stop:
b stop
.end
中断触发方式:下降沿
网络编号 == 引脚号
KEY1 === PF9
KEY2 === PF7
KEY3 === PF8
1,根据框图,需要分析RCC / GPIO / EXTI / GIC章节
2:RCC:使能GPIOF组寄存器(EXTI / GIC不属于核外寄存器,不需要使能,上电自动运行)
3:GPIO:设置引脚为输入模式
4:EXTI:设置中断触发方式(下降沿触发)
5:GIC:检测哪一个按键按下
中断触发流程:RCC使能 == GPIOF输入 == EXTI设置触发方式 == GIC检测按键 == A7核接收到中断信号,执行中断处理函数
GPIO:AHB4
GICC === 0xA0022000
GICD === 0xA0021000
GPIOF === 0x50007000
EXTI === 0x5000D000
作用:使能GPIOF组寄存器
地址:0x50000000 + 0xA28 = 0x50000A28
伪代码:RCC_MP_AHB4ENSETR [5] = 1
作用:设置GPIO引脚模式为输入模式(输入,输出,复用,模拟)
地址:0x50007000 + 0x00 = 0x50007000
伪代码:GPIOF_MODER [19:18] = 10 === KEY1
GPIOF_MODER [17:16] = 10 === KEY2
GPIOF_MODER [15:14] = 10 === KEY3
EXTI external interrupt selection register === 外部中断选择寄存器
作用:设置GPIO引脚信号与EXTI进行连接 === 将外部按键信号经过GPIO控制器,转发到EXTI控制器
伪代码:EXTI_EXTICR3[15:8] = 0x05 ----> 设置KEY1按键与EXTI9进行连接
EXTI_EXTICR2[31:24] = 0x05 ----> 设置KEY2按键与EXTI7进行连接
EXTI_EXTICR3[7:0] = 0x05 ----> 设置KEY1按键与EXTI8进行连接
作用:设置中断信号为下降沿触发方式
伪代码:EXTI_FTSR1[9] = 1 ----> 设置KEY1按键为下降沿触发方式
EXTI_FTSR1[7] = 1 ----> 设置KEY2按键为下降沿触发方式
EXTI_FTSR1[8] = 1 ----> 设置KEY3按键为下降沿触发方式
作用:设置中断不屏蔽 === EXTI层中断转发到GIC层
伪代码:EXTI_IMR1[9] = 1 ----> 设置KEY1按键中断不屏蔽
EXTI_IMR1[7] = 1 ----> 设置KEY2按键中断不屏蔽
EXTI_IMR1[8] = 1 ----> 设置KEY3按键中断不屏蔽
作用:清除EXTI层中断挂起标志位
rc_w1作用:读0:表示中断没有触发
读1:表示中断触发
写0:不清除EXTI层中断挂起标志位
写1:清除EXTI层中断挂起标志位
伪代码:EXTI_FPR1[9] = 1 ----> 清除key1按键EXTI层中断挂起标志位
EXTI_FPR1[7] = 1 ----> 清除key2按键EXTI层中断挂起标志位
EXTI_FPR11[8] = 1 ----> 清除key3按键EXTI层中断挂起标志位
SGI:Software generated interrupts ==> 软件产生中断(软中断)
PPI:Private peripheral interrupts ==> 私有外设中断
SPI:Shared peripheral interrupts ==> 共享外设中断
1,GIC层共有288个中断号(0 ~ 287)
2,16个PPIS(ID:16 ~ 31),16个SGIS(ID:0 ~ 15),256个SPIS(ID:32 ~ 287)
按键中断号: 97 === EXTI7
98 === EXTI8
99 === EXTI9
作用:设置GICD组0使能
伪代码:GICD_CTLR [0] = 1
作用:设置GICD层中断使能
伪代码:EXTI9 ----> 中断号99 ----> GICD_ISENABLER3[3] = 1
EXTI7 ----> 中断号97 ----> GICD_ISENABLER3[1] = 1
EXTI8 ----> 中断号98 ----> GICD_ISENABLER3[2] = 1
作用:设置GICD层中断优先级寄存器,GICD层优先级需要比GICC层优先级高,才能转发到GICC层(值的范围 0 ~ 2^5 -1,数字越小,优先级越高)
伪代码:中断号99 ---->GICD_IPRIORITYR24[31:27] = 0b00000
中断号97 ---->GICD_IPRIORITYR24[15:11] = 0b00000
中断号98 ---->GICD_IPRIORITYR24[23:19] = 0b00000 (值自定义)
作用:设置GICD层中断目标分配给CPU0
0b00---不分配
0b01---分配给CPU0
0b10---分配给CPU1
0b11---分配给CPU0 和 CPU1
伪代码:GICD_ITARGETSR24[25:24] = 0b01
GICD_ITARGETSR24[9:8] = 0b01
GICD_ITARGETSR24[17:16] = 0b01
作用:清除GICD层中断挂起标志位
挂起:暂时被淘汰出内存
伪代码:中断号99 ----> GICD_ICPENDR3[3] = 1 ----> 清除key1按键GICD层中断挂起标志位
中断号97 -----> GICD_ICPENDR3[1] = 1 ----> 清除key2按键GICD层中断挂起标志位
中断号98 ----> GICD_ICPENDR3[2] = 1 ----> 清除key3按键GICD层中断挂起标志位
作用:设置GICC层组0使能
伪代码:GICC_CTLR [0] = 1
作用:设置GICC层的优先级
伪代码:GICC_PMR [7:3] = 0b11111(自定义)
作用:获取中断号
伪代码: num = GICC_IAR
作用:清除获取到的中断号
GICC_EOIR = num