目录
VTOR(Vector Table Offset Register)寄存器
相关的关键寄存器
VTOR(Vector Table Offset Register)寄存器
其中保存了中断向量表(Vector Table)的首地址,此地址必须是4*(2^n)的倍数,(2^n)需要大于(不能等于)处理器支持的中断数量。
比如STM32支持的中断一共有68(for interrupts)+16(for system exception)=84个,那么最小的(2^n)等于128,128*4=512(十六进制为0x200),所以STM32处理器的中断向量表的地址必须为512的倍数。
系统复位后该寄存器可以根据一些硬件管脚的配置输入信号初始化成不同的值。比如STM32一般都是初始化成0x08000000。
SP(Stack Pointer)寄存器
保存栈顶地址。
PC(Program Counter)寄存器
保存下一条要执行的指令地址。
bootloader的启动
1、处理器上电或者复位后,VTOR被初始化成一个固定的值,硬件电路自动将VTOR所指向的中断向量表的的第1个WORD(4字节)值装载到SP中,
将第2个WORD值装载到PC中,然后执行第一条指令,即VTOR所指向的中断向量表的第2个WORD值指向的指令。
该指令所在的函数一般叫做Reset_Handler,该函数一般先调用SystemInit,然后调用__main函数,__main函数中调用我们熟知的程序入口函数:main。
一般在SystemInit中会修改VTOR寄存器的值为bootloader的中断向量表首地址。
2、判断是否需要跳转到app,如果需要并且app是有效的,将app的中断向量表的第1个WORD装载到SP中(MDK-ARM toolchain对应的示例代码:__set_MSP(*(__IO uint32_t *)APP_START_ADDRESS);),
然后将app的中断向量表的第2个WORD的值作为函数指针进行调用。
app的启动
app自己的Reset_Handler被调用,该函数也是先调用SystemInit,然后调用__main函数。
SystemInit中会修改VTOR寄存器的值为app的中断向量表首地址,这样app中的中断就都由app的中断向量表指向的中断处理函数来处理了。
中断向量表
中断向量表的格式以及和中断号的对应关系如下图:
中断向量表在代码中如何构造出来
一般通过汇编语言编写:
; MDK-ARM toolchain的汇编代码
Stack_Size EQU 0x1000
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size ;告诉编译器开辟一段空间,用作栈内存
__initial_sp
Heap_Size EQU 0x2000
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size ;告诉编译器开辟一段空间,用作堆内存
__heap_limit
PRESERVE8
THUMB
; 下面是构造中断向量表的汇编语句
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack, flash上分配4字节内存,并初始化为栈顶的地址
DCD Reset_Handler ; Reset Handler, flash上分配4字节内存,并初始化为Reset_Handler函数的地址
DCD NMI_Handler ; NMI Ha