将STM32 内部Flash虚拟成优盘,进行IAP升级

news2024/10/7 4:31:03

        书接上回,上篇文章已经成功的将 STM32 内部FLASH虚拟成优盘进行文件存储了。

【将 STM32 内部Flash虚拟成优盘】icon-default.png?t=M85Bhttps://blog.csdn.net/qq_44810226/article/details/127508789

        然后我们开始固件升级流程:

       

 从上图可以看出,固件存储的位置是不知道的,不确定的,但是一定在U盘存储的区域内。

        我们可以通过给bin文件加上一些标志,来在Flash中判断是否有固件存在。如下图所示,给bin文件开头添加 固件名称、软件版本、硬件版本、起始地址、校验位、长度等数据。

 

因为FAT系统存储的特性,每个文件都会在扇区的开头存储,我们设置的扇区大小为0x200,所以我们可以在U盘开始的地址来遍历,搜索每个地址的前几个字符是否为我们想要固件的名称。

/*************************************************************
** Function name:       FindBinFileAddr
** Descriptions:        在指定地址查找是否有固件存在
** Input parameters:    None
** Output parameters:   None
** Returned value:      固件地址 或者 0(没有找到)
** Remarks:             None
*************************************************************/
uint32_t FindBinFileAddr(void){
	unsigned char tempBuff[14] = {0};
	for(uint16_t i=40;i<BLOCKNUM;i++){
  		memcpy(tempBuff, (char *)(MASS_STORAGE_CLASS_START_ADDR+(i*STORAGE_BLK_SIZ)), sizeof(tempBuff)-1);
		if (strcmp(tempBuff, BIN_START_FLAG) == 0){
			SEGGER_RTT_printf(0,"Find Fw StartName in[%x]	USB-Device Sector %d->   %s\r\n",(MASS_STORAGE_CLASS_START_ADDR+(i*STORAGE_BLK_SIZ)),i,tempBuff);
			return (MASS_STORAGE_CLASS_START_ADDR+(i*STORAGE_BLK_SIZ));
		} 
	}
	SEGGER_RTT_printf(0,"Not Find Fw !!!\r\n");
	return 0;
}

这里还可以先判断一下固件的其他描述参数,判断固件是否有效,也可以在后面判断。

找到固件之后就可以进行正常升级了。

找到合适的固件之后,判断固件是否有效:通过名称、CRC、版本号等

这里我将升级用到的参数都做到了一个 结构体中,方便后面写代码。PUpdateFw_Struct 是这个结构体的指针。


UPDATE_Frameware_INIT(gFWUpdate,0x08050600,0x08019000,50,STMFLASH_ReadByte,STMFLASH_Write,2048);

.c文件 

/*************************************************************
** Function name:       FWInit
** Descriptions:        固件升级 初始化
** Input parameters:    None
** Output parameters:   None
** Returned value:      None
** Remarks:             None
*************************************************************/
uint8_t FWUpdateInit(PUpdateFw_Struct fw){

    uint16_t checkCRC = 0;
    memcpy(fw->info_fwName,(uint8_t *)(fw->fwAddr),FW_NAME_LENGTH);
    memcpy(fw->info_fwVersion,(uint8_t *)(fw->fwAddr+FW_NAME_LENGTH),FW_VERSION_LENGTH);
    memcpy(&fw->info_fwLength,(uint32_t *)(fw->fwAddr+FW_NAME_LENGTH+FW_VERSION_LENGTH),4);
    memcpy(fw->info_boardVersion,(uint8_t *)(fw->fwAddr+FW_NAME_LENGTH+FW_VERSION_LENGTH+4),FW_VERSION_LENGTH);
    memcpy(&fw->info_crc,(uint8_t *)(fw->fwAddr+FW_NAME_LENGTH+2*FW_VERSION_LENGTH+4+4),sizeof(uint16_t));
    memcpy(fw->info_binEndFlag,(uint8_t *)(fw->fwAddr+48+fw->info_fwLength),BIN_END_FLAG_LENGTH);

    checkCRC = usMBCRC16((unsigned char *)(fw->fwAddr+48),fw->info_fwLength);

    if (strcmp(fw->info_fwName, BIN_START_FLAG) != 0){
        SEGGER_RTT_printf(0,"fw name is err ! not a effective firmware ... \r\n");
        return 0;
    }
    if (strcmp(fw->info_binEndFlag, BIN_END_FLAG) != 0){
        SEGGER_RTT_printf(0,"fw end name is err ! not a effective firmware ... \r\n");
        return 0;
    }
    if (checkCRC != fw->info_crc){
        SEGGER_RTT_printf(0,"crc check is err ! not a effective firmware ... \r\n");
        return 0;
    }

    SEGGER_RTT_printf(0,"   Firmware effective  : name-> %s  \r\n",fw->info_fwName);

    SEGGER_RTT_printf(0,"   Version-> %d.%d.%d.%d\r\n",fw->info_fwVersion[0],fw->info_fwVersion[2],fw->info_fwVersion[4],fw->info_fwVersion[6]);
    SEGGER_RTT_printf(0,"   FileLength-> %x\r\n",fw->info_fwLength);
    SEGGER_RTT_printf(0,"   BoardVersion-> %d.%d.%d.%d\r\n",fw->info_boardVersion[0],fw->info_boardVersion[2],fw->info_boardVersion[4],fw->info_boardVersion[6]);
    // crc 检测
    SEGGER_RTT_printf(0,"   FileCRC-> %x\r\n",fw->info_crc);
    SEGGER_RTT_printf(0,"   CheckCRC-> %x \r\n",checkCRC);

    SEGGER_RTT_printf(0,"   FileEndName-> [%p] %s\r\n",(uint8_t *)(fw->fwAddr+48+fw->info_fwLength),fw->info_binEndFlag);

    // 返回是否init成功 如果失败则代表不是一个正常的固件 不可以进行升级
    return 1;
}


void (*JumpToApplication)(void);
uint32_t gJumpAddress;
typedef  void (*pFunction)(void);

/*************************************************************
** Function name:       FWStartUpdate
** Descriptions:        开始升级
** Input parameters:    None
** Output parameters:   None
** Returned value:      None
** Remarks:             None
*************************************************************/
void FWStartUpdate(PUpdateFw_Struct fw){
    fw->WriteByte(fw->appAddr,(uint32_t *)(fw->fwAddr+48),fw->info_fwLength/8);
    SEGGER_RTT_printf(0,"Write FW ok \r\n");

    uint32_t erase[2] = {0};

    // 破坏APP2 固件存储的地址 
    fw->WriteByte(fw->fwAddr,erase,1);
    SEGGER_RTT_printf(0,"Eares app2 fw ok \r\n");
    // 破坏fat结构 上电重新初始化
    // fw->WriteByte(MASS_STORAGE_CLASS_START_ADDR,erase,1);

    // 跳转到APP
    /* Test if user code is programmed starting from address 0x0800C000 */
    // 检查栈顶是否合法,确保栈顶落在0x2000 0000 - 0x2001 0000 之间,刚好在stm32f1的RAM范围内
    if (((*(__IO uint32_t *)fw->appAddr) & 0x2FFE0000) == 0x20000000)
    {
        SEGGER_RTT_printf(0,"Check ok %x  %x  %x \r\n",fw->appAddr,(*(__IO uint32_t *)fw->appAddr),((*(__IO uint32_t *)fw->appAddr) & 0x2FFE0000));
    // 检查reset入口是否正确
    // if (((*(uint32_t*)(STM32_APP_BASE + 4)) & 0x0fff0000 ) == 0x08020000 ) 

      /* Jump to user application */
      gJumpAddress = *(__IO uint32_t *)(fw->appAddr + 4);
      JumpToApplication = (pFunction)gJumpAddress;

      /* Reset of all peripherals */
      HAL_DeInit();

      /* Set interrupt vector to app code */
      SCB->VTOR = fw->appAddr;

      /* Initialize user application's Stack Pointer */
      __set_MSP(*(__IO uint32_t *)fw->appAddr);
        __disable_irq();
      JumpToApplication();
    }else{
        SEGGER_RTT_printf(0,"Check err %x  %x  %x \r\n",fw->appAddr,(*(__IO uint32_t *)fw->appAddr),((*(__IO uint32_t *)fw->appAddr) & 0x2FFE0000));

    }

}

 .h文件

// 写入前先检查 是不是所有位置都可以写入:即是不是0xff  如果不是则擦除所在位置

struct SUpdateFw_Struct {
    // 固件存放地址
    uint32_t fwAddr;
    // 写入地址:APP1地址
    uint32_t appAddr;
    // APP1所在区块
    uint16_t appSector;

    // 读取函数
    uint8_t (*ReadOneByte)(uint32_t addr);
    // 写入函数
    void (*WriteByte)(uint32_t addr,uint32_t *data, uint32_t num);
    // Flash Sector 大小
    uint16_t sectorSize;

    // 固件Info
    char info_fwName[FW_NAME_LENGTH+1];
    // 固件版本信息
    char info_fwVersion[FW_VERSION_LENGTH+1];
    // 固件长度
    uint32_t info_fwLength;
    char info_boardVersion[FW_VERSION_LENGTH+1];
    // info中的起始地址
    uint32_t info_startAddr;
    // 固件Info
    uint16_t info_crc;
    char info_binEndFlag[BIN_END_FLAG_LENGTH+1];
};
typedef struct SUpdateFw_Struct UpdateFw_Struct;
typedef UpdateFw_Struct *PUpdateFw_Struct;

//                              固件存放地址、写入地址:APP1地址、 APP1所在区块、 读取函数、 写入函数、  Flash Sector 大小
#define UPDATE_Frameware_INIT(xname,xfwAddr,xappAddr,xappSector,xReadOneByte,xWriteByte,xsectorSize)     \
UpdateFw_Struct xname = {                                                 \
    .fwAddr = xfwAddr,                                  \
    .appAddr = xappAddr,                                \
    .appSector = xappSector,                            \
    .ReadOneByte = xReadOneByte,                        \
    .WriteByte = xWriteByte,                            \
    .sectorSize = xsectorSize,                          \
    .info_fwName = {0},                                 \
    .info_fwVersion = {0},                              \
    .info_fwLength = 0,                                 \
    .info_boardVersion = {0},                           \
    .info_startAddr = 0,                                \
    .info_crc = 0,                                      \
    .info_binEndFlag = {0},                             \
};

 

 这里程序参考意义不大,可能指针会有点难看。我将整个代码放在csdn中,需要的同学可以下载学习。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1423.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python-代码封装思想

继上文所将讲的pythonrequestsUnittest框架&#xff0c;本文将继续分享python代码的进一步封装思想&#xff0c;来提高代码的整体运行效率及整洁性&#xff0c;本文以接口测试框架为例进行讲解。 关于Unittest单元测试框架的具体使用方法链接链接&#xff08;点击跳转&#xf…

MMEngine理解

MMEngine理解1 简介1.1 架构1.2 模块介绍1.2.1 核心模块与相关组件1.2.1 公共基础模块2 上手示例2.1 构建模型2.2 构建数据集和数据加载器2.3 构建评测指标2.4 构建执行器并执行任务3. 基础模块3.1 注册器&#xff08;Registry&#xff09;3.1.1 什么是注册器3.1.2 使用流程3.1…

OSPF路由协议(二)

作者介绍&#xff1a; ⭐️作者&#xff1a;小刘在C站 ❄️每天分享课堂笔记&#xff0c;一起努力&#xff0c;共赴美好人生&#xff01; ☁️夕阳下&#xff0c;是最美的绽放。 目录 一.Router id 二.DR,BDR 三.DR BDR 选举过程 四.ospf 度量值 cost 代价 五.ospf 的数据…

部署vue项目到阿里云服务器

一般前端工程师只会使用npm run serve 在开发环境下验证&#xff0c;那么如何把npm run build 打出的包部署到服务器上进行上线呢&#xff1f;这篇文章就详细阐述这一流程。 1. 购买或试用阿里云服务器 作为新用户可以试用一个月阿里云服务器&#xff0c;阿里云官方网址如下&a…

【数据结构与算法分析】0基础带你学数据结构与算法分析07--二叉树

在学习上一章后&#xff0c;我们对树加以限制&#xff0c;如果树的度为 2&#xff0c;那么就称这颗树为 二叉树 (binary tree)。 二叉树的性质 在一棵二叉树上&#xff0c;有一些重要的性质&#xff1a; 第 i 层 (i∈N) 上最多有 2^(i−1) 个结点层次为 k(k∈N) 的树最多有 …

进程地址空间

目录 程序地址空间 感知虚拟地址空间的存在 进程地址空间 分页 & 虚拟地址空间 Linux2.6内核进程调度队列 程序地址空间 我们在学习C语言的时候了解过程序地址空间的分布&#xff1a; 需要注意的是&#xff1a;程序地址空间不是内存。我们在linux操作系统中通过代码来…

刷题笔记之二(字符串中找出连续最长的数字串+数组中出现次数超过一半的数字+另类加法+计算糖果+进制转换)

目录 1. 多层继承问题 2. 继承中子类的构造要引用super 3. 比较地址 4. 字符串中找出连续最长的数字串(编程题) 5. 数组中出现次数超过一半的数字&#xff08;编程题&#xff09; 6. 另类加法&#xff08;编程题&#xff09; 7. Interface 接口中定义方法 8. 实现或继…

C语言学习(二)之字符串和格式化输入/输出

文章目录一、字符串二、 输入2.1 scanf()作用2.2 两种用法三、输出3.1 printf()3.1.1 printf 四种用法3.1.2 常用输出控制符3.1.3 为什么需要输出控制符一、字符串 字符串是一个或多个字符的序列。如&#xff1a;“Hello World” 双引号不是字符串的一部分。仅告知编译器它括…

【学习笔记】《深入浅出Pandas》第16章:可视化

文章目录16.1 plot方法16.1.1 plot概述16.1.2 plot基础方法16.1.3 图形类型16.1.4 x轴和y轴16.1.5 图形标题16.1.6 字体大小16.1.7 线条样式16.1.8 背景辅助线16.1.9 图例16.1.10 图形大小16.1.11 色系16.1.12 绘图引擎16.1.14 图形叠加16.1.15 颜色的表示16.1.16 解决图形中的…

量子笔记:量子计算 toy python implementation from scratch

目录 0. 概要 1. 量子比特表示&#xff1a;用二维张量表示 2. 张量积的实现 2.1 用scipy.linalg.kron()实现张量积 2.2 用张量积计算双量子系统的基 3. 多量子系统基向量表示和生成 3.1 Helper function: bin_ext 3.2 多量子系统的基的生成 3.3 numpy.matrix numpy.m…

基于多尺度注意力网络单图像超分(MAN)

引言 Transformer的自注意力机制可以进行远距离建模&#xff0c;在视觉的各个领域表现出强大的能力。然而在VAN中使用大核分解同样可以得到很好的效果。这也反映了卷积核的发展趋势&#xff0c;从一开始的大卷积核到vgg中采用堆叠的小卷积核代替大卷积核。 上图展现了MAN网络在…

使用T0,方式2,在P1.0输出周期为400µs,占空比为4:1的矩形脉冲,要求在P1.0引脚接有虚拟示波器,观察P1.0引脚输出的矩形脉冲波形

大家学过一段时间的单片机了&#xff0c;今天我们来说说单片机里的定时器&#xff0c;又叫计数器。首先&#xff0c;我们通过案例来了解一下什么是定时器。 【例】使用T0&#xff0c;方式2&#xff0c;在P1.0输出周期为400s&#xff0c;占空比为4&#xff1a;1的矩形脉冲&…

如何编写优秀的测试用例,建议收藏和转发

1、测试点与测试用例 测试点不等于测试用例&#xff0c;这是我们首先需要认识到的。 问题1&#xff1a;这些测试点在内容上有重复&#xff0c;存在冗余。 问题2&#xff1a;一些测试点的测试输入不明确&#xff0c;不知道测试时要测试哪些。 问题3&#xff1a;总是在搭相似…

串口通信协议【I2C、SPI、UART、RS232、RS485、CAN】

&#xff08;1&#xff09;I2C 集成电路互连总线接口(Inter IC)&#xff1a;同步串行半双工传输总线&#xff0c;连接嵌入式处理器及其外围器件。 支持器件&#xff1a;LCD驱动器、Flash存储器 特点&#xff1a; ①有两根传输线&#xff08;时钟线SCL、双向数据线SDA&#…

python基础19-36题

题目&#xff1a; 代码十九二十二十一二十二二十三二十四二十五二十六二十七二十八二十九三十三十一三十二三十三三十四三十五三十六十九 birthday int(input(“请输入生日日期&#xff1a;”)) Set1 [1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31] Set2 [2,3,6,7,10,11,…

【CV】第 7 章:目标检测基础

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

几何等变图神经网络综述

许多科学问题都要求以几何图形&#xff08;geometric graphs&#xff09;的形式处理数据。与一般图数据不同&#xff0c;几何图显示平移、旋转和反射的对称性。研究人员利用这种对称性的归纳偏差&#xff08;inductive bias&#xff09;&#xff0c;开发了几何等变图神经网络&a…

SpringMVC | 快速上手SpringMVC

&#x1f451; 博主简介&#xff1a;    &#x1f947; Java领域新星创作者    &#x1f947; 阿里云开发者社区专家博主、星级博主、技术博主 &#x1f91d; 交流社区&#xff1a;BoBooY&#xff08;优质编程学习笔记社区&#xff09; 前言&#xff1a;在上一节中我们了解…

多分类评估指标计算

文章目录混淆矩阵回顾Precision、Recall、F1回顾多分类混淆矩阵宏平均&#xff08;Macro-average&#xff09;微平均&#xff08;Micro-average&#xff09;加权平均&#xff08;Weighted-average&#xff09;总结代码混淆矩阵回顾 若一个实例是正类&#xff0c;并且被预测为正…

Linux(Nginx)

目录 一、Nginx简介 二、Nginx使用 Nginx安装 tomcat负载均衡 Nginx配置 三、Nginx部署项目 项目打包前 将前端项目打包&#xff08;测试本地项目打包后没问题&#xff09; ip/host主机映射 完成Nginx动静分离的default.conf的相关配置 将前台项目打包(配合Nginx动静…