单片机FLASH下载算法的制作

环境

硬件使用正点原子STM32F407探索者V2开发板
编程环境使用MDK
下载工具使用JLINK
FLASH芯片使用W25Q128

什么是下载算法

单片机FLASH的下载算法是一个FLM文件,FLM通过编译链接得到,其内部包含一系列对FLASH的操作,包括初始化、擦除、写、读、校验等等操作。

单片机固件下载流程

想要制作下载算法,先要了解下载算法的工作原理。我们下载一个程序的流程大概是这样的:下载工具(比如jlink)先读取FLM文件,然后JLINK提取FLM文件的信息,将其传输到单片机的内部SRAM,下载算法在开始SRAM中运行,由于下载算法包含了一系列对FLASH的操作,那么下载工具通过下发初始化、擦除、写入、校验等指令给单片机,单片机去执行这些指令操作,实现对单片机FLASH的下载。

下载算法FLM文件的制作步骤

首先需要准备一份FLASH的驱动代码,能实现初始化、擦除,读,写等功能。

  1. 从MDK安装目录下拷贝一份下载算法工程,路径:MDK\ARM\PACK\ARM\CMSIS\5.4.0\Device_Template_Flash,使用的MDK版本不一样路径可能不一样。此时我们得到了一份空的下载算法工程。
  2. 取消工程的只读属性。
  3. 给工程添加分组,将Flash驱动代码和用到的库函数添加到对应的分组,和普通工程一样,根据模块添加即可。在这里插入图片描述
  4. 添加头文件路径,把头文件的路径都包含进来。
  5. 给C/C++选项卡添加宏STM32F40_41xxx,USE_STDPERIPH_DRIVER。
  6. Device选项卡选择单片机型号。Target选项卡勾选微库。
  7. 在FlashDev.c文件中根据实际Flash属性修改FlashDevice结构体变量。
  8. 将target选项卡中的输出文件名字改成FlashDevice结构体Device Name成员中的设备名字,这一步不是必须的,只是为了输出的FLM文件名称和设备名称一致。
  9. 在FlashPrg.c文件中根据模板添加Flash操作的相关代码。
  10. 编译得到一个FLM文件。

其实上边看似繁琐,实则只有修改FlashDevice结构体变量和修改FlashPrg.c文件是我们新接触的,其它步骤在平时单片机编程中已经再熟悉不过了。接下来我们重点分析这两点。

修改FlashDevice结构体变量的值

struct FlashDevice const FlashDevice  =  {
   FLASH_DRV_VERS,             // Driver Version, do not modify!
   "W25Q128_16M_FLM",   // Device Name 
   EXTSPI,                     // Device Type
   FLASH_BASE_ADDR,            // Device Start Address
   0x01000000,                 // Device Size in Bytes (256kB)  2M
   4096,                       // Programming Page Size 
   0,                          // Reserved, must be 0
   0xFF,                       // Initial Content of Erased Memory
   3000,                       // Program Page Timeout 3000 mSec
   3000,                       // Erase Sector Timeout 3000 mSec

// Specify Size and Address of Sectors
   0x001000, 0x000000,         // Sector Size  8kB (8 Sectors)
   SECTOR_END
};

其实每一个成员的作用注释已经解释的很清楚了,注意这里把页编程大小改成了4096个字节,不是W25Q128指定的256个字节,这不是必须要改的,修改成4096只是为了提高下载效率。我实测把4096改成8,下载速度非常明显的变慢。
第四个实参使用了一个宏FLASH_BASE_ADDR来初始化的,我这里对FLASH_BASE_ADDR定义的是0x00000000,就以SPI FLASH为例,FLASH的存储空间是从0开始的,为什么我没有固定写0而是写了一个宏定义呢?这在我们验证下载算法的时候介绍。
器件大小、扇区大小、扇区擦除超时时间、页编程超时时间些都根据实际FLASH芯片参数填写即可。

添加FLASH接口代码到FlashPrg.c文件

在FlashPrg.c文件中有InitUnInitEraseChipEraseSectorProgramPageVerify这些函数,每个函数的功能一目了然。函数实现如下:

int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {
	SystemInit();//系统初始化
	W25QXX_Init();//初始化W25QXX芯片
  return (0);                                  // Finished without Errors
}
int UnInit (unsigned long fnc) {
  return (0);                                  // Finished without Errors
}
int EraseChip (void) {
	for(int i=0;i<4096;i++)//我用的是W25Q128
	{
		W25QXX_Erase_Sector(i);//注意这里参数是扇区的编号
	}
  return (0);                                  // Finished without Errors
}
int EraseSector (unsigned long adr) {

	uint32_t sector = 0;//扇区编号
	adr -= FLASH_BASE_ADDR; 
	sector = adr /4096;//扇区的大小是4096 计算出了扇区的编号
	W25QXX_Erase_Sector(sector);
  return (0);                                  // Finished without Errors
}
int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {
	adr -= FLASH_BASE_ADDR; 
	W25QXX_Write_NoCheck(buf,adr,sz);
  return (0);                                  // Finished without Errors
}
uint8_t read_buf[4096];
unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf) {
	unsigned long remain = sz;	//剩余的字节数
	unsigned long current_add = 0;//当前的地址
	unsigned int index = 0;//用于buf的索引
	current_add = adr - FLASH_BASE_ADDR;
	
	while(remain >= 4096)
	{
		W25QXX_Read(read_buf,current_add,4096);
		for(int i=0;i<4096;i++)
		{
			if(read_buf[i] != buf[index+i])
				return adr+index+i;
		}
		current_add += 4096;
		remain -= 4096;
		index += 4096;
	}
	W25QXX_Read(read_buf,current_add,remain);
	for(int i=0;i<remain;i++)
	{
		if(read_buf[i] != buf[index+i])
			return adr+index+i;
	}
	return (adr+sz);                      // 校验成功
}

编译我们就能得到一个.FLM文件。

验证测试下载算法

这里我们只验证下载算法的功能,测试是否能正常下载,至于下载进去以后如何运行代码,这里不讨论,留在下一章介绍,因为涉及到链接脚本、拷贝、跳转、等等操作。
把该文件放在\MDK\ARM\Flash路径下,随便打开一个工程,添加下载算法在这里插入图片描述
编译下载,发现报错,如下图:
在这里插入图片描述
报错原因是下载算法没有找到08000000H这个地址,我这里使用的是默认的链接脚本:

LR_IROM1 0x08000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

下载算法文件里定义的FLASH起始地址是0x00000000,大小是0x01000000,那么下载算法的空间就是0x00000000~0x00FFFFFF。这里加载地址是0x08000000,就是要往0x08000000开始的地址写入数据。这样一来,很显然下载算法判断出了非法地址就报错了。
既然这个加载地址报错,那就把加载地址改成0x00000000,如下:

LR_IROM1 0x00000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x0800000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

这总合法了吧,但遗憾的是编译报错,报错的原因是程序里调用了__main函数,__main函数中不能被链接到非启动区域,也就是加载地址和链接地址不一样。这里不讨论报错的原因和应对措施。其实有很多种解决方法。我暂时将链接地址也改成0x00000000如下图:

LR_IROM1 0x00000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x0000000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

编译下载,下载成功。
在这里插入图片描述
下载成功了,我用一个SPI FLASH demo程序把FLASH0地址开始的数据读出来,打印出来:
在这里插入图片描述
在把我们烧写进去的固件对应的bin文件打开,对比一下。
在这里插入图片描述
可以看到是完全一样的。
证明制作的下载算法是没问题的。FLASH中存储的代码如何执行下一篇文章介绍。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

delphi电子处方流转(药店)

【delphi电子处方流转(药店)】支持 处方下载、处方核验、处方审核、药品销售出库明细上传、药品销售出库明细撤销等功能。

【Java 语言】读取 properties 配置文件 ( Java 语言中的 properties 配置文件 | 使用 properties 配置文件 )

文章目录 一、Java 语言中的 properties 配置文件二、使用 properties 配置文件三、完整代码示例1、Java 代码2、properties 配置文件3、执行结果 一、Java 语言中的 properties 配置文件 Java 语言中 , properties 配置文件 是一种用于存储应用程序配置信息的文本文件 ; prop…

腾讯云服务器多少钱一年?腾讯云服务器88元一年,附优惠购买入口

腾讯云服务器可以以低至88元一年的价格购买&#xff01;这个价格可以说是非常实惠。现在&#xff0c;让我们一起来了解腾讯云服务器的价格以及如何购买优惠的服务器。 如何购买88元一年的腾讯云服务器&#xff1f; 购买腾讯云服务器非常简单&#xff0c;只需按照以下步骤&…

Odoo 15开发手册第四章 模块继承

Odoo 的一项强大之处是无需直接修改所扩展模块的代码即可添加功能。这都归功于与自身代码组件相独立的功能继承。对模块的扩展可通过继承机制实现&#xff0c;以已有对象的修改层的形式。这些修改可以发生在每个层面&#xff0c;包括模型、视图和业务逻辑层面。我们不是直接修改…

idea查看UML类图

idea查看UML类图 一、如何查看UML类图 1.1 选择需要查看的类或者包&#xff0c;鼠标右键&#xff0c;选择Diagrams->Show Diagram 1.2 对于UML类图中的包&#xff0c;选中后点击鼠标右键-> Expand Nodes(展开节点) 展开前 展开后 1.3 展开后分布比较凌乱&#xff…

Axure基础详解二十二:随机点名效果

效果演示 组件 建立一个【中继器】&#xff0c;内部插入一个“文本框”。【中继器】每页项目数为1&#xff0c;开始页为1。 设置交互 页面载入时交互 给【中继器】新曾行&#xff0c;“name”数据列添加10行数据&#xff0c;填入相应的名字&#xff1b;“shunxu”数据列全部…

GLSL: Shader cannot be patched for instancing.

最近在 unity 里碰到了这么一个错误&#xff0c;只有这么点信息&#xff0c;让人看着挺懵逼的&#xff0c;后来发现&#xff0c;是因为 unity 的 terrain 组件在设置里勾了 Draw Instanced 选项导致的&#xff0c;感觉应该是 unity 的 bug。 因为错出在 2021&#xff0c;2022就…

ZYNQ_project:test_fifo_255X8

首先&#xff0c;这个vivado的fifo和quartus有很大不同。 用BRAM来实现异步fifo。 vivado的fifo有复位&#xff0c;在时钟信号稳定后&#xff0c;复位至少三个时钟周期&#xff08;读写端口的慢时钟&#xff09;&#xff0c;复位完成后30个时钟周期后再进行写操作&#xff08…

网络安全-黑客技术(自学笔记)

前言 前几天发布了一篇 网络安全&#xff08;黑客&#xff09;自学 没想到收到了许多人的私信想要学习网安黑客技术&#xff01;却不知道从哪里开始学起&#xff01;怎么学 今天给大家分享一下&#xff0c;很多人上来就说想学习黑客&#xff0c;但是连方向都没搞清楚就开始学习…

python基于DETR(DEtection TRansformer)开发构建人员手持物品检测识别分析系统

PyTorch训练代码和DETR&#xff08;DEDetection-TRansformer&#xff09;的预训练模型。我们用Transformer替换了完全复杂的手工制作的对象检测管道&#xff0c;并将Faster R-CNN与ResNet-50匹配&#xff0c;使用一半的计算能力&#xff08;FLOP&#xff09;和相同数量的参数在…

vue3路由

vue3路由总结 vue3路由安装和引入&#xff1a;路由配置、创建 Router 实例&#xff1a;导航守卫 使用路由返回上一个页面没有跳转指定页 vue3路由 Vue3 路由是 Vue.js 3.x 版本中用于管理页面跳转和导航的模块。它基于 Vue Router 4.x&#xff0c;相较于 Vue2 的路由机制&…

来讲解一手事务隔离级别

简介 在数据库管理系统中&#xff0c;事务是一组被视为单一工作单元的操作&#xff0c;这些操作要么全部执行成功&#xff0c;要么全部回滚。为了确保在多用户并发访问数据库时数据的一致性和可靠性&#xff0c;引入了事务隔离级别的概念。事务隔离级别定义了一个事务对于其他…

餐厅订座预约小程序的效果如何

市场中无论哪种城市&#xff0c;餐厅非常多&#xff0c;一条不长的商业街&#xff0c;汇聚着数家餐饮品牌&#xff0c;且相互间竞争激烈&#xff0c;并且各个商家都希望用成本低高效率的方法引流及转化。 随着互联网深入各个行业&#xff0c;传统餐饮行业经营痛点不少。 传统餐…

(Matalb回归预测)WOA-BP鲸鱼算法优化BP神经网络的多维回归预测

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、部分代码&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matalb平台编译&#xff0c;将WOA(鲸鱼算法)与BP神…

代码随想录算法训练营第五十五天 | LeetCode 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结

代码随想录算法训练营第五十五天 | LeetCode 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结 文章链接&#xff1a;两个字符串的删除操作、编辑距离、编辑距离总结 视频链接&#xff1a;两个字符串的删除操作、编辑距离 1. LeetCode 583. 两个字符串的删除操作 1.1 思…

YOLOv8环境搭建

YOLOv8环境搭建 torch环境安装requestment.txt文件中的包安装ultralytics调用 torch环境 使用的是python3.9版本 pip install torch-2.1.0cu118-cp39-cp39-linux_x86_64.whl torchvision0.16.0 torchaudio2.1.0 --index-url https://download.pytorch.org/whl/cu118安装reques…

GUI编程--PyQt5--QTreeWidget

文章目录 树型控件展示数据修改节点数据获取所有节点的数据 Qt模组参考 QWidgets QTreeWidget 树型控件展示数据 展示数据的同时&#xff0c;每个节点标注数据类型。 class MyWindow(QWidget):def __init__(self, title):super(MyWindow, self).__init__()self.setWindowTitl…

【SpringBoot篇】分页查询 | 扩展SpringMvc的消息转换器

文章目录 &#x1f6f8;什么是分页查询&#x1f339;代码实现⭐问题&#x1f384;解决方法 做了几个项目&#xff0c;发现在这几个项目里面&#xff0c;都实现了分页查询效果&#xff0c;所以就总结一下&#xff0c;方便学习 我们基于黑马程序员的苍穹外卖来讲解分页查询的要点…

el-table中el-popover失效问题

场景&#xff1a;先有一个数据表格&#xff0c;右侧操作栏为固定列&#xff0c;另外有一个字段使用了el-popover来点击弹出框来修改值&#xff0c;发现不好用&#xff0c;点击后无法显示弹出框&#xff0c;但当没有操作栏权限时却意外的生效了。 这种问题真是不常见&#xff0…

【蓝桥杯 第十五届模拟赛 Java B组】训练题(A - I)

目录 A、求全是字母的最小十六进制数 B、Excel表格组合 C、求满足条件的日期 D、 取数字 - 二分 &#xff08;1&#xff09;暴力 &#xff08;2&#xff09;二分 E、最大连通块 - bfs F、哪一天&#xff1f; G、信号覆盖 - bfs &#xff08;1&#xff09;bfs&#xf…