STM32具备升级功能的bootloader及APP/IAP的实现

本文介绍如何在STM32上实现升级功能,程序包括:bootloader和APP(也叫IAP, In Application Programming),基于STM32F103RCT6型号的MCU作为实验平台,以STM32CubeMX工具进行工程的建立及底层配置等工程。

 

一、整体框架

整体上,在flash上烧写2个程序,bootloader和APP。

bootloader程序位于0x80000000处,即默认的程序启动地址;

APP程序则位于bootloader程序的往后某地址,空间大小需自行定义。

STM32F103RCT6的flash大小为256K。

 

1、flash分区概述

如我flash空间分配如下:

STM32具备升级功能的bootloader及APP/IAP的实现_第1张图片

 

2、各分区说明

分区说明
分区  地址  大小  作用
bootloader 0x8000 0000 32K  校验、引导APP、升级
param 0x8000 8000 16K  参数区,保存一些断电不丢失参数
APP 0x8000 C000 192K  主应用程序
reserve 0x8003 0000 16K  预留区(可用作参数的备份,或其他)

 

二、bootloader

bootloader的主要功能:校验数据、启动APP、升级APP。

bootloader的工作流程如下:

 

1、基础功能初始化(时钟、外设等);

主要进行一些BSP板级初始化:(仅供参考,因工程而异)

/******************************************************************/
/**
 * BSP初始化函数\n
 *
 */
/******************************************************************/
void BSP_Init(void)
{
	
	/* MCU Configuration--------------------------------------------------------*/
	
	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	HAL_Init();
	
	/* Configure the system clock */
	SystemClock_Config();
	
	/* Initialize all configured peripherals */
	
	/* Initialize GPIO */
	MX_GPIO_Init();
	
	/* Initialize usart */
	MX_UART_Init();

	/* Initialize timer */
	Timer_ParamInit();
	MX_TIM3_Init();
	MX_TIM4_Init();

}

 

2、数据校验(参数区信息、APP程序的检验)

此步骤为后续启动过程读取一些基础参数,以及校验数据的准确性等。

读取参数区的参数:如我将升级相关的参数写在此分区(目前仅是启动标志,具体可自行定义),根据此标志来判断下一步该如何走。

/* flash参数区信息结构 */
struct param_info
{
	UINT16		usStartFlag;	// 启动标志 0x0A-跳至APP 0x0B-等待升级 0x0F-已强制启动过
};

校验数据:如我将校验APP程序区的数据是否正常,采用CRC校验。

/******************************************************************/
/**
 * 检验flash参数区函数\n
 *
 */
/******************************************************************/
int check_paramInfo(UINT32 unParamAddr, UINT32 unAppAddr, UINT32 unAppRunOffset)
{
	struct param_info		stParams = {0};
	INT32		nRetAppHead = 0;

	/* 检查参数区-判断启动APP/升级? */
	memset(&stParams, 0, sizeof(struct param_info));
	cpuflash_read(unParamAddr, (UINT8 *)&stParams, sizeof(struct param_info));
	if(stParams.usStartFlag == BOOT_FALG_NORMAL_RUNAPP)		// 直接跳转APP
	{
		/* APP校验 */
		nRetAppHead = check_AppInfo(unAppAddr, unAppRunOffset);
		if(nRetAppHead == 0)
		{
			HAL_TIM_Base_Stop_IT(&htim3);	// ??? 不关中断跳转不了-原因未明
			loadAPP(unAppAddr +unAppRunOffset);
		}
		else
		{
			printf("%s: check_AppInfo failed, [may be crc error] !\n", __FUNCTION__);
		}
	}

	/* 若参数/APP头信息错误-尝试强制启动 */
	if((stParams.usStartFlag!=BOOT_FALG_WAIT_UPGRADE && stParams.usStartFlag!=BOOT_FALG_FORCE_RUNAPP) || nRetAppHead!=0)
	{
		force_loadAPP(unParamAddr, unAppAddr, unAppRunOffset);
	}
	else
		printf("%s: ------------ wait to upgrade ------------\n", __FUNCTION__);

	return 0;
}

流程:先读取参数,判断下一步是直接启动APP还是留在bootloader等待升级。若是启动APP则校验APP程序数据是否正常,若校验失败则可尝试强制启动一次(启动失败也没关系,看门狗会自动复位)。

 

3、跳转APP或升级APP。

如何跳转至APP呢?跳转函数:

/*****************************************************************/
/**
 * 加载APP \n
 * 
 */
/******************************************************************/
void loadAPP(INT32U unLoadAddr)
{
	void (*fnJump2APP)(void);
	INT32U	unJumpAddr;
	
	if(((*(__IO INT32U *)unLoadAddr) & 0x2FFE0000) == 0x20000000)	/* 检查栈顶地址是否合法 */
	{
		printf("%s: ----------------------> run APP addr: 0x%x\r\n", __FUNCTION__, unLoadAddr);

		/* 用户代码区第5~8字节为程序开始地址(复位地址) */
		unJumpAddr = *(__IO INT32U *)(unLoadAddr + 4);
		fnJump2APP = (void (*)(void))unJumpAddr;
		/* 初始化APP堆栈指针(用户代码区的前4个字节用于存放栈顶地址) */
		__set_MSP(*(__IO INT32U *)unLoadAddr);
		fnJump2APP();
	}
	else
	{
		printf("ERROR: %s: Stack top address is not valid! Can not run func!\r\n", __FUNCTION__);
		while(1);
	}
}

 

升级,即读取到的参数标志为升级状态,则留在bootloader等等接收升级包数据(APP程序数据),并将其写入flash的APP分区。(具体见程序)

 

三、APP

APP的主要功能:除升级功能外的所有应用功能,及跳转至bootloader准备升级。

中断向量表重映射:由于APP程序的起始地址的变化,因此需要重映射,否则程序异常。

 

 

跳转功能可用bootloader的跳转函数,也可直接重启reboot,两种方式都可达到目的---进入bootloader运行。


 

四、升级功能

 

 

附件:完整工程链接

 

未完待续。。。

你可能感兴趣的:(stm32)