STM32在bootloader跳转到application时设置MSP

[复制链接]
发表于 2025-11-18 19:14:49 | 显示全部楼层 |阅读模式
1. 简介

在做bootloader 跳转到application时,常常会看到设置MSP的利用__set_MSP(*(__IO uint32_t*) APPLICATION_ENTRY);

1.1 MSP的作用

在STM32微控制器中,MSP(Main Stack Pointer,主堆栈指针)是一个非常紧张的寄存器,它用于管理堆栈。堆栈是用于临时存储数据和保持子步调返回地点的地域。MSP在以下几种环境下发挥关键作用:

  • 启动时初始化:在体系启动时,MSP会被初始化为向量表中的初始值。这个初始值通常在启动文件(如startup_stm32fxx.s)中界说。
  • 非常和克制处理惩罚:当发生非常或克制时,MSP用于生存当前的步调状态,包罗寄存器内容。如许,当非常或克制处理惩罚完成后,可以规复原来的步调状态并继续实行。
  • 利用体系利用:在利用实时利用体系(RTOS)时,MSP通常用于处理惩罚体系级的克制和非常,而每个任务大概有本身的堆栈指针(PSP,Process Stack Pointer)。MSP和PSP的切换由利用体系来管理,以实现任务之间的切换。
  • 函数调用:在函数调用过程中,MSP用于生存局部变量、函数参数和返回地点。当函数调用竣事时,MSP会规复到调用前的状态。
MSP的值可以通过特定的汇编指令(如MRS和MSR)来读取和修改。在C语言编程中,通常不必要直接利用MSP,但在底层驱动开辟或调试时,相识MSP的作用和怎样利用它是很有资助的。
下面是一个简单的汇编代码示例,展示怎样读取和写入MSP:
  1. MRS R0, MSP  ; 读取MSP的值到R0寄存器
  2. MSR MSP, R0  ; 将R0寄存器的值写入MSP
复制代码
通过这些利用,可以查察和修改MSP的值,以便举行调试或特定的体系级利用。
1.2 MSP的设置

MSP 通常在特权模式下利用, 由硬件自动管理和切换, 在体系启动时初始化。

  • 体系初始化时,会实行Reset_Handler, 先看下这个函数
  1. Reset_Handler:
  2.   ldr   r0, =_estack
  3.   mov   sp, r0          /* set stack pointer */
  4. /* Call the clock system initialization function.*/
  5.   bl  SystemInit
  6. /* Copy the data segment initializers from flash to SRAM */
  7.   ldr r0, =_sdata
  8.   ldr r1, =_edata
  9.   ldr r2, =_sidata
  10.   movs r3, #0
  11.   b LoopCopyDataInit
  12.   ...
  13.   ...
复制代码
从上述代码的可以看出, Reset_Handler把_estack加载到SP(堆栈指针), 而_estack在链接文件中界说
/* Highest address of the user mode stack */ _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
以STM32G070为例, 在.map文件中可以看到_estack的值
  1. 0x20009000                        _estack = (ORIGIN (RAM) + LENGTH (RAM))
  2. 0x00000200                        _Min_Heap_Size = 0x200
  3. 0x00000400                        _Min_Stack_Size = 0x400
复制代码
以是上电初始化时, MSP的值应该是 0x20009000.
2. 跳转时是否必须体现的设置MSP的值

2.1 _estack的值存储在那里

上述1.2节,先容了_estack的初始化值为0x20009000,但这个值存储在哪个地点?答案是在克制向量表中:
  1. .section .isr_vector,"a",%progbits
  2.   .type g_pfnVectors, %object
  3. g_pfnVectors:
  4.   .word _estack
  5.   .word Reset_Handler
  6.   .word NMI_Handler
  7.   .word HardFault_Handler
  8.   .word 0
  9.   .word 0
  10.   .word 0
  11.   .word 0
  12.   .word 0
  13.   .word 0
  14.   .word 0
  15.   .word SVC_Handler
  16.   .word 0
  17.   .word 0
  18.   .word PendSV_Handler
  19.   .word SysTick_Handler
  20.   .word WWDG_IRQHandler                   /* Window WatchDog              */
  21.   .word 0                                /* reserved                     */
  22.   ...
  23.   ...
复制代码
由克制向量表代码段可看出, _estack在向量表的首地点; 查察.map文件:
  1. .isr_vector     0x08000000       0xb8
  2.                 0x08000000                        . = ALIGN (0x4)
  3. *(.isr_vector)
  4. .isr_vector    0x08000000       0xb8 ./Core/Startup/startup_stm32g070cbtx.o
  5.                 0x08000000                g_pfnVectors
  6.                 0x080000b8                        . = ALIGN (0x4)
复制代码
向量表的首地点为isr_vector 0x08000000;以是_estack的值存储在 0x08000000, 值为 0x20009000.
通过JLINK可以读出FLASH里的值

大概查察hex文件,同样可以找到

2.2 跳转时设置 MSP

跳转时设置MSP的值:
  1. __set_MSP(*(__IO uint32_t*) APPLICATION_ENTRY);
复制代码
此中APPLICATION_ENTRY就是application的起始地点, 这里假设APPLICATION_ENTRY = 0x0800a200, 那这个地点理论上存放的也是application的 _estack, 通过JLINK读取这个地点的值验证:

以是,__set_MSP(*(__IO uint32_t*) APPLICATION_ENTRY);
这句话的意思也就是把application的_estack赋值给MSP。
2.3 跳转时不显式的设置MSP

如果跳转时不加__set_MSP(*(__IO uint32_t*) APPLICATION_ENTRY);
, 会不会有标题?
先看跳转的代码:
  1. // Start application
  2.     dw_reset = *(uint32_t *)(APPLICATION_START);
  3.     pf_reset = (t_VOID_FUNC)( dw_reset );
  4.     pf_reset();
复制代码
这里APPLICATION_START = 0x0800A204,也就是bootloader 直接跳转到application的 Reset_Handler。至此,又回到了1.2节, 在Reset_Handler里会自动将 _estack的值赋给SP。
以是,如果Reset_Handler里设置了SP的值,则跳转时,不是必须要显式的设置MSP的值。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表