天天看点

1.8.5.异常向量表的编程处理

朱老师笔记

1.8.5.1、像内存一样去访问异常向量表

(1)S5PV210的异常向量表可以改变(在CP15协处理器中),以适应操作系统的需求。但是目前系统刚启动时,此时DRAM尚未初始化,程序都在SRAM中运行。210在iRAM中设置了异常向量表,供暂时性使用。

(2)查210的iROM application note文档中iRAM的地址分配,可知,iRAM中的异常向量表起始地址为0xD0037400。知道了异常向量表的起始地址后,各个异常对应的入口就很好知道了。

1.8.5.2、函数名的实质就是函数的首地址

(1)函数名在C语言中的理解方法和变量名其实没区别。编译器会把这个函数的函数体对应的代码段和这个函数的函数名(实质是符号)对应起来,等我们在使用这个函数名符号时,编译器会将函数的函数体实际上做替换。因为函数体都不止4字节,而函数名这个符号只能对应1个地址,所以实际对应的是函数体那一个代码段的首地址。

(2)拿C语言中的语法来讲,函数名就是这个函数的函数指针。

总结:当我们将异常处理程序的首地址和异常向量表绑定起来后,异常处理初步阶段就完成了。到目前可以保证相应异常发生后,硬件自动跳转到对应异常向量表入口去执行时,可以执行到我们事先绑定的函数。

1.8.5.3、为什么中断处理要先在汇编中进行

(1)中断处理要注意保护现场(中断从SVC模式来,则保存SVC模式下的必要寄存器的值)和恢复现场(中断处理完成后,准备返回SVC模式前,要将保存的SVC模式下的必要寄存器的值恢复回去,不然到了SVC模式后寄存器的值乱了,SVC模式下原来正在进行的常规任务就被你搞坏了)

(2)保存现场包括:第一:设置IRQ栈;第二,保存LR;第三,保存R0~R12

(3)为什么要保存LR寄存器?要考虑中断返回的问题。中断ISR执行完后如何返回SVC模式下去接着执行原来的代码。中断返回其实取决于我们进入中断时如何保存现场。中断返回时关键的2个寄存器就是PC和CPSR。所以我们在进入IRQ模式时,应该将SVC模式下的下一句指令的地址(中断返回地址)和CPSR保存起来,将来恢复时才可以将中断返回地址给PC,将保存的CPSR给CPSR。

(4)中断返回地址就保存在LR中,而CPSR(自动)保存在(IRQ模式下的)SPSR中

1.8.5.4、汇编保存现场和恢复现场

(1)保护现场关键是保存:中断处理程序的返回地址,r0-r12(cpsr是自动保存的)

(2)恢复现场主要是恢复:r0-r12,pc,cpsr

《朱老师物联网大讲堂》学习笔记

学习地址:www.zhulaoshi.org

像内存一样去访问异常向量表。

在我们开发板中iRAM的向量异常表的起始地址为0xd0037400,

结合上节说的,相对地址是固定的,而这里起始地址又确定了,

各种异常对应的入口地址就很好知道了。

1.8.5.异常向量表的编程处理

函数名的实质就是函数的首地址,拿C语言中的语言来讲,函数名就是这个函数的函数指针,

将异常向量表和异常处理程序的首地址绑定起来后,异常处理初步阶段就完成了,

目前如果相应异常发生后,硬件自动跳转到对应异常向量表入口去执行,进而执行我们事先绑定的函数。

第一眼看到下面的异常向量表绑定,会觉得不知所以,其实前面有宏定义,

#define exception_vector_table_base  0xD0037400

#define exception_reset     (exception_vector_table_base + 0x00)

#define r_exception_reset  (*(volatile unsigned int *)exception_reset)

[plain]  view plain  copy

  1. void system_init_exception(void)  
  2. {  
  3.     r_exception_reset = (unsigned int)reset_exception;  
  4.     r_exception_undef = (unsigned int)undef_exception;  
  5.     r_exception_sotf_int = (unsigned int)sotf_int_exception;  
  6.     r_exception_prefetch = (unsigned int)prefetch_exception;  
  7.     r_exception_data = (unsigned int)data_exception;  
  8.     r_exception_irq = (unsigned int)IRQ_handle;  
  9.     r_exception_fiq = (unsigned int)IRQ_handle;   
  10.     intc_init();  
  11. }  

为什么中断处理要先在汇编中进行,

因为中断是从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

[cpp]  view plain  copy

  1. IRQ_handle:  
  2.     ldr sp, IRQ_STACK  
  3.     sub lr, lr, #4  
  4. //这里的4这样理解,+8-4,因为是3级指令,  
  5.     stmfd sp!   {r0-r12, lr}  
  6.     bl  irq_handler  
  7.     ldrfd   sp! {r0-r12, pc}^