STM32F103制作FlashDriver
文章目录
- 前言
- 芯片内存定义
- 实现过程
- FlashDriver生成
- 段定义
- 擦除函数
- 写入函数
- 编译后的map
- 手动测试
- HexView提取指定地址内容并重映射
- 总结
前言
在汽车行业控制器软件刷新流程中,一般会将Flash驱动单独进行刷写,目的是防止程序中一直存在Flash驱动的话,可能会造成对APP软件的异常操作,导致应用程序无法执行。本文介绍STM32F103使用KEIL生成指定FlashDriver地址的hex文件,然后使用HexView命令行提取FlashDriver及Remapping flash地址到ram地址
本文参考github,SummerFalls大神的UDS_S32K144_FlashDriver
芯片内存定义
STM32F103RCT6,flash大小256k,一个扇区2k,SRAM:48KB;
实现过程
FlashDriver生成
段定义
由于我无法直接在Keil中导出指定ram地址的hex文件,所以采用先定义指定flash地址的flash驱动,后面通过hexview实现地址重映射
keil中的内存区域定义通过分散加载文件(.sct格式)实现,如下所示
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************LR_IROM1 0x08000000 0x00020000 { ; load region size_region\ER_IROM1 0x08000000 0x00020000 { ; load address = execution address*.o (RESET, +First)*(InRoot$$Sections).ANY (+RO).ANY (+XO)}RW_IRAM1 0x20000800 0x0000C000 { ; RW data.ANY (+RW +ZI)}
}
LR_IROM2 0x08020000 0x00020000 {RW_IROM_flashdrvoffset 0x08020000 0x00000008{; load address = execution address*(.NVM_Driver_Section_offset) }RW_IROM_flashdrv 0x08020008 0x000007F8{; load address = execution address*(.NVM_Driver_Section) }}
此处设置了两个段,NVM_Driver_Section_offset用来设置函数偏移地址,NVM_Driver_Section用来设置函数地址
增加段的宏定义
#define NVM_DRIVER_SECTION __attribute__((section (".NVM_Driver_Section")))
#define NVM_DRIVER_SECTION_OFFSET __attribute__((section (".NVM_Driver_Section_offset")))
函数地址偏移量定义
__attribute__((used)) NVM_DRIVER_SECTION_OFFSET static const tFlashDriverAPIInfo gs_FlashDriverAPI = {(tpfFLASH_DRV_EraseSector) CAL_OFFSET(FLASH_ErasePage),(tpfFLASH_DRV_Program) CAL_OFFSET(FLASH_ProgramWord),
};
分两个段,保证地址偏移量在生成的hex文件的前面
此处使用库函数中的FLASH_ErasePage和FLASH_ProgramWord函数。由于提取的函数最终是以数组的形式存在,以函数指针的方式进行调用,所以函数中不能存在全局变量或调用其他的函数。
需要将原库函数中的函数的调用函数使用宏定义的方式进行定义,使用do while语法实现。
擦除函数
__attribute__((used)) NVM_DRIVER_SECTION FLASH_Status FLASH_ErasePage(uint32_t Page_Address)
{FLASH_Status status = FLASH_COMPLETE;FLASH_WaitForLastOperation(EraseTimeout,&status);if(status == FLASH_COMPLETE){ /* if the previous operation is completed, proceed to erase the page */FLASH->CR|= CR_PER_Set;FLASH->AR = Page_Address; FLASH->CR|= CR_STRT_Set;/* Wait for last operation to be completed */FLASH_WaitForLastOperation(EraseTimeout,&status);/* Disable the PER Bit */FLASH->CR &= CR_PER_Reset;}/* Return the Erase Status */return status;
}
上面的FLASH_WaitForLastOperation函数使用宏定义进行展开
#define FLASH_WaitForLastOperation(Timeout,pstatus)\
do{\uint32_t TimeoutCnt = Timeout;\*pstatus = FLASH_COMPLETE;\FLASH_GetBank1Status(pstatus);\while((*pstatus == FLASH_BUSY) && (TimeoutCnt != 0x00))\{\FLASH_GetBank1Status(pstatus);\TimeoutCnt--;\}\if(TimeoutCnt == 0x00 )\{\*pstatus = FLASH_TIMEOUT;\}\
}while(0)
里面又用到一个FLASH_GetBank1Status函数
#define FLASH_GetBank1Status(pFLASH_Status)\
do{\*pFLASH_Status = FLASH_COMPLETE;\if((FLASH->SR & FLASH_FLAG_BANK1_BSY) == FLASH_FLAG_BSY)\{\*pFLASH_Status = FLASH_BUSY;\}\else\{\if((FLASH->SR & FLASH_FLAG_BANK1_PGERR) != 0)\{\*pFLASH_Status = FLASH_ERROR_PG;\}\else\{\if((FLASH->SR & FLASH_FLAG_BANK1_WRPRTERR) != 0 )\{\*pFLASH_Status = FLASH_ERROR_WRP;\}\else\{\*pFLASH_Status = FLASH_COMPLETE;\}\}\}\
}while(0)
写入函数
__attribute__((used)) NVM_DRIVER_SECTION FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data)
{FLASH_Status status = FLASH_COMPLETE;__IO uint32_t tmp = 0;FLASH_WaitForLastOperation(ProgramTimeout,&status);if(status == FLASH_COMPLETE){/* if the previous operation is completed, proceed to program the new first half word */FLASH->CR |= CR_PG_Set;*(__IO uint16_t*)Address = (uint16_t)Data;/* Wait for last operation to be completed */FLASH_WaitForLastOperation(ProgramTimeout,&status);if(status == FLASH_COMPLETE){/* if the previous operation is completed, proceed to program the new second half word */tmp = Address + 2;*(__IO uint16_t*) tmp = Data >> 16;/* Wait for last operation to be completed */FLASH_WaitForLastOperation(ProgramTimeout,&status);/* Disable the PG Bit */FLASH->CR &= CR_PG_Reset;}else{/* Disable the PG Bit */FLASH->CR &= CR_PG_Reset;}} /* Return the Program Status */return status;
}
其中用到的函数也已经改为宏定义
编译后的map
gs_FlashDriverAPI 0x08020000 Data 8 main.o(.NVM_Driver_Section_offset)FLASH_ErasePage 0x08020009 Thumb Code 186 stm32f10x_flash.o(.NVM_Driver_Section)FLASH_ProgramWord 0x080200c3 Thumb Code 250 stm32f10x_flash.o(.NVM_Driver_Section)
函数需要偶数地址对齐
hexview中显示:
手动测试
__align(4) uint8_t flash_erase_buf[]={0x30,0xB5, 0x6C, 0x49, 0x04, 0x46, 0x4F, 0xF4,0x30, 0x22, 0xCD, 0x68, 0x04, 0x20, 0x13, 0x46, 0xED, 0x07, 0x09, 0xD1, 0xCB, 0x68, 0x5B, 0x07,0x01, 0xD5, 0x02, 0x20, 0x30, 0xBD, 0xCB, 0x68, 0xDB, 0x06, 0x18, 0xD5, 0x03, 0x20, 0x30, 0xBD,0xCD, 0x68, 0x04, 0x20, 0xED, 0x07, 0x02, 0xD0, 0x5B, 0x1E, 0xF9, 0xD1, 0x1C, 0xE0, 0xCD, 0x68,0x6D, 0x07, 0x01, 0xD5, 0x02, 0x20, 0x06, 0xE0, 0xCD, 0x68, 0xED, 0x06, 0x03, 0xD5, 0x03, 0x20,0x01, 0x2B, 0x11, 0xD0, 0x30, 0xBD, 0x01, 0x2B, 0x0E, 0xD0, 0x04, 0x28, 0xFA, 0xD1, 0x0B, 0x69,0x43, 0xF0, 0x02, 0x03, 0x0B, 0x61, 0x4C, 0x61, 0x0B, 0x69, 0x43, 0xF0, 0x40, 0x03, 0x0B, 0x61,0xCB, 0x68, 0xDB, 0x07, 0x0C, 0xD1, 0x01, 0xE0, 0x05, 0x20, 0x30, 0xBD, 0xCA, 0x68, 0x52, 0x07,0x01, 0xD5, 0x02, 0x20, 0x17, 0xE0, 0xCA, 0x68, 0xD2, 0x06, 0x14, 0xD5, 0x03, 0x20, 0x12, 0xE0,0xCB, 0x68, 0x04, 0x20, 0xDB, 0x07, 0x02, 0xD0, 0x52, 0x1E, 0xF9, 0xD1, 0x0A, 0xE0, 0xCB, 0x68,0x5B, 0x07, 0x01, 0xD5, 0x02, 0x20, 0x03, 0xE0, 0xCB, 0x68, 0xDB, 0x06, 0x00, 0xD5, 0x03, 0x20,0x01, 0x2A, 0x00, 0xD1, 0x05, 0x20, 0x0A, 0x69, 0x41, 0xF6, 0xFD, 0x73, 0x1A, 0x40, 0x0A, 0x61,0x30, 0xBD
};__align(4) uint8_t flash_write_buf[]={0xF8, 0xB5, 0x00, 0x92, 0x3C, 0x4A, 0x06, 0x46, 0x04, 0x20, 0xC3, 0x02,0xD4, 0x68, 0x1D, 0x46, 0xE4, 0x07, 0x09, 0xD1, 0xD4, 0x68, 0x64, 0x07, 0x01, 0xD5, 0x02, 0x20,0xF8, 0xBD, 0xD4, 0x68, 0xE4, 0x06, 0x18, 0xD5, 0x03, 0x20, 0xF8, 0xBD, 0xD4, 0x68, 0x04, 0x20,0xE4, 0x07, 0x02, 0xD0, 0x6D, 0x1E, 0xF9, 0xD1, 0x1B, 0xE0, 0xD4, 0x68, 0x64, 0x07, 0x01, 0xD5,0x02, 0x20, 0x06, 0xE0, 0xD4, 0x68, 0xE4, 0x06, 0x03, 0xD5, 0x03, 0x20, 0x01, 0x2D, 0x10, 0xD0,0xF8, 0xBD, 0x01, 0x2D, 0x0D, 0xD0, 0x04, 0x28, 0xFA, 0xD1, 0x14, 0x69, 0x44, 0xF0, 0x01, 0x04,0x14, 0x61, 0x31, 0x80, 0xD5, 0x68, 0x1C, 0x46, 0xEF, 0x07, 0x41, 0xF6, 0xFE, 0x75, 0x09, 0xD1,0x01, 0xE0, 0x05, 0x20, 0xF8, 0xBD, 0xD4, 0x68, 0x64, 0x07, 0x21, 0xD4, 0xD4, 0x68, 0xE4, 0x06,0x23, 0xD4, 0x13, 0xE0, 0xD7, 0x68, 0x04, 0x20, 0xFF, 0x07, 0x02, 0xD0, 0x64, 0x1E, 0xF9, 0xD1,0x2F, 0xE0, 0xD7, 0x68, 0x7F, 0x07, 0x01, 0xD5, 0x02, 0x20, 0x03, 0xE0, 0xD7, 0x68, 0xFF, 0x06,0x00, 0xD5, 0x03, 0x20, 0x01, 0x2C, 0x24, 0xD0, 0x04, 0x28, 0x23, 0xD1, 0xB6, 0x1C, 0x09, 0x0C,0x00, 0x96, 0x31, 0x80, 0xD1, 0x68, 0xC9, 0x07, 0x09, 0xD1, 0xD1, 0x68, 0x49, 0x07, 0x01, 0xD5,0x02, 0x20, 0x17, 0xE0, 0xD1, 0x68, 0xC9, 0x06, 0x14, 0xD5, 0x03, 0x20, 0x12, 0xE0, 0xD1, 0x68,0x04, 0x20, 0xC9, 0x07, 0x02, 0xD0, 0x5B, 0x1E, 0xF9, 0xD1, 0x0A, 0xE0, 0xD1, 0x68, 0x49, 0x07,0x01, 0xD5, 0x02, 0x20, 0x03, 0xE0, 0xD1, 0x68, 0xC9, 0x06, 0x00, 0xD5, 0x03, 0x20, 0x01, 0x2B,0x00, 0xD1, 0x05, 0x20, 0x11, 0x69, 0x29, 0x40, 0x11, 0x61, 0xF8, 0xBD, 0x00, 0x20, 0x02, 0x40,};typedef void (*flash_erase_handler)(uint32_t u32addr);
typedef void (*flash_write_handler)(uint32_t u32addr, uint32_t u32data);flash_erase_handler flash_erase = (flash_erase_handler)(flash_erase_buf + 1);
flash_write_handler flash_write = (flash_write_handler)(flash_write_buf + 1);#define Test_addr 0x08030000
函数地址为0x08020009,往前一位开始复制,186byte,得到擦除函数
此处数组+1是因为指令LSB即最低有效位为0时是ARM指令,为1时是Thumb代码,此处需要+1使其成为Thumb代码
同理,可得到写入函数。
运行擦除函数:
目的地址内容被擦除
运行写入函数:
可以看到写入值正常。
HexView提取指定地址内容并重映射
编辑bat脚本如下
.\HexTools\hexview.exe /G /s .\RVMDK\Output\Project.hex /AR:0x8020000-0x80201bf /xi:16 -o FlashDrv.hex /e:errorfile
.\HexTools\hexview.exe /G /s FlashDrv.hex /remap:0x8020000-0x80201bf,0x20001000,0x1c0,0x1c0 /xi:16 -o FlashDrv.hex /e:errorfile
使用/AR命令提取指定地址内容
使用/remap命令对地址进行remap,重映射地址为0x20001000,block大小为0x1c0
提取的flashdrv如下图所示:
总结
本文介绍了STM32F103 Flashdriver的制作过程,如果编译器有工具支持直接重映射到ram地址的话,就不需要后面hexview的步骤了,例如S32DS中就有。(keil中可能也有,后面如果研究出来了再补上)
若你觉得本文对你有帮助,欢迎点赞,关注,收藏,转发~~~ 你的鼓励是对小弟的最大支持~~~ 建了一个WX公众h,《汽车电子学习笔记》感兴趣可以关注一下~~~文章都会同步更新~
相关文章:

STM32F103制作FlashDriver
文章目录前言芯片内存定义实现过程FlashDriver生成段定义擦除函数写入函数编译后的map手动测试HexView提取指定地址内容并重映射总结前言 在汽车行业控制器软件刷新流程中,一般会将Flash驱动单独进行刷写,目的是防止程序中一直存在Flash驱动的话&#x…...

springboot树形结构接口, 懒加载实现
数据库关系有父子id的, 作为菜单栏展示时需要用前端需要用到懒加载, 所谓懒加载就是接口有一个标志位isLeaf, 前端请求后通过该字段判断该节点是否还有子节点数据 创建数据库表 t_company_info结构有id和parentId标识, 用来表示父子关系 /*Navicat Premium Data TransferSourc…...

java企业级信息系统开发学习笔记02初探spring——利用组件注解符精简spring配置文件
文章目录一、学习目标二、打开01的项目三、利用组件注解符精简spring配置文件(一)创建新包,复制四个类(二)修改杀龙任务类(三)修改救美任务类(四)修改勇敢骑士类…...

用Python发送电子邮件?这也太丝滑了吧(21)
小朋友们好,大朋友们好! 我是猫妹,一名爱上Python编程的小学生。 欢迎和猫妹一起,趣味学Python。 今日主题 猫爸赚钱养家,细想起来真的不容易啊! 起早贪黑,都是6点早起做早饭,送…...

分类预测 | MATLAB实现CNN-GRU-Attention多输入分类预测
分类预测 | MATLAB实现CNN-GRU-Attention多输入分类预测 目录分类预测 | MATLAB实现CNN-GRU-Attention多输入分类预测分类效果模型描述程序设计参考资料分类效果 模型描述 Matlab实现CNN-GRU-Attention多变量分类预测 1.data为数据集,格式为excel,12个输…...

C++提高编程(1)
C提高编程1.模板1.1模板的概念1.2函数模板1.2.1函数模板语法1.2.2函数模板注意事项1.2.3函数模板案例1.2.4普通函数与函数模板的区别1.2.5普通函数与函数模板的调用规则1.2.6模板的局限性1.3类模板1.3.1类模板语法1.3.2类模板和函数模板区别1.3.3类模板中成员函数创建时机1.3.4…...
day26 回溯算法的部分总结
回溯算法的部分总结 回溯算法是一种常用于解决排列组合问题、搜索问题的算法,它的基本思想是将问题的解空间转化为一棵树,通过深度优先搜索的方式遍历树上的所有节点,找到符合条件的解。回溯算法通常使用递归实现,每次递归时传入…...

带你玩转Python爬虫(胆小者勿进)千万别做坏事·······
这节课很危险,哈哈哈哈,逗你们玩的 目录 写在前面 1 了解robots.txt 1.1 基础理解 1.2 使用robots.txt 2 Cookie 2.1 两种cookie处理方式 3 常用爬虫方法 3.1 bs4 3.1.1 基础介绍 3.1.2 bs4使用 3.1.2 使用例子 3.2 xpath 3.2.1 xpath基础介…...

【JavaScript 】严格模式,With关键字,测试框架介绍,assert
❤️ Author: 老九 ☕️ 个人博客:老九的CSDN博客 🙏 个人名言:不可控之事 乐观面对 😍 系列专栏: 文章目录静态类型语言弱类型严格模式将过失错误转化为异常简化变量的使用With测试框架try-catch选择性捕获…...
mybatis实现一个简单的CRUD功能的小案例(后端)编写流程
下面是一个使用mybatis实现增删改查功能的示例程序: 1.创建一个数据库 首先需要创建一个名为test_db的数据库,里面包含一个名为user_info的表,其中包含id、name、age三个字段。 2.配置mybatis 在项目的pom.xml文件中添加mybatis和mysql依…...

腾讯云轻量应用服务器价格表(2023版)
2023腾讯云轻量应用服务器2核2G4M带宽88元一年、2核4G6M带宽159元/年、4核8G10M优惠价425元、8核16G14M价格1249、16核32G20M服务器2499元一年,今天分享2023腾讯云服务器配置及精准报价。 腾讯云轻量应用服务器优惠价格表 腾讯云服务器分为轻量应用服务器和云服务器…...

网络层IP协议和数据链路层
目录IP协议协议头格式分片网段划分特殊的IP地址IP地址的数量限制NAT技术NAT技术背景NAT IP转换过程NAPTNAT技术的缺陷NAT和代理服务器私有IP地址和公网IP地址路由路由表生成算法数据链路层认识以太网以太网帧格式认识MAC地址对比理解MAC地址和IP地址认识MTUMTU对IP协议的影响MT…...
零基础学习Java 03
目录 数组 动态初始化数组 静态初始化 数组的应用 数组两种典型的异常 length关键字求出数组的长度 数组遍历在IDEA中输出快捷语句 对象数组 数组的遍历:foreach方法 二维数组 枚举(enum) 数组 1在方法中可以返回一个数组,但是在定义方法时类型要…...
PG数据库超时退出 TCP设定
数据库在使用psql工具以及jdbc进行远程连接时,在经过一定时间之后报错-致命错误: terminating connection due to client no input timeout。 排查安全参数,hg_clientnoinput 0; 问题原因 操作系统TCP相关参数设置不正确&…...

每日学术速递4.4
CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CL 1.Baize: An Open-Source Chat Model with Parameter-Efficient Tuning on Self-Chat Data 标题:Baize:一种对自聊天数据进行参数高效调优的开源聊天模型 作者…...

ChatGPT将引发大量而普遍的网络安全隐患
ChatGPT是一个基于人工智能的语言生成模型,它可以在任何给定的时间,使用自然语言生成技术,生成文本、对话和文章。它不仅可以被用来编写文本,还可以用来编写语言、生成图像和视频。目前, ChatGPT已广泛应用于语言翻译、…...

购买学生护眼台灯几瓦最好?有哪些推荐护眼灯
现今的近视已然成为普遍现象,而且有往低年龄段发展的趋势。究其原因,长期使用电子设备是一方面,还是就是我们日常工作、学习、生活没有很好的护眼环境,很多时候我们不经意的错误习惯,久而久之就有可能诱发近视。对孩子…...

什么是 SYN 攻击?如何避免 SYN 攻击?
SYN 攻击方式最直接的表现就会把 TCP 半连接队列打满,这样当 TCP 半连接队列满了,后续再在收到 SYN 报文就会丢弃,导致客户端无法和服务端建立连接。 避免 SYN 攻击方式,可以有以下四种方法: 调大 netdev_max_backlo…...
数据分析练习——学习一般分析步骤
目录 一、准备工作 二、导入库和数据 1、导入必要的库: 2、模拟数据 三、数据分析过程 1、读取数据: 2、数据概览和描述性统计: 2.1、查看数据概览: 2.2、查看描述性统计: 3、数据清洗: 3.1、处…...
Linux环境下挂载exfat格式U盘,以及安装exfat文件系统
目录Linux一般支持的文件系统有:1.安装exfat软件安装工具环境以及exfat件依赖的系统软件下载exfat源码包并安装2.挂载exfat格式U盘查看U盘在那个目录执行挂载命令Linux一般支持的文件系统有: 文件系统名称详情ext专门为Linux核心做的第一个文件系统&…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...

前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...