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:- MRS R0, MSP ; 读取MSP的值到R0寄存器
- MSR MSP, R0 ; 将R0寄存器的值写入MSP
复制代码 通过这些利用,可以查察和修改MSP的值,以便举行调试或特定的体系级利用。
1.2 MSP的设置
MSP 通常在特权模式下利用, 由硬件自动管理和切换, 在体系启动时初始化。
- 体系初始化时,会实行Reset_Handler, 先看下这个函数
- Reset_Handler:
- ldr r0, =_estack
- mov sp, r0 /* set stack pointer */
- /* Call the clock system initialization function.*/
- bl SystemInit
- /* Copy the data segment initializers from flash to SRAM */
- ldr r0, =_sdata
- ldr r1, =_edata
- ldr r2, =_sidata
- movs r3, #0
- b 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, %object
- g_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 0xb8
- 0x08000000 . = ALIGN (0x4)
- *(.isr_vector)
- .isr_vector 0x08000000 0xb8 ./Core/Startup/startup_stm32g070cbtx.o
- 0x08000000 g_pfnVectors
- 0x080000b8 . = 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 application
- dw_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的值。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |