【STM32】IAP下载程序分析
迪丽瓦拉
2025-06-01 01:10:49
0

IAP下载程序分析

  • IAP基本原理
  • STM32启动流程
  • 程序跳转代码实现
  • 总结

IAP基本原理

要实现STM32的IAP(在应用编程),需要分别建立bootloaderapp工程。这里的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 StackDCD     Reset_Handler              ; Reset HandlerDCD     NMI_Handler                ; NMI HandlerDCD     HardFault_Handler          ; Hard Fault HandlerDCD     MemManage_Handler          ; MPU Fault HandlerDCD     BusFault_Handler           ; Bus Fault HandlerDCD     UsageFault_Handler         ; Usage Fault HandlerDCD     0                          ; ReservedDCD     0                          ; ReservedDCD     0                          ; ReservedDCD     0                          ; ReservedDCD     SVC_Handler                ; SVCall HandlerDCD     DebugMon_Handler           ; Debug Monitor HandlerDCD     0                          ; ReservedDCD     PendSV_Handler             ; PendSV HandlerDCD     SysTick_Handler            ; SysTick Handler

在栈顶指针地址后面紧接着是以Reset_Handler开始的中断向量表,该表一一指向了对应的中断函数地址。
上电或复位后,STM32的PC被赋予0x8000000+4的值,也就是跳转到中断向量表中Reset_Handler向量指向的中断程序
Reset_Handler所指向的程序如下,可以看出此处执行了SystemInitmain两个函数,也就是说通过复位中断后程序最终流向了main函数的while(1)死循环,从而执行用户代码。

Reset_Handler    PROCEXPORT  Reset_Handler             [WEAK]IMPORT  SystemInitIMPORT  __mainLDR     R0, =SystemInitBLX     R0LDR     R0, =__mainBX      R0ENDP

在执行main函数的过程中,每当有中断发生时,程序就会跳转到中断向量表中搜索对应的中断程序,然后跳转至中断函数处执行,最后返回main函数继续执行。

程序跳转代码实现

通过上面的分析可知,STM32在上电或复位后把0x8000000处的值赋给了MSP寄存器来初始化主堆栈指针地址,把0x8000000+4处的值赋给了PC寄存器使程序进入复位中断从而顺利执行。
所以,要实现bootloader到app的跳转,需要我们需要改变MSP和PC这两个寄存器。bootloader中跳转代码的实现如下:

#define     __IO    volatile                  /*!< defines 'read / write' permissions   */
#define ApplicationAddress    0x8003000
pFunction Jump_To_Application;
uint32_t JumpAddress;
typedef  void (*pFunction)(void);/*** @brief  Set the Main Stack Pointer** @param  topOfMainStack  Main Stack Pointer** Assign the value mainStackPointer to the MSP * (main stack pointer) Cortex processor register*/
__ASM void __set_MSP(uint32_t mainStackPointer)
{msr msp, r0bx lr
}
void Jump2App(void)
{/* Test if user code is programmed starting from address "ApplicationAddress" */if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000){ /* Jump to user application */JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);Jump_To_Application = (pFunction) JumpAddress;/* Initialize user application's Stack Pointer */__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空间的中断函数。

相关内容