《朱老师物联网大讲堂》学习笔记
学习地址:www.zhulaoshi.org
像内存一样去访问异常向量表。
在我们开发板中iRAM的向量异常表的起始地址为0xd0037400,
结合上节说的,相对地址是固定的,而这里起始地址又确定了,
各种异常对应的入口地址就很好知道了。
函数名的实质就是函数的首地址,拿C语言中的语言来讲,函数名就是这个函数的函数指针,
将异常向量表和异常处理程序的首地址绑定起来后,异常处理初步阶段就完成了,
目前如果相应异常发生后,硬件自动跳转到对应异常向量表入口去执行,进而执行我们事先绑定的函数。
第一眼看到下面的异常向量表绑定,会觉得不知所以,其实前面有宏定义,
#define exception_vector_table_base 0xD0037400
#define exception_reset (exception_vector_table_base + 0x00)
#define r_exception_reset (*(volatile unsigned int *)exception_reset)
void system_init_exception(void)
{
r_exception_reset = (unsigned int)reset_exception;
r_exception_undef = (unsigned int)undef_exception;
r_exception_sotf_int = (unsigned int)sotf_int_exception;
r_exception_prefetch = (unsigned int)prefetch_exception;
r_exception_data = (unsigned int)data_exception;
r_exception_irq = (unsigned int)IRQ_handle;
r_exception_fiq = (unsigned int)IRQ_handle;
intc_init();
}
为什么中断处理要先在汇编中进行,
因为中断是从SVC模式开始的,要保存该模式下必要的寄存器值,
中断完成后返回SVC,恢复这些寄存器的值,
否则SVC模式寄存器的值就乱了,SVC模式下原来正在进行的常规任务就被你破坏了。
现场保存包括
1.设置IRQ栈,各个模式的栈不同,所以各自要单独设置,
ldr sp, IRQ_STACK
sp名字只有一个,不过在不同模式下会自动切换到对应的sp,
2.保存LR,中断返回时2个关键寄存器就是pc和CPSR,
在进入IRQ模式时,应该将SVC模式下的下一句指令的地址和CPSR保存起来,
将来恢复时将返回地址给PC,将保存的CPSR给CPSR,
中断返回地址就保存在LR中,而CPSR自动保存在IRQ的SPSR中,
3.保存R0~R12。
#define IRQ_STACK 0xd0037f80
IRQ_handle:
ldr sp, IRQ_STACK
sub lr, lr, #4
//这里的4这样理解,+8-4,因为是3级指令,
stmfd sp! {r0-r12, lr}
bl irq_handler
ldrfd sp! {r0-r12, pc}^