bootloader是什么

  • bootloader就是单片机启动时候运行的一段小程序,这段程序负责单片机固件的更新,也就是单片机选择性的自己给自己下载程序。可以更新,可以不更新,更新的话,boot loader更新完程序后,跳转到新程序运行;不更新的话,boot loader直接跳转到原来的程序去运行。
  • boot loader更新完程序后并不擦除自己,下次启动后依然先运行boot loader程序,又可以选择性的更新或者不更新程序,所以boot loader就是用来管理单片机程序的更新。
  • 在实际的单片机工程项目中,如果加入了boot loader功能,就可以给单片机日后升级程序留出一个接口,方便日后单片机程序更新。当然,这就需要创建亮哥工程项目,一个位boot loader工程,一个为app工程。
  • bootloader工程生成的文件通常下载到ROM或者Flash中的首地址,这样可以保证上电后先运行boot loader程序。而app工程生成的文件则下载到ROM或者Flash中boot loader后面的地址中。也就是说,存在ROM或者Flash中的内容是分为两部分的。
  • 要实现同一个ROM或者Flash中保存两段程序,并且保证不能相互覆盖,则需要在下载程序时指定地址。如在keil中,可以进行如下调整(需要知道Flash的扇区地址)。

在这里插入图片描述

升级流程

在介绍升级流程之前。我们必须先搞清楚MCU型号对应的Flash分区情况,可以直接查看手册(当然,其实我们也可以在hal库代码中找到相关信息),如下图:

在这里插入图片描述

因为上文说到,我们有两个程序需要下载到Flash,bootloader文件一般下载在最开始的地址,application一般在后面的地址。

上图即为我们预定义的flash分配情况。我们一般是按照整个扇区进行利用的,这样便于擦除和写入。

  • bootloader从起始地址开始,这个没有疑问。我分配了扇区0给它(这个大小是具体情况而定)。
  • application占用扇区1。
  • ota_flag这个是用于存放是否升级的标志位。存放在扇区2,ota_flag只占用4字节,当写入0x87654321的时候,表示需要升级,否则,无需升级。
  • ota_data占用扇区3。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oH0MLjqQ-1686299396663)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20230609161215006.png)]

代码示例

#ifndef __BSP_BOOTLOADER_H
#define __BSP_BOOTLOADER_H

#ifdef __cplusplus
extern "C"{

#endif

#include "stm32f4xx.h"
#include "stdbool.h"

#define BOOTLOADER_BASE_ADDRESS    (0x08000000)
#define BOOTLOADER_SECTION         FLASH_Sector_0
#define BOOTLOADER_SECTION_SIZE    16*1024

#define APPLICATION_BASE_ADDRESS   (0x08004000)
#define APPLICATION_SECTION        FLASH_Sector_1
#define APPLICATION_SECTION_SIZE   16*1024

#define UPDATE_FLAG_ADDRESS        (0x08008000)
#define UPDETA_FLAG_SECTION        FLASH_Sector_2
#define UPDETA_FLAG_SECTION_SIZE   16*1024
#define UPDATE_FLAG                (0x87654321)

#define DOWNLOAD_BASE_ADDRESS      (0x0800C000)
#define DOWNLOAD_SECTION           FLASH_Sector_3
#define DOWNLOAD_SECTION_SIZE      16*1024

bool UPDATE_CHECK(void);
void UPDATE_APPLICATION(void);
void JUMP2APPLICATION(void);
void MCU_RESET(void);
#ifdef __cplusplus
}
#endif

#endif


#include "bsp_bootloader.h"
#include "stdio.h"


typedef void (*pFunction)();
pFunction Jump_To_Application;

void UPDATE_APPLICATION()
{
	FLASH_Status status = FLASH_COMPLETE;
	
	FLASH_Unlock();

	status=FLASH_EraseSector(APPLICATION_SECTION,VoltageRange_3);
	if(FLASH_COMPLETE==status)
	{
		printf("APPLICATION_SECTION Erase OK\r\n");
	}
	
	for(int i=0;i<APPLICATION_SECTION_SIZE;i++)
	{
		__IO uint8_t* download_addr=(__IO uint8_t*)DOWNLOAD_BASE_ADDRESS;//read download data
		
		status=FLASH_ProgramByte(APPLICATION_BASE_ADDRESS+i,*(download_addr+i));
		if(FLASH_COMPLETE==status)
	    {
		     printf("APPLICATION_SECTION FLASH_ProgramByte %.2f%%\r\n",(i+1)*1.0/APPLICATION_SECTION_SIZE);
	    }
	}
	printf("APPLICATION_SECTION FLASH_ProgramByte OK\r\n");
	
	status=FLASH_EraseSector(UPDATE_FLAG_ADDRESS,VoltageRange_3);
	if(FLASH_COMPLETE==status)
	{
		printf("UPDETA_FLAG_SECTION Erase OK\r\n");
	}
	
	FLASH_Lock();
}

bool UPDATE_CHECK()
{
	return	*(__IO uint32_t*)UPDATE_FLAG_ADDRESS==UPDATE_FLAG;
}

void MCU_RESET()
{
   NVIC_SystemReset();
}

void JUMP2APPLICATION()
{
	printf("JUMP2APPLICATION OK\r\n");
	
	 __set_MSP(*(__IO uint32_t*)APPLICATION_BASE_ADDRESS);
	
	Jump_To_Application = (pFunction)(*(__IO uint32_t*)(APPLICATION_BASE_ADDRESS+4));
	
	Jump_To_Application();
}


int main(void)
{
#ifdef BOOTLOADER
	Init_USART();
	Init_LED();
	printf("hello,this is bootloader\r\n");
	
	if(UPDATE_CHECK())
	{
		UPDATE_APPLICATION();
		
		MCU_RESET();
	}
	else
	{
		JUMP2APPLICATION();
	}
	
#else
    NVIC_SetVectorTable(NVIC_VectTab_FLASH, APPLICATION_BASE_ADDRESS);
	
	//设置中断分组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	
	Init_USART();
	Init_LED();
	
	printf("hello,this is application\r\n");
	
	Init_INT_TIMER();
#endif	
	
  /* Infinite loop */
  while (1)
  {
//	USART_DMA_SEND(data,5);
//	delay(0xfffffff);
  }
}

总结

1、关于地址跳转部分,可以参考STM32 Bootloader程序中Jump2App函数分析
2、注意中断向量表偏移设置。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐