STM32F030跳转函数BootLoader和APP的主要部分

本文详细介绍了在STM32上使用C语言和汇编语言实现用户系统的加载和运行过程。通过定义宏和类型,实现了中断向量表的复制、栈顶地址设置及程序跳转。在MDK、IAR和STM32CubeIDE中分别展示了如何用汇编语言编写跳转函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


使用C语言

#define 	RAM_START_ADDR		(0x20000000)
#define		VECTOR_SIZE		(0xb0)//中断向量表的大小
typedef 	void (*pFunction)(void);

/**
  * @brief  Load and run user system
  * @note   
  * @rmtoll 
  * @param  None
  * @retval None
  */
void LoadUserSystem(u32 address)
{
	pFunction LoadAddress;
	u32 JumpAddress;
	
	if (((*(__IO uint32_t*)address) & 0x2FFE0000 ) == 0x20000000)
	{
		//关总中断
		__disable_irq();
		//复位地址
		JumpAddress = *(volatile u32*)(address + 4);
		LoadAddress = (pFunction)JumpAddress;
		memcpy((void *)RAM_START_ADDR, (void *)address, VECTOR_SIZE);
		LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_SYSCFG);
		LL_SYSCFG_SetRemapMemory(LL_SYSCFG_REMAP_SRAM);
        
		//将把用户代码的栈顶地址设为栈顶指针
		__set_MSP(*(__IO uint32_t*)address);
		//程序跳转
		LoadAddress();
	}
}

使用汇编:

可以将C与汇编结合使用,将跳转函数转为汇编,其中C的代码部分


/**
  * @brief  Jump to user program
  * @note
  * @rmtoll
  * @param  None
  * @retval None
  */
int SystemJump2Where(uint32_t address)
{
	/* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
	if (((*(__IO uint32_t*)address) & 0x2FFE0000 ) == 0x20000000)
	{
		extern void vJumpToWhere(int);
		vJumpToWhere(address);
	}

	/*跳转失败,返回-1*/
	return -1;
}

1.在MDK中,汇编

		
        THUMB
        REQUIRE8
        PRESERVE8

        AREA ||i.vJumpToWhere||, CODE, READONLY, ALIGN=4

vJumpToWhere PROC
	cpsid           i 				;Disable interrupt
	ldr	    	r1, [r0]		;Get MSP location
	ldr	    	r2, [r0, #4]	;Get resethanler address
	movs    	r0, #0
	msr     	CONTROL, r0		;Use MSP
	msr     	MSP, r1
	bx    		r2 				;Jump
     
    ENDP
		
		
	EXPORT vJumpToWhere [CODE]
	END

 

2.在IAR中,汇编


    RSEG	CODE:CODE(2)
    thumb

	PUBLIC	vJumpToWhere

/*-----------------------------------------------------------*/
/**
  * @brief Jump to program start address and excute
  * @param Program start address
  * @retval None
  */
vJumpToWhere
	cpsid   i				//Disable interrupt
	ldr     r1, [r0]		//Get MSP location
	ldr     r2, [r0, #4]	        //Get resethanler address
	movs    r0, #0
	msr 	CONTROL, r0		//Use MSP
	msr 	MSP, r1
	bx	r2                      //Jump
     
    END

 

3.在STM32CubeIDE中(escplise),这部分代码还待优化


.global  vJumpToWhere	// 把vJumpToWhere链接属性改为外部,这样其他文件就可以看见了

	.thumb
	.section  .text.vJumpToWhere	//相关属性
	.type  vJumpToWhere, %function
	.size  vJumpToWhere, .-vJumpToWhere
	.align 4

/*-----------------------------------------------------------*/
/**
  * @brief Jump to program start address and excute
  * @param Program start address
  * @retval None
  */
vJumpToWhere:
    cpsid 	i				//Disable interrupt
	ldr     r1, [r0]		//Get MSP location
	ldr     r2, [r0, #4]	//Get resethanler address
	movs    r0, #0
	msr 	CONTROL, r0		//Use MSP
	msr 	MSP, r1
	bx		r2              //Jump
     

 

### STM32F407应用程序跳转Bootloader的方法 对于STM32F407微控制器而言,要让应用程序能够跳转Bootloader段执行,主要依赖于调整向量表偏移寄存器(VTOR),并确保PC指针指向Bootloader起始位置。具体来说,在单片机启动时会优先加载位于地址`0x8000000`处的指令[^1]。 为了实现这一过程,下面提供了一种方法来完成从应用代码到Bootloader的切换: #### 修改向量中断表基地址 由于Bootloader通常放置在Flash存储区的最前端,即从地址`0x8000000`开始,因此可以通过改变NVIC中的向量表偏移寄存器(VTOR),使得系统响应异常或中断请求时能正确找到新的处理函数入口。 ```c // 设置向量表偏移到Bootloader区域 SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; ``` 这里假设`VECT_TAB_OFFSET`定义为零,表示使用默认的向量表位置;而`FLASH_BASE`则代表内部Flash内存的基础地址(`0x8000000`)。 #### 更新堆栈指针与程序计数器 紧接着需要做的是获取Bootloader段的第一个有效指令的位置以及对应的初始堆栈指针值。这些信息一般保存在其前两个双字单元内——第一个四字节存放着复位后的SP初值,紧随其后的四个字节则是Reset_Handler的地址。 ```c void (*jump_to_boot)(void); uint32_t *src = (uint32_t *)BOOTLOADER_START_ADDR; // Bootloader起始地址, e.g., 0x8000000 __set_MSP(*src++); // 加载MSP jump_to_boot = (void (*)(void))(*src); // 获取重置处理器后应执行的第一条指令地址 jump_to_boot(); // 执行跳转动作 ``` 上述C语言片段展示了如何动态地读取指定地址范围内的数据,并据此设置CPU的工作状态以便顺利转移到Bootloader环境当中去。 #### 注意事项 - 确认Bootloader已经存在于预期的Flash区域内。 - 如果存在多个可能的目标分区,则需额外考虑选择合适的分支逻辑。 - 对于某些特殊情况下,比如调试期间,建议保留返回路径以方便后续开发工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值