欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > STM32在bootloader跳转到application时设置MSP

STM32在bootloader跳转到application时设置MSP

2025/2/23 16:24:35 来源:https://blog.csdn.net/weixin_45444963/article/details/144692268  浏览:    关键词:STM32在bootloader跳转到application时设置MSP

1. 简介

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

1.1 MSP的作用

在STM32微控制器中,MSP(Main Stack Pointer,主堆栈指针)是一个非常重要的寄存器,它用于管理堆栈。堆栈是用于临时存储数据和保持子程序返回地址的区域。MSP在以下几种情况下发挥关键作用:

  1. 启动时初始化:在系统启动时,MSP会被初始化为向量表中的初始值。这个初始值通常在启动文件(如startup_stm32fxx.s)中定义。

  2. 异常和中断处理:当发生异常或中断时,MSP用于保存当前的程序状态,包括寄存器内容。这样,当异常或中断处理完成后,可以恢复原来的程序状态并继续执行。

  3. 操作系统使用:在使用实时操作系统(RTOS)时,MSP通常用于处理系统级的中断和异常,而每个任务可能有自己的堆栈指针(PSP,Process Stack Pointer)。MSP和PSP的切换由操作系统来管理,以实现任务之间的切换。

  4. 函数调用:在函数调用过程中,MSP用于保存局部变量、函数参数和返回地址。当函数调用结束时,MSP会恢复到调用前的状态。

MSP的值可以通过特定的汇编指令(如MRSMSR)来读取和修改。在C语言编程中,通常不需要直接操作MSP,但在底层驱动开发或调试时,了解MSP的作用和如何操作它是很有帮助的。

下面是一个简单的汇编代码示例,展示如何读取和写入MSP:

MRS R0, MSP  ; 读取MSP的值到R0寄存器
MSR MSP, R0  ; 将R0寄存器的值写入MSP

通过这些操作,可以查看和修改MSP的值,以便进行调试或特定的系统级操作。

1.2 MSP的设置

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

  • 系统初始化时,会执行Reset_Handler, 先看下这个函数
Reset_Handler:ldr   r0, =_estackmov   sp, r0          /* set stack pointer *//* Call the clock system initialization function.*/bl  SystemInit/* Copy the data segment initializers from flash to SRAM */ldr r0, =_sdataldr r1, =_edataldr r2, =_sidatamovs r3, #0b LoopCopyDataInit......

从上述代码的可以看出, 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的值

0x20009000                        _estack = (ORIGIN (RAM) + LENGTH (RAM))
0x00000200                        _Min_Heap_Size = 0x200
0x00000400                        _Min_Stack_Size = 0x400

所以上电初始化时, MSP的值应该是 0x20009000.

2. 跳转时是否必须显示的设置MSP的值

2.1 _estack的值存储在哪里

上述1.2节,介绍了_estack的初始化值为0x20009000,但这个值存储在哪个地址?答案是在中断向量表中:

 .section .isr_vector,"a",%progbits.type g_pfnVectors, %objectg_pfnVectors:.word _estack.word Reset_Handler.word NMI_Handler.word HardFault_Handler.word 0.word 0.word 0.word 0.word 0.word 0.word 0.word SVC_Handler.word 0.word 0.word PendSV_Handler.word SysTick_Handler.word WWDG_IRQHandler                   /* Window WatchDog              */.word 0                                /* reserved                     */......

由中断向量表代码段可看出, _estack在向量表的首地址; 查看.map文件:

.isr_vector     0x08000000       0xb80x08000000                        . = ALIGN (0x4)*(.isr_vector).isr_vector    0x08000000       0xb8 ./Core/Startup/startup_stm32g070cbtx.o0x08000000                g_pfnVectors0x080000b8                        . = ALIGN (0x4)

向量表的首地址为isr_vector 0x08000000;所以_estack的值存储在 0x08000000, 值为 0x20009000.
通过JLINK可以读出FLASH里的值
在这里插入图片描述

或者查看hex文件,同样可以找到
在这里插入图片描述

2.2 跳转时设置 MSP

跳转时设置MSP的值:

__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);, 会不会有问题?
先看跳转的代码:

// Start applicationdw_reset = *(uint32_t *)(APPLICATION_START);pf_reset = (t_VOID_FUNC)( dw_reset );pf_reset();

这里APPLICATION_START = 0x0800A204,也就是bootloader 直接跳转到application的 Reset_Handler。至此,又回到了1.2节, 在Reset_Handler里会自动将 _estack的值赋给SP。
所以,如果Reset_Handler里设置了SP的值,则跳转时,不是必须要显式的设置MSP的值。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词