一.关于跳转部分的代码的理解(转)
这里重点说一下几句经典且非常重要的代码:
第一句: if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000) //判断栈定地址值是否在0x2000 0000 - 0x 2000 2000之间
怎么理解呢? (1),在程序里#define ApplicationAddress 0x8003000 ,*(__IO uint32_t*)ApplicationAddress) 即取0x8003000开始到0x8003003 的4个字节的值, 因为我们的应用程序APP中设置把 中断向量表 放置在0x08003000 开始的位置;而中断向量表里第一个放的就是栈顶地址的值
也就是说,这句话即通过判断栈顶地址值是否正确(是否在0x2000 0000 - 0x 2000 2000之间) 来判断是否应用程序已经下载了,因为应用程序的启动文件刚开始就去初始化化栈空间,如果栈顶值对了,说应用程已经下载了启动文件的初始化也执行了;
第二句: JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); [ common.c文件第18行定义了: pFunction Jump_To_Application;]
ApplicationAddress + 4 即为0x0800 3004 ,里面放的是中断向量表的第二项“复位地址” JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); 之后此时JumpAddress
第三句: Jump_To_Application = (pFunction) JumpAddress;
startup_stm32f10x_md_lv. 文件中别名 typedef void (*pFunction)(void); 这个看上去有点奇怪;正常第一个整型变量 typedef int a; 就是给整型定义一个别名 avoid (*pFunction)(void); 是声明一个函数指针,加上一个typedef 之后 pFunction只不过是类型 void (*)(void) 的一个别名;例如:
[cpp]
- pFunction a1,a2,a3;
- void fun(void)
- {
- ......
- }
- a1 = fun;
所以,Jump_To_Application = (pFunction) JumpAddress; 此时Jump_To_Application指向了复位函数所在的地址;
第四 、五句: __set_MSP(*(__IO uint32_t*) ApplicationAddress); \\设置主函数栈指针 Jump_To_Application(); \\执行复位函数
Jump_To_Application()是把用户代码的复位地址付给PC指针,我看到Jump_To_Application()这句代码debug的时候对应的汇编代码是
LDR r0,[pc,#12] ;相对PC的数据加载,去函数指针的地址
LDR r0,[r0,#00] ;R0做索引,无偏移,数据装载到R0,这个内容就是函数指针指向的内容,也就是函数的地址了,用户程序的起始地址; BLX r0 ;这个不解释,说了是跳转正点原子代码里是这么实现的:
//appxaddr:用户代码起始地址.void iap_load_app(u32 appxaddr){ if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)//检查栈顶地址是否合法. { jump2app=(iapfun)*(vu32*)(appxaddr+4);//用户代码区第二个字为程序开始地址(复位地址) MSR_MSP(*(vu32*)appxaddr);//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址) jump2app(); //跳转到APP. }}