单片机中OTA升级流程及bootload软件框架

本文详细介绍了OTA升级原理及流程,并提供了针对STM32单片机的Bootloader软件框架和源码示例,帮助读者理解如何实现远程固件更新。

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

为什么要进行OTA升级

OTA 英文全称是Over-the-Air Technology,即空间下载技术,是通过移动通信(GSM或CDMA)的空中接口对SIM卡数据及应用进行远程管理的技术。在我们常用的电子设备中,通过会进行软件优化或者固件升级,这个时候我们的产品可能已经在全国各地,不可能亲自去进行固件升级,所以就需要利用OTA技术进行升级。

OTA升级的流程

这里的升级流程框架我是按照我之前的一个项目写的,该项目中所用单片机的FLASH大小为128K,其中包含我的FLASH分配,和APP和BOOTLOAD对于升级流程实现
在这里插入图片描述

bootload软件框架

这里主要是bootload代码的实现框架和一些具体的细节问题,可以和下面的后面的代码部分相结合阅读。
在这里插入图片描述

bootload软件源码(针对接收HEX文件)

这里我就只放一下IAP的头文件和源文件
#ifndef _IAP_H_
#define _IAP_H_
#include "stm32f10x.h"

#define FlashBaseAddress              0x08000000
#define ApplicationAddress    			0x8003000
#define ApplicationSize							0xD000						// 52KB
#define ApplicationBackup						(ApplicationAddress + ApplicationSize)
typedef  void (*pFunction)(void);

#define UPGRADE_FLAG_START	    				((uint16_t)0x1010)
#define UPGRADE_FLAG_RECV_COMPLETE				((uint16_t)0x2020)
#define UPGRADE_FLAG_END						((uint16_t)0x3030)	// 注意如果没有读到0x600的值也视为已经完成

extern volatile uint8_t updateFinished;
extern uint32_t maxProgramAdd;

void jumpToApplication(void);//跳转到APP程序

uint8_t IsUpgradeStarted(void);//开始Bootload升级标记
uint8_t IsUpgradeRecEnd(void);//接收Bootload升级标记
uint8_t IsUpgradeComplete(void);////Bootload升级完成标记

uint8_t EraseFlash(uint32_t baseAddress);//擦除FLASH
uint8_t WriteUpgradeFlag(uint16_t flagValue);//写半字
uint8_t WriteMaxProgramAddress(uint32_t address);//写OTA接收程序最大地址
uint8_t readMaxProgramAddress(uint32_t* addressValue);//读OTA接收程序最大地址
static uint8_t MassCopy(void);//根据程序大小,从Application备份区拷贝到Application区
uint8_t copyApplication(void);//擦除Application区,从备份区拷贝新程序到Application区

uint8_t HEX_File_Parsing(uint8_t * data,uint8_t len);//Hex文件解析

#endif
#include "iap.h"
#include "Flash.h"
#include "EEPROM.h"
#include "stdio.h"
pFunction Jump_To_Application;
uint32_t JumpAddress;
uint32_t maxProgramAdd=0;
volatile uint8_t updateFinished = 0;
void jumpToApplication(void)//跳转到APP程序
{
//	__set_PRIMASK(1);
//	__DSB();
//    __ISB();
//    SysTick->CTRL = 0;
	if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)       
	{
			JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);                 
			Jump_To_Application = (pFunction) JumpAddress;                             
			__set_MSP(*(__IO uint32_t*) ApplicationAddress);                           
			Jump_To_Application();                                                                 
	}
}

uint8_t IsUpgradeStarted(void)
{
	uint16_t FlashData;
	uint8_t FreshStatus=readSysU16(0x600,&FlashData);
	
	if(FreshStatus==0 && FlashData == UPGRADE_FLAG_START)
	{
		return 0;
	}
	return 1;	
}

uint8_t IsUpgradeRecEnd(void)
{
	uint16_t FlashData;
	uint8_t FreshStatus=readSysU16(0x600,&FlashData);
	FreshStatus |= readMaxProgramAddress(&maxProgramAdd);
	if(FreshStatus==0 && FlashData == UPGRADE_FLAG_RECV_COMPLETE)
	{
		return 0;
	}
	return 1;
}
uint8_t IsUpgradeComplete(void)
{
	uint16_t FlashData;
	uint8_t FreshStatus=readSysU16(0x600,&FlashData);
	
	if(FreshStatus==0 && FlashData == UPGRADE_FLAG_END)
	{
		printf("\r\n升级成功了!");
		return 0;
	}
	return 1;	
}

/**
  * @brief  擦除ApplicationSize大小的Flash
  * @param  None
  * @retval None
  */
uint8_t EraseFlash(uint32_t baseAddress) 
{
	uint8_t flashStatus = 0;
	for (uint32_t i = 0; i < ApplicationSize; i+=PAGE_SIZE)
	{
		flashStatus = FLASH_ErasePage(baseAddress + i);
		if (flashStatus != FLASH_COMPLETE) 
			return flashStatus;
	}
	return 0;
}

/**
  * @brief  Writes/upadtes variable data in EEPROM.
  * @param  flagValue: new value
  * @retval Success or error status:
  *           - 0: Success
  *           - PAGE_FULL: if valid page is full
  *           - NO_VALID_PAGE: if no valid page was found
  *           - Flash error code: on write Flash error
  */
uint8_t WriteUpgradeFlag(uint16_t flagValue) 
{
	uint8_t error = writeSysU16(0x0600, flagValue);
	return error == FLASH_COMPLETE ? 0 : error;
}
/**
  * @brief  Writes/upadtes variable data in EEPROM.
  * @param  flagValue: new value
  * @retval Success or error status:
  *           - 0: Success
  *           - PAGE_FULL: if valid page is full
  *           - NO_VALID_PAGE: if no valid page was found
  *           - Flash error code: on write Flash error
  */
uint8_t WriteMaxProgramAddress(uint32_t address) 
{
	uint8_t error = writeSysU16(0x0601, (u16)(address >> 16));
	if (error == FLASH_COMPLETE) error = writeSysU16(0x0602, ((u16)(address & 0xFF)));
	return error == FLASH_COMPLETE ? 0 : error;
}
/**
  * @brief  Returns the last stored max programAddress
  * @param  addressValue: Global variable contains the read variable value
  * @retval Success or error status:
  *           - 0: if variable was found
  *           - 1: if the variable was not found
  *           - NO_VALID_PAGE: if no valid page was found.
  */
uint8_t readMaxProgramAddress(uint32_t* addressValue) 
{
	u16 hb,lb;
	u8 flashStatus = readSysU16(0x0601, &hb) || readSysU16(0x0602, &lb);
	*addressValue = (((u32)hb) << 16) | lb;
	if (flashStatus == 0 && *addressValue > ApplicationAddress && *addressValue < ApplicationAddress + ApplicationSize) {
		return 0;
	}
	return 1;
}
/**
	* @brief  根据程序大小,从Application备份区拷贝到Application区
  * @param  None
  * @retval None
  */
static uint8_t MassCopy(void) 
{
	uint8_t flashStatus = 0;
	for (uint32_t i = 0; i <= (maxProgramAdd - ApplicationAddress); i+= 2)
	{
		flashStatus = FLASH_ProgramHalfWord(ApplicationAddress + i, readFlashU16(ApplicationBackup + i));
		if (flashStatus != FLASH_COMPLETE) return flashStatus;
	}
	return 0;
}
/**
	* @brief  擦除Application区,从备份区拷贝新程序到Application区
  * @param  None
  * @retval None
  */
uint8_t copyApplication(void) 
{
	uint8_t Error = 0; 
	
	printf("\r\n 开始擦除APP!");
	Error = EraseFlash(ApplicationAddress);
	if(Error)
		return (Error); 
	
	Error = MassCopy();
	if(Error)
		return (Error);
	
	Error = WriteUpgradeFlag(UPGRADE_FLAG_END);  // 擦除bootloader标志
	updateFinished = 1;
	return Error;
}

//Hex文件解析
uint8_t HEX_File_Parsing(uint8_t * data,uint8_t len)
{
	/*数据格式::|LL|aaaa|TT|data|CC|
	** :冒号 HEX文件每一行首字节都是由冒号开头
	** LL:数据域长度
	** AAAA:地址域
	** TT:类型域 00数据记录 
				  01文件结束记录 
				  02扩展段地址记录
				  03开始段地址记录
				  04扩展线性地址记录 
				  05开始线性地址记录
	** data:数据域
	** CC:校验
	*/
	uint8_t i;
	uint8_t crctotal=0;
	uint8_t flashStatus=0;
	uint16_t Flashdata=0;
	
	if(data[0]!=0x3A)//开头是不冒号
	{
		printf("\r\n error1");
		return 1;
	}
		
	
	for(uint8_t i=1;i<len-1;i++)//hex文件校验和
	{
		crctotal+=data[i];
	}
	if(crctotal!=(uint8_t)(0x100-data[len-1]))//crc校验不通过
	{
		printf("\r\n error2");
		return 1;
	}
		
	if(data[4]==0x04)//04扩展线性地址记录
	{
		uint32_t Freshaddress=(data[5]<<8)+data[6];
		if(Freshaddress!=0x0800)
			return 1;
	}
	else if (data[4]==0x00)//00数据记录
	{
		uint32_t Freshaddress=FlashBaseAddress + ((data[2]<<8)+data[3]);//这里应该是APP的地址
		
		maxProgramAdd=Freshaddress+data[1];//最大地址等于 目前最新地址+该行数据长度
		
		if(maxProgramAdd>=ApplicationBackup && maxProgramAdd<= ApplicationAddress)//如果地址越界
		{
			printf("\r\n error3");
			return 1;
		}
					
		for(i=0;i<data[1];i+=2)
		{
			uint32_t WriteAdree=Freshaddress+i;
	
			Flashdata=data[6+i]<<8;//半字高8位
			Flashdata+=data[5+i];//半字低8位
//			printf("\r\n要写的数据是%x",Flashdata);
//			printf("  要写的地址是%x",WriteAdree);
//			printf("\r\n要写的地址是%x",ApplicationBackup + (WriteAdree - ApplicationAddress));
			flashStatus = FLASH_ProgramHalfWord(ApplicationBackup + (WriteAdree - ApplicationAddress),Flashdata);
		
			if (flashStatus != FLASH_COMPLETE)
			{
				printf("\r\n error4 %d",flashStatus);
				return flashStatus;
			}			
		}
	}

	return 0;
}

如果看完有帮助的可以点赞收藏一下,还有不懂的可以直接联系我哦~
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_LiuChunJiang刘春江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值