> 文章列表 > IMX6ULL中断之复位中断函数实现

IMX6ULL中断之复位中断函数实现

IMX6ULL中断之复位中断函数实现

一.   复位中断函数

开发板一上电或者进行一次复位操作,其就会执行复位中断函数。复位中断函数可能需要实现的一些功能,包括进入 SVC(特权)模式,清除 bss段,设置 SP指针等。

二.  复位中断函数实现

1.  复位中断函数工作如下:

(1)  关闭全局中断。
参考正点原子提供的资料【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6,第17章 GPIO中断实验,关闭全局中断需要用到的指令如下:

cpsid i     //禁止 IRQ 中断
cpsie i     //使能 IRQ 中断

(2)   关闭 I Cache,D Cache 和 MMU。

关闭这些需要用到 CP15处理器的一些指令操作。

(3)  设置中断向量偏移。

ARM 处理器都是从地址 0X00000000 开始运行的,通过中断向量表偏移就可以将中断向量表存放到任意地址。

注意:设置中断向量偏移这个操作,也可以在 C语言中进行设置。只要在中断发生之前设置好就可以。

(4) 设置处理器9种工作模式下对应的SP指针。

要使用中断,那么必须设置 IRQ 模式下的 SP 指针。索性直接设置所有模式下的 SP 指针。(因为对于 Cortex-A系列的芯片而言, 内核 CPU 的所有外部中断都属于这个 IRQ 中断)

(5)  清除 bss段。

(6)  跳到 C函数,也就是 main() 函数。

2.  代码实现分析

下面分析以上内容的实现。分析如下:

(1)  关闭 I Cache,D Cache 和 MMU。

关闭这些涉及 CP15协处理器的一些指令操作。

参考 "参考资料" 目录下Cortex-A7 Technical ReferenceManua.pdf 文档的 55 页,可知如下指令:

MRC 指令: 读取 CP15 协处理器中的寄存器数据到 ARM 寄存器中。

MCR 指令:写 CP15 寄存器

格式如下:

MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>

cond:  指令执行的条件码,如果忽略的话就表示无条件执行。
opc1:协处理器要执行的操作码。
Rt     ARM 源寄存器,要写入到 CP15 寄存器的数据就保存在此寄存器中。
CRn CP15 协处理器的目标寄存器。
CRm协处理器中附加的目标寄存器或者源操作数寄存器,如果不需要附加信息就将 CRm设置为 C0,否则结果不可预测。
opc2可选的协处理器特定操作码,当不需要的时候要设置为 0

参考 Cortex-A7 Technical ReferenceManua.pdf 文档,可找到 SCTLR寄存器。该寄存器即可关闭/打开 I-Cache,D-Cache,MMU。

例如如下指令操作:

MRC p15, 0, R0, c1, c0, 0  //读取 SCTLR寄存器值到ARM的R0寄存器中
MCR p15, 0, R0, c1, c0, 0  //将ARM的R0寄存器的值写到 SCTLR寄存器中

(2)  设置中断向量偏移

将新的中断向量表首地址写入到 CP15协处理器的 VBAR 寄存器。参考资料Cortex-A7 Technical ReferenceManua.pdf 文档 第 B3.17 章节 指令使用方法如 MRC一样。

3.  汇编代码实现

汇编文件 start.S 代码实现如下:

.global _start
.global _bss_start
_bss_start:.word _bss_start
.global _bss_end
_bss_end:.word _bss_end_start:ldr pc, =Reset_Handler		/* 复位中断  */	ldr pc, =Undefined_Handler	/* 未定义中断 	*/ldr pc, =SVC_Handler		/* SVC(Supervisor)中断 */ldr pc, =PrefAbort_Handler	/* 预取终止中断 */ldr pc, =DataAbort_Handler	/* 数据终止中断 */ldr	pc, =NotUsed_Handler	/* 未使用中断 */ldr pc, =IRQ_Handler		/* IRQ中断 	*/ldr pc, =FIQ_Handler		/* FIQ(快速中断)未定义中断 	*//* 复位中断服务函数 */	
Reset_Handler:cpsid i   //禁止IRQ中断MRC p15, 0, r0, c1, c0, 0  //读取 SCTLR寄存器值到ARM的R0寄存器中bic r0, r0, #(1 << 12) //关闭 I-Cachebic r0, r0, #(1 << 11) //关闭分支预测bic r0, r0, #(1 << 2)  //关闭 D-Cachebic r0, r0, #(1 << 1)  //关闭对齐bic r0, r0, #(1 << 0)  //关闭 MMUMCR p15, 0, R0, c1, c0, 0 //将ARM的R0寄存器的值写到SCTLR寄存器中/*设置中断向量 */ldr r0, =0x87800000dsb  //数据同步isb  //指令同步MCR p15, 0, r0, c12, c0, 0 //将0x87800000地址写入C15协处理器VBAR寄存器dsbisb/*清除BSS段 */ldr r0, _bss_startldr r1, _bss_endmov r2, #0
bss_loop:           /*循环 */stmia r0!, {r2}  cmp r0, r1ble bss_loop    /* 如果小于等于的话就跳转到bss_loop继续清bss段*//*配置处理器模式为 IRQ模式*/mrs r0, cpsr      /*将cpsr寄存器中的值读到r0寄存器*/bic r0, r0, #0x1f /*清零cprs寄存器的 bit[4~0]位*/orr r0, r0, #0x12 /*设置处理器模式为 SVC模式*/msr cpsr, r0      /*写到 cpsr 寄存器中*/ldr sp, =0x80600000 //设置 SVC模式下的 sp 指针/*配置处理器模式为 SYS模式*/mrs r0, cpsr      /*将cpsr寄存器中的值读到r0寄存器*/bic r0, r0, #0x1f /*清零cprs寄存器的 bit[4~0]位*/orr r0, r0, #0x1f /*设置处理器模式为 SVC模式*/msr cpsr, r0      /*写到 cpsr 寄存器中*/ldr sp, =0x80400000 //设置 SVC模式下的 sp 指针/*配置处理器模式为 SVC模式*/mrs r0, cpsr      /*将cpsr寄存器中的值读到r0寄存器*/bic r0, r0, #0x1f /*清零cprs寄存器的 bit[4~0]位*/orr r0, r0, #0x13 /*设置处理器模式为 SVC模式*/msr cpsr, r0      /*写到 cpsr 寄存器中*/ldr sp, =0x80200000 //设置 SVC模式下的 sp 指针cpsie i   //打开IRQ 
/*跳转到 C 语言 main函数*/b main    /* 未定义中断服务函数 */
Undefined_Handler:ldr r0, =Undefined_Handlerbx r0/* SVC中断服务函数 */
SVC_Handler:ldr r0, =SVC_Handlerbx r0/* 预取终止中断服务函数 */
PrefAbort_Handler:ldr r0, =PrefAbort_Handler	bx r0/* 数据终止中断服务函数 */
DataAbort_Handler:ldr r0, =DataAbort_Handlerbx r0/* 未使用的中断服务函数 */
NotUsed_Handler:ldr r0, =NotUsed_Handlerbx r0/* IRQ中断服务函数!重点!!!!! */
IRQ_Handler:ldr r0, =IRQ_Handlerbx r0/* FIQ中断服务函数 */
FIQ_Handler:ldr r0, =FIQ_Handler	bx r0	

通过开发板测试验证,开发板上的复位键按键按下后,蜂鸣器正常响。灯也是正常闪烁。