1、IAP跳转实现
其实很多时候IAP是跳转到APP成功了,但是APP里面的模块已经被IAP使用过了,再次使用值就非复位初始化一样,需要重新复位这些使用到的模块
其中包括串口,systick,RCC时钟模块,其他如果使用到了也需要复位
1.1、IAP中跳转,复位USART,Systick 滴答时钟,RCC时钟
#define IAP_FLASH_SIZE 0x3000 //预留12k
#define APP_ADDRESS (FLASH_BASE+IAP_FLASH_SIZE)
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset)
{
/* Check the parameters */
assert_param(IS_NVIC_VECTTAB(NVIC_VectTab));
assert_param(IS_NVIC_OFFSET(Offset));
SCB->VTOR = NVIC_VectTab | (Offset & (uint32_t)0x1FFFFF80);
}
void JumpToApp(void)
{
__disable_irq();//关闭中断
SysTick->CTRL =0; //定时器复位关闭
HAL_RCC_DeInit();//时钟复位
HAL_UART_DeInit(&huart1);;//使用到的串口复位
NVIC_SetVectorTable(FLASH_BASE,0x3000);//这句话可以加在IAP APP就不用再单独添加
JumpAddress = *(uint32_t*) (APP_ADDRESS + 4);
Jump_To_Application = (pFunction) JumpAddress;//Jump to user application
__set_MSP(*(uint32_t*) APP_ADDRESS);//Initialize user application's Stack Pointer
Jump_To_Application();
}
1.2、 APP初始化使能中断
__enable_irq();
2、STM32启动过程
2.1、栈顶指针
栈空间在启动文件就已经分配好了。
在MAP文件中可查看。
FLASH空间内容
结论:
上图是APP中调试窗体查看的,APP中断表偏移为0x3000,所以APP代码从0x08003000K开始。
第一个整字就是栈顶地址 0x20001D78
在MAP文件的地址 0x20001978+0x400 = 0x20001D78
所以程序开始运行时的栈顶指针就是指向栈分配空间的末尾地址。
2.2、栈分配方向
在栈变量(局部变量)分配时是采用返向分配的原则。
变量空间的分配从栈顶开始往下递减。
但是数据存储顺序就是正常理解的小段模式存放。和分配方向不矛盾。
2.3、局部变量空间分配问题:栈还是通用寄存器??
经过测试,局部变量基本类型int char 非数组变量可能分配到栈里面,也可能实在R0-R11通用寄存器中,如果变量过多就会放在栈空间中,少量在通用寄存器中就可以。但是不固定。数组一定是分配在栈空间中的。
如下图,分配到变量i是,通用寄存器R11用完了,只能把变量定义到栈中。栈对应内存地址,可以取地址,通用寄存器不能直接取地址。
如下变量a地址被用到了,编译器自动会把a放在栈中。所以啊,全看编译器自己的心情。
总结:
局部变量数组类型以及结构体等会分配到栈空间中,一般int,char变量不固定位置,看变量的使用方式和变量占用情况而定。