IAP下载程序分析
- IAP基本原理
- STM32启动流程
- 程序跳转代码实现
- 总结
IAP基本原理
要实现STM32的IAP(在应用编程),需要分别建立bootloader和app工程。这里的bootloader程序是用户自己实现的,与STM32内置的bootloader无关。例如,我们可以把bootloader程序放在0x8000000处,把app程序放在0x80001000处,上电时首先进入bootloader程序执行,检查是否需要更新app,执行完毕后再跳转到app程序处执行。
STM32启动流程
为了实现bootLoader到app的跳转,首先需要弄清楚STM32程序执行的流程。
STM32 flash程序执行通常由地址0x8000000开始。首4个字节存放主栈顶指针MSP地址,其值是由编译器编译后决定的。比如用户用到了多少全局变量以及静态变量,在RAM中就需要预留出相应的空间,从而影响栈顶指针的位置,而局部变量在RAM中的存取就需要栈顶指针和栈大小来约束。上电时STM32的MSP寄存器即被初始化。
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
在栈顶指针地址后面紧接着是以Reset_Handler
开始的中断向量表,该表一一指向了对应的中断函数地址。
上电或复位后,STM32的PC被赋予0x8000000+4的值,也就是跳转到中断向量表中Reset_Handler
向量指向的中断程序
Reset_Handler
所指向的程序如下,可以看出此处执行了SystemInit
和main
两个函数,也就是说通过复位中断后程序最终流向了main
函数的while(1)
死循环,从而执行用户代码。
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
在执行main函数的过程中,每当有中断发生时,程序就会跳转到中断向量表中搜索对应的中断程序,然后跳转至中断函数处执行,最后返回main函数继续执行。
程序跳转代码实现
通过上面的分析可知,STM32在上电或复位后把0x8000000
处的值赋给了MSP寄存器来初始化主堆栈指针地址,把0x8000000+4
处的值赋给了PC寄存器使程序进入复位中断从而顺利执行。
所以,要实现bootloader到app的跳转,需要我们需要改变MSP和PC这两个寄存器。bootloader中跳转代码的实现如下:
#define __IO volatile
#define ApplicationAddress 0x8003000
pFunction Jump_To_Application;
uint32_t JumpAddress;
typedef void (*pFunction)(void);
__ASM void __set_MSP(uint32_t mainStackPointer)
{
msr msp, r0
bx lr
}
void Jump2App(void)
{
if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
{
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
}
}
ApplicationAddress
是用户定义的app程序首地址,如0x8000000+0x1000。通过if条件来判断该地址中的值是否在指定的RAM空间范围内,如果是则从0x8000000+0x1000+4地址(即app程序的Reset_Handler
向量)中取出要跳转的地址JumpAddress
,并通过空函数指针Jump_To_Application
指向该地址。
完成好准备工作后,接下来就是最重要的一步。通过__set_MSP()
函数设置MSP寄存器,通过调用空函数指针Jump_To_Application
使得PC跳转至地址JumpAddress
。如此一来,MSP和PC的值由bootloader空间更新为app空间,转而运行app部分的代码。
但是,配置工作还没有结束。上面提到了当执行main函数发生中断时,会跳转至中断向量表,由于我们没有修改中断向量表,中断向量表指向的仍是bootloader空间的中断函数,所以最后中断返回bootloader的main函数执行。而我们希望映射的中断向量表是app空间的中断向量表,因此,需要在app的main函数开头添加重映射语句:
SCB->VTOR = ApplicationAddress;
总结
1.要实现IAP功能,需要建立bootloader和app两个工程,bootloader地址从0x8000000开始,而app地址由用户指定(不能与bootloader冲突),编译好工程后分别下载到STM32;
2.在bootloader中设置MSP和PC以跳转至app执行,进入app后首先要重映射中断向量表,使得中断执行app空间的中断函数。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)