bootloader编写——MCU固件升级系列2(STM32)

这篇具有很好参考价值的文章主要介绍了bootloader编写——MCU固件升级系列2(STM32)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本系列将从升级流程、boot代码编写、APP代码编写以及固件打包来介绍,硬件选用STM32F407ZGT6(手里只有),来完成这系列教程。

bootloader编写——MCU固件升级系列2(STM32)

前言

开发STM32固件升级并编写Bootloader时,需要注意以下几个关键点:

  1. 熟悉硬件和数据手册:在开发过程中,确保充分理解STM32微控制器的特性和功能。阅读相关数据手册,了解其内存布局、外设接口以及其他重要信息。

  2. 选择合适的通信接口:根据项目需求选择合适的通信接口进行固件升级,如串口、I2C、SPI、USB等。确保所选接口可以与外部设备(如PC)正常通信。(后续会使用CAN UART)

  3. 定义固件升级协议:设计一个简单且可靠的通信协议,用于在Bootloader和外部设备之间传输数据。协议应包括命令、地址、数据长度、数据包校验等信息。

  4. 保留足够的Bootloader空间:为Bootloader预留足够的程序存储空间。Bootloader的大小可能会随着功能的增加而增大,因此预留一定的余量非常重要。

  5. 安全和鲁棒性:确保Bootloader代码具有良好的异常处理和错误检测能力。避免因意外情况导致的设备损坏或不可恢复状态。

  6. 可扩展性:在设计Bootloader时考虑到未来可能的功能扩展。保持代码结构清晰,易于维护和升级。

  7. 测试与验证:在实际硬件上对Bootloader进行充分测试,确保其下载、擦除、写入等操作的正确性和稳定性。

遵循以上关键点,在开发过程中保持耐心和细致,能有效编写出一个可靠、高效的STM32 Bootloader。

编写Bootloader程序

在编写前我需要确定几个地方:

  • bootloader

    • 确定bootloader存放地址 0x08000000
    • 配置bootloader中断向量表
    • 实现串口或USB等通信接口 UART
    • 编写flash擦除、编程函数
    • 确定应用程序存放地址 0x08000000 + Boot_size + PARAM_SIZE
    • 跳转到应用程序入口 跳转指令
  • 注意事项

    • 确认芯片型号和数据手册,了解芯片的Flash大小和布局
    • 确定应用程序和bootloader的存放地址
    • 确定bootloader的触发方式,如按键触发、超时触发等
    • bootloader需要配置中断向量表,以便跳转到应用程序时正确执行
    • bootloader需要实现串口或USB等通信接口,以便与上位机进行通信
    • bootloader需要编写flash擦除、编程函数,以便将应用程序下载到Flash中
    • bootloader需要检查应用程序的合法性,如校验和、签名等
    • bootloader需要跳转到应用程序入口,启动应用程序

在MCU中,bootloader主要作用引导进入APP1程序,检测升级标注位是否需要将备份APP2覆盖到APP1中(升级新程序)或者接收升级包进行升级(可以是CAN、UART通信或者读取SD卡获取升级包)。bootloader程序尽量保持简洁,不需要用到资源统统去掉(很容易出现问题,往往初始化的外设资源,最好都去初始化(保留原来的状态)),保证小巧、稳定和扩展性。
需要实现的功能:flash擦除接口和通信接口,主要这两个,还需要添加状态和标注位。

Flash读写和擦除

Flash 功能接口

u32 STMFLASH_ReadWord(u32 faddr)
{
	return *(vu32*)faddr; 
}  

uint16_t STMFLASH_GetFlashSector(u32 addr)
{
	if(addr<ADDR_FLASH_SECTOR_1)return FLASH_Sector_0;
	else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_Sector_1;
	else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_Sector_2;
	else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_Sector_3;
	else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_Sector_4;
	else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_Sector_5;
	else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_Sector_6;
	else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_Sector_7;
	else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_Sector_8;
	else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_Sector_9;
	else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_Sector_10; 
	return FLASH_Sector_11;	
}

void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)	
{ 
  FLASH_Status status = FLASH_COMPLETE;
	u32 addrx=0;
	u32 endaddr=0;	
  if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;	//非法地址
	FLASH_Unlock();									//解锁 
  FLASH_DataCacheCmd(DISABLE);//FLASH擦除期间,必须禁止数据缓存
 		
	addrx=WriteAddr;				//写入的起始地址
	endaddr=WriteAddr+NumToWrite*4;	//写入的结束地址
	if(status==FLASH_COMPLETE)
	{
		while(WriteAddr<endaddr)//写数据
		{
			if(FLASH_ProgramWord(WriteAddr,*pBuffer)!=FLASH_COMPLETE)//写入数据
			{ 
				break;	//写入异常
			}
			WriteAddr+=4;
			pBuffer++;
		} 
	}
  FLASH_DataCacheCmd(ENABLE);	//FLASH擦除结束,开启数据缓存
	FLASH_Lock();//上锁
} 

void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead)   	
{
	u32 i;
	for(i=0;i<NumToRead;i++)
	{
		pBuffer[i]=STMFLASH_ReadWord(ReadAddr);//读取4个字节.
		ReadAddr+=4;//偏移4个字节.	
	}
}

实现在SD卡寻找APP程序,进行升级。

	FIL fnew;                         /* 文件对象 */
	FRESULT res_sd = FR_OK;                   /* 文件操作结果 */
	UINT fnum;                        /* 文件成功读写数量 */
	BYTE ReadBuffer[512]={0};        /* 读缓冲区 */
	
	u8 checknum = 0;
	int writeSum = 0;
 	while(SD_Init())
	{

	}
 	exfuns_init();									 
  f_mount(fs[0],"0:",1); 					
	Flash_Erase(APP1_ADDRESS);
	while(1)
	{
		t++; 
		res_sd = f_open(&fnew, "0:APP2.bin", FA_OPEN_EXISTING | FA_READ);
		if(res_sd == FR_OK)//有升级文件
		{
			printf("open bootloader\r\n");
			fnum = 1;
			do
			{
				res_sd = f_read(&fnew, ReadBuffer, sizeof(ReadBuffer), &fnum);
				if(res_sd == FR_OK)
				{
						printf("##");
						if(fnum!=0)
						STMFLASH_Write(APP1_ADDRESS+writeSum,(u32*)ReadBuffer,fnum/4);
						writeSum += fnum;
						for(int i = 0 ; i < fnum;i++)
						{
							checknum ^= ReadBuffer[i];
							printf("0x%2x ",ReadBuffer[i]);
						}
						printf("\r\n");
						memset(ReadBuffer,0,sizeof(ReadBuffer));
				}
				else
				{
						
						printf("read file failth(%d)\n", res_sd);
				}
			}while(fnum > 0);
			/* 不再读,关闭文件 */
        f_close(&fnew);
				u8 readBuf[4];
				u8 readCheckCrc = 0;
				for(int i = 0;i < writeSum ; i++)
				{
					STMFLASH_Read(APP1_ADDRESS+i*4,(u32*)readBuf,1);
					for(int j = 0;j<4;j++)
					readCheckCrc ^= readBuf[j];
				}
				printf("boot jump app\r\n");
				if(readCheckCrc == checknum && readCheckCrc!=0)
				{
					printf("check sum success jump APP1\r\n");
					//跳转
					jump_to_app();
				}
				else
				{
					printf("check sum Failth\r\n");
				}
				while(1);
				
		}
		else
		{
			printf("not found bootloader \r\n");
		}
		LED0=!LED0;  //状态灯  bootloader状态
	}

上面还需要进行优化,需要添加一些标志位可以在一个扇区或者在备份寄存器标记,来做升级标记。

跳转指令 重点

#define  APP1_ADDRESS  0x8020000
__asm void start_app(uint32_t r0_msp, uint32_t r1_pc)
{
    MOV SP, R0    //R0的数值   其实就是参数r0_msp
    BX R1             //R1               其实就是r1_pc
}
void jump_to_app(void)
{
	start_app((*(uint32_t *)(APP1_ADDRESS)),(*(uint32_t *)(APP1_ADDRESS + 4)));
}

在实际操作过程中,遇到跳转,没能正常运行APP。
我进行分析,排除问题,把问题范围缩小,可能会出现的问题:1、Flash读写接口有问题 2、FAT32文件系统读取数据有问题。
看前面的代码,我都加了日志信息输出,把文件系统读到的数据输出,和真实的bin文件内容对比,对比问题是正确,说明问题出现在Flash擦除。
看下面的截图,左边是都是FF没做写入前做擦除,右边是擦除后再写,是写入成功的。
写入前要先做擦除处理。
bootloader编写——MCU固件升级系列2(STM32)文章来源地址https://www.toymoban.com/news/detail-435287.html

到了这里,关于bootloader编写——MCU固件升级系列2(STM32)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • stm32利用bootloader与app实现远程升级

    1、flash空间分配: 事先在flash开辟好空间,假设flash为128k,我这边给它分为五个区,分别为bootloader、标志位、application、application backup、标签ID。 (注:升级之前,app的代码烧录于application的flash存储区域内。用于app升级的 bin文件 大小一定要小于自己开辟的flash空间大小)

    2024年02月13日
    浏览(37)
  • STM32F103 USB OTA升级BootLoader (一)

     1.配置外部高速晶振  2.勾选USB功能  3.将USB模式配置Virtual Port Com  4.将系统主频配置为72M,USB频率配置为48M.  5.配置好项目名称,开发环境,最后获取代码。 6.修改Flash大小和勾选Use Micro LIB   7.修改main.c代码  Update.c代码 Update.h代码  源码链接: 跳转链接 上位机升级工具:

    2024年02月11日
    浏览(40)
  • 【STM32】IAP升级01 bootloader实现以及APP配置(主要)

    通过之前的了解 之前的了解,我们知道实现IAP升级需要两个条件: 1.APP程序必须在 IAP 程序之后的某个偏移量为 x 的地址开始; 2.APP程序的中断向量表相应的移动,移动的偏移量为 x; 默认条件下的起始地址 默认的条件下,图中 IROM1 的起始地址(Start)一般为 0x08000000,大小

    2024年02月03日
    浏览(34)
  • 基于STM32单片机BOOTLOADER通过串口升级程序IAP——APP方案

                            此方法前提是你得有一个EEPROM         我用的单片机是STM32F103ZET6 , 此单片机FLASH容量为512KB; 在此单片机里面FLASH的起始地址是0X8000000,BOOT作为引导加载程序一般都是从这个地址开始,单片机一上点默认会从这个地址开始运行,所以将自己

    2024年02月04日
    浏览(42)
  • stm32、gd32等芯片固件升级思路

    众所都周知,固件固件就是固定不动的软件,所以不用升级,此贴完结。 。 。 。 。 。 哎,话虽如此固件一般情况下不需要更新,毕竟主要功能是为控制一些底层的硬件,但是你永远不知道明天和需求哪个先来。所以在一些必要时刻需要给你的单片机留一个后门用于应对各

    2024年02月12日
    浏览(42)
  • STM32深入系列02——BootLoader分析与实现

    ==== 文章汇总 ==== 这个应该是最基本的方法,只要自己写过程序的应该都会,将编译生成的 hex 文件使用 ST-Link 工具或者 J-Link 工具直接下载进 Flash 即可。Keil中点击下载也能一键下载。 下载时可以看到地址是从 0x0800 0000 ,即 Flash 的起始地址开始下载的。 优点 :简单,插上下

    2024年02月02日
    浏览(32)
  • STM32F0实现IAP升级固件

    好几年前写过一篇关于 STM32 bootloader 升级固件的博客,但是使用的芯片是 STM32 F4 系列,升级固件的方式是在外部 flash 的 fat32 文件系统中存入固件文件,reset 后通过特定按键进入 IAP 程序。 最近需要在 STM32 上实现同样的 IAP 功能,但是方式不太一样,也发现一些芯片的差别,

    2024年02月14日
    浏览(36)
  • STM32单片机实现固件在线升级(IAP)

    单片机的固件升级方式有很多种, 1、ICP:In Circuit Programing,简单说就是在单片机开发时使用烧录器升级程序,比如使用J-Link烧录单片机程序。 2、ISP:In System Programing,在单片机内部实现了基于通信接口(如串口、I2C、SPI等等)的FLASH引导程序,配合厂家提供的烧录软件工具

    2024年02月13日
    浏览(45)
  • STM32 USB DFU固件升级的设计与实现

    STM32微控制器支持通过USB DFU(Device Firmware Upgrade)协议进行固件升级,这使得设备可以在不需要特殊的调试工具或编程器的情况下,通过USB接口实现固件的更新。 在本文中,我们将介绍如何设计和实现STM32 USB DFU固件升级功能,并提供相关的代码示例。 ✅作者简介:热爱科研

    2024年01月25日
    浏览(34)
  • STM32 IAP应用开发——通过USB实现固件升级

    什么是IAP? IAP(In-Application Programming) 指MCU可以在系统中获取新代码并对自己重新编程,即可用程序来改变程序。在应用编程(IAP)是用户的应用代码对片内Flash存储器进行擦除/编程的方法。这种方式的典型应用就是用一小段代码来实现程序的下载,实际上单片机的ISP功能就

    2024年02月12日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包