ARM单片机工程之间的切换
??在做ARM单片机开发的时候,有时候会在一个MCU内部存放几个工程,工程之间可以是独立的,也可以是有联系的。有联系体现在2个以上的工程公用RAM和flash资源,实现工程之间的同步,如果单片机内部存在BRAM(BACKUP RAM),那么可以选择使用BRAM存放工程之间的共享数据;如果没有,还可以使用读写Flash实现数据的共享。本章主要介绍ARM单片机中工程之间的跳转。
1.首先了解下中断向量表
??上图摘自STM32L4芯片手册,首先这个中断向量表上可以直观的看到地址0x0000存放的是SP的初始值,地址0x0004存放的是Reset。可以在IAR或者KEIL调试程序的时候看到,Reset其实就是一个跳转的地址,具体的说是,中断向量表上每个单位存放的是4个字节组成的地址,当有中断异常等发生时,就会认准里面存的地址然后直接跳过去运行。(目前接触到的M3,M4,M7内核的中断向量表都长这啥样)
2.主堆栈MSP
??MSP:缺省的堆栈指针,它由OS内核、异常服务例程以及所有需要特权访问的应用程序代码使用。在程序启动的时候,会将上面中断向量表的SP Value写到MSP。
3.程序计数器PC
??PC,字面意思就是记录程序的执行位置,在程序一启动的时候,默认是将Reset的地址赋值给PC,然后运行代码。因为Arm内核使用了指令流水线,所以在读PC时返回的值是当前指令地址+4。
4.系统的Reset序列
??系统先是进入复位状态,接着在离开复位状态后,内核做的第一件事: (1)从地址0x00000000处读取MSP的初始值。 (2)从地址0x00000004处读取PC的初始值–这个是复位向量,最低位LSB必须为1。程序就是从这PC值真正开始运行的。
5.跳转代码的书写
??下面直接贴出工程跳转函数:
typedef void (*func)();
void Project_Jump(uint32_t addr)
{
func func_ptr;
SysTick->CTRL = 0;
__disable_irq();
for(uint8_t i=0;i<8;i++)
{
NVIC->ICER[i] = 0xFFFFFFFF;
NVIC->ICPR[i] = 0xFFFFFFFF;
}
__DSB();
__ISB();
SCB->VTOR = addr;
__DSB();
__ISB();
__enable_irq();
__set_MSP(*(uint32_t *)addr);
func_ptr = (__IO func)(*(__IO uint32_t*) (addr+4));
func_ptr();
}
??上面的__DSB()和__ISB()最好加上,确保数据和指令都同步。还有就是,如果单片机当前工程有使用到ICache和DCache的话,跳转的时候也需要将它们Disable和Clean掉。
|