首页 > 其他分享 >STM32单片机实现固件在线升级(IAP)

STM32单片机实现固件在线升级(IAP)

时间:2023-08-15 21:34:41浏览次数:38  
标签:ADDR APP FLASH 程序 STM32 单片机 地址 固件

固件升级方案综述

单片机的固件升级方式有很多种,
1、ICP:In Circuit Programing,简单说就是在单片机开发时使用烧录器升级程序,比如使用J-Link烧录单片机程序。
2、ISP:In System Programing,在单片机内部实现了基于通信接口(如串口、I2C、SPI等等)的FLASH引导程序,配合厂家提供的烧录软件工具或自行开发的软件实现程序烧录。
3、IAP:In applicating Programing,是指单片机程序开发好之后在运行过程中由外部用户发起的在线升级,这种升级方式一般由用户自行设计升级方案,方案灵活性和自由度较高,在智能家居、汽车电子、物联网设备中常用的OTA(Over The Air)即空中下载技术原理也与之类似。
本文以STM32单片机为例介绍了IAP的设计原理。

划分FALSH存储区域

在STM32系列单片机中,程序存储在内部FLASH中,按照不同的单片机型号FLASH大小有所不同,有64KB、128KB、512KB等等。以STM32F407VET6系列单片机为例,内置FLASH大小为512KB,存储地址为0x08000000-0x0807FFFF。单片机每次程序复位时从0x08000000的位置开始执行主程序,如果不做IAP则这512KB空间都可以用来存储用户编写的APP程序。
若要实现IAP功能则必须将FLASH空间划分为几个部分,每部分都存储一个可以独立运行的程序文件(可以理解为几个独立的单片机工程):
1、引导程序,每次复位时程序默认执行此程序,在接下来的执行过程中可以跳转到用户编写的程序,因此这部分程序是固化在以0x08000000为起始的区域中。在引导程序中可以对电路系统作出一些自检和初始化检查的工作,因此该程序又称为bootloader或boot程序,需要注意的是在设计bootloader时要提前规定好程序空间的大小,比如规定程序存储区域为0x08000000-0x8007FFF,则bootlader程序存储空间为32KB,编写boot程序时要注意这一点
2、用户需要升级的新程序,这部分包含了用户的业务代码,复杂的运算逻辑和算法实现均在这一部分完成,称为APP程序,该部分程序一般存储在bootloader区域之后的FLASH中。用一个不是特别恰当的例子类比bootloader和APP:bootloader相当于电脑组装时的BIOS,APP则相当于操作系统,电脑开机时首先运行BIOS,完成后跳转运行到操作系统。
3、升级之前的老版APP备份。这部分相当于电脑系统更新前对老系统的备份,一旦在升级过程中发生错误需要还原到备份系统,防止系统升级失败成砖。同样的APP与APP备份将剩余的FLASH平分,以上述booloader为例,APP程序及其备份所占区域为:(512-32)/2=240KB,因此编写的APP程序编译后的占用的FLASH空间不得超过240KB,这一点可以通过查验.map文件确认,对于不同FLASH大小的芯片可以类比以上计算方法确认自己的程序大小上限(在此插入一句,改变编译器的优化等级可以改变最后的程序大小,但是高的优化等级对程序编写规范要求更高,因此优化等级应该在一开始设计APP之前就确定好,中途变更会带来不可预测的问题)。
以STM32F407VET6单片机为例划分后的FALSH存储框图如下所示:

bootlader设计

根据上面的描述,bootloader主要有完成以下功能:
1、系统自检
2、实现APP程序跳转
3、升级过程中接收APP文件并存储到对应的FLASH区域
功能1、3对于不同的系统要求不同,自检的内容以及实现文件传输的物理层接口和链路协议不同,不在此过多描述。下面主要给出APP跳转的部分代码:

#define  APP_ADDR     0x08008000    //应用程序起始地址 
typedef  void (*pFunction)(void);   //重定义pFunction为void(*)(void)函数指针类型
void jump(void)
{
	uint32_t      APP_ADDR_Buff=0;   //缓存APP地址数值
	uint32_t      APP_ADDR_Value=0;  //APP地址的内容
	uint32_t     Jump_ADDR;        //跳转的目标地址
	pFunction    Jump_APP;        //跳转的目标函数指针
	APP_ADDR_Buff = APPLICATION_ADDRESS; //用户程序的首地址
	APP_ADDR_Value = (*(volatile uint32_t*)APP_ADDR_Buff);//取出首地址里面的值
	if (( APP_ADDR_Value & 0x2FFE0000 ) == 0x20000000) //判断APP首地址里面存的栈顶地址值是否合法
	{
			DISABLE_INTERRUPTS(); //关总中断,使用不同的库写法不同,不可直接复制
			RCC_DeInit();//将外设RCC寄存器重设为缺省值,使用不同的库写法不同,不可直接复制
			Jump_ADDR = *(volatile uint32_t*)(APP_ADDR_Buff + 4);//APP起始地址第二个字为程序开始地址(新程序复位地址)
		    //指针函数指向用户程序地址,也就是PC指针goto到用户程序起始地址
			Jump_APP = (pFunction)Jump_ADDR; //取出程序地址给指针函数
			__set_MSP(*(volatile uint32_t*)APP_ADDR_Buff);    //初始化APP的堆栈指针 
			Jump_APP();     //执行指针函数,实现程序跳转
	}
    else
    {
        ErrorHandle();  //抛出异常
    }
}
int main(void)
{

	SystemInit();//系统时钟初始化
	SYSInit();  //系统初始化
	delay_ms(200);	
    if(ReadProgramAPPFlag())  //如果需要更新APP
    {
        APP_FlashWrite(); //接收APP文件数据,并将APP程序存储到指定位置
        if(APP_Check())   //APP文件校验通过,将新的APP程序更新到备份区域
            APP_Backup(); 
        else			 //否则恢复备份区
            APP_Restore();
        ResetProgramAPPFlag();  //对完成升级的标志复位
    }
    jump();    //正常情况下运行到这一步时APP区域已经正确写入程序文件
	while(1);	  
}

其中ReadProgramDoneFlag()是判断程序应该是先接收升级文件再跳转还是直接跳转的标志,在APP中如果有升级需求则对这个标志置位,在bootloader中完成文件接收之后对标志复位,需要注意的时这个标志位不是全局变量也不是局部变量,要保证程序跳转,初始化堆栈之后这个标志的值不受影响,因此该标志变量最佳选择是写在外部EEPROM或内置FLASH中,读写标志的操作其实是对EEPROM或FLASH的读写。

编写APP程序

APP程序中实现了用户的业务代码,和由APP跳转回bootloader的逻辑,实际的操作还是对上文中程序存储Flag的读写,这部分逻辑实现的流程图如下图所示:

由于APP程序对应的是另外一个工程文件,因此在工程设置中要将FLASH的偏移地址向下移动,空出bootlader的区域,比如上文中bootloader区域是0x08000000-0x08008000,因此APP工程的FLASH起始地址是0x8008000,偏移量是0x8000,这一点非常重要。

标签:ADDR,APP,FLASH,程序,STM32,单片机,地址,固件
From: https://www.cnblogs.com/JXL-Blogs/p/17632507.html

相关文章

  • STM32F103C8T6测试点亮小灯
    目录代码代码#include"stm32f10x.h"//Deviceheaderintmain(void){ // 寄存器操作,stm32有很多寄存器,操作不方便,推荐使用标准库或HAL库// RCC->APB2ENR=0x00000010;// GPIOC->CRH=0x00300000;// GPIOC->ODR=0x00002000; //注意:步骤二中,需引......
  • iTOP-RK3588开发板单独编译Android固件-打包update.img
    在ubootkernelandroid都编译完成的情况下,才可以打包update.img,所以一般在完整编译的时候用。输入以下命令:./build.sh-u打包完成会在rockdev/Image-rk3588_s目录下生成update.img镜像。更多内容:B站搜索迅为RK3588开发板......
  • stm32cubemx 配置波特率
    1、参考链接:https://www.cnblogs.com/forever-youth/p/15807690.html 2、步骤:   1、先算出连接can总线的PCLK1时钟频率   2、再根据公式:can波特率=pclk1/((tbs1+tbs2+sync_seg)*brp)     其中PCLK1就是时钟频率,sync_seg一般默认固定为1   ......
  • 2-了解单片机基础功能
    目录一.阅读STM32F103C8DataSheet一.阅读STM32F103C8DataSheet1.芯片优势2.内核以及存储器3.时钟,复位和电源管理4.DMA通道示意图5.引脚定义图6.调试模式和定时器7.看门狗(程序正常运行会喂狗,一旦程序跑飞就不能喂狗,看门狗就会复位)8.I2C......
  • 野火stm32指南者开发板点亮LED
    目录1.芯片手册中的LED电路图2.官网手册3.代码演示3.1stm32f10x.h头文件3.2点亮绿灯3.3点亮蓝灯3.4点亮红灯3.5LED灯闪烁,绿灯闪烁。3.6红绿蓝三色LED灯切换闪烁1.芯片手册中的LED电路图2.官网手册3.代码演示3.1stm32f10x.h头文件#ifndef_STM32F10X_H#define_ST......
  • 华硕官方固件安装alist+ddns-go ipv6实现异地访问磁盘文件
    表哥在前面的一期文章中,讲到了在pandb固件中安装alist。在此本文为大家介绍华硕路由器官方固件如何配置ipv6+alist+gdns配置。实验环境华硕路由器(官方固件)安装alist安装DDNS-GO开启IPv6访问配置ipv6首先利用超级管理员密码登录光猫,设置网络模式为桥接模式然后,登录路由器,设置上网方......
  • 01-了解STM32以及ARM
    目录一.ARM概念二.什么是STM32一.ARM概念1.ARM全称AcornRISCMachine(英国Acorn公司精简指令集机器).ARM处理器本身是32位设计,但也配备16位指令集,一般来讲比等价32位代码节省35%,却能保留32位系统的所有优势.2.Acorn公司在英国,它本身并不生产芯片而是为芯片厂......
  • 单片机原理2:定时器和中断
    定时器定时器寄存器:TMOD:方式寄存器,设定定时器0和定时器1的工作方式C/T:0为定时,1为计数TCON:控制寄存器,可位寻址TCON:TF1|TR1|TF0|TR0|IE1|IT1|IE0|IT0前面四位用于定时/计数,后面四位用于控制外部中断两个模式:定时和计数模式中断:主程序因为随机事件发生,暂停现行程序的运行,......
  • stm32 HAL UART DMA 发送
    MCU STM32H743IIT6     constuint8_tTEXT_TO_SEND[]={"ALIENTEKApolloSTM32H7DMA"};constuint8_tTEXT_TO_SEND2[]={"helloworld!"};externUART_HandleTypeDefhuart1;intmain(void){/*USERCODEBEGIN1*//*USERCODE......
  • STM32标准库实现Flash存储和读取
     在STM32F103C8T6微控制器上使用标准库实现Flash存储和读取数据可以通过以下步骤完成:首先,确保你已经配置好了STM32F103C8T6的Flash存储器。默认情况下,Flash存储器已经被分成了两个扇区,一个用于存放程序代码(MainFlashMemory),另一个用于存放数据(DataEEPROM)。在代码中包含s......