STM32中断向量表位置有两种类型,第一种是基地址为0x08000000的Flash中断向量表,第二种是在系统内部的SRAM中断向量表。
对于基地址为0x08000000的Flash中断向量表,由于存储在Flash中,所以当中断产生时,CPU需要在Flash中读取对应的中断处理程序。由于Flash中的数据不可更改,当需要更新中断向量表时,需要写入Flash。这一过程是比较麻烦的。而对于在系统内部的SRAM中断向量表,由于存储在SRAM中,所以读写速度更快,而且可以直接在SRAM中更新中断向量表,不需要再次写入Flash。
在ARM Cortex-M3处理器的内核接受一个中断时,它会将当前的处理器状态放到堆栈中,并保存一些关键寄存器的值(例如R0、R1等),然后会在中断向量表中找到对应的中断处理程序,并跳转到该程序的起始地址去执行。在中断处理程序中,执行完毕后会从堆栈中还原处理器状态,然后返回到中断发生位置继续执行。
但如果中断处理程序的入口地址不正确,处理器状态就会被破坏,而且很难恢复,这样会导致系统崩溃。因此,在编写中断处理程序时,需要保证中断处理程序的入口地址正确。
在ARM Cortex-M3处理器中,中断向量表中的地址必须是4的倍数,因为从这个地址开始的指令都是4字节长的。而中断跳转指令(BX)是2字节长的,因此在跳转到中断处理程序时,需要加上一个偏移量来保证跳转到的地址是4的倍数。
例如,如果中断处理程序的地址为0x08000100,那么在向量表中其实需要写入的地址是0x08000101,跳转指令中的偏移量为1。如果中断处理程序的地址为0x08000101,那么向量表中地址为0x08000104,跳转指令中的偏移量为3。
在STM32中,有些中断处理程序会直接调用C语言函数,例如使用HAL库中的函数来处理中断。而C语言中的函数一般都有一个前置的函数头,包括函数名和一些参数的定义。如果直接跳转到这个函数头,会导致栈指针错误,从而导致无法正确执行中断处理程序。
为了解决这个问题,在跳转到中断处理程序的时候,需要跳转到函数的起始地址,而不是函数的头地址。这样才能保证栈指针的正确性。