当前位置: 首页 > news >正文

单片机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 TypeFLASH_BASE_ADDR,            // Device Start Address0x01000000,                 // Device Size in Bytes (256kB)  2M4096,                       // Programming Page Size 0,                          // Reserved, must be 00xFF,                       // Initial Content of Erased Memory3000,                       // Program Page Timeout 3000 mSec3000,                       // Erase Sector Timeout 3000 mSec// Specify Size and Address of Sectors0x001000, 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_regionER_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_regionER_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_regionER_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中存储的代码如何执行下一篇文章介绍。

相关文章:

单片机FLASH下载算法的制作

环境 硬件使用正点原子STM32F407探索者V2开发板 编程环境使用MDK 下载工具使用JLINK FLASH芯片使用W25Q128 什么是下载算法 单片机FLASH的下载算法是一个FLM文件&#xff0c;FLM通过编译链接得到&#xff0c;其内部包含一系列对FLASH的操作&#xff0c;包括初始化、擦除、写…...

[nlp] 损失缩放(Loss Scaling)loss sacle

在深度学习中,由于浮点数的精度限制,当模型参数非常大时,会出现数值溢出的问题,这可能会导致模型训练不稳定。为了解决这个问题,损失缩放(Loss Scaling)技术被引入,它通过缩放损失值来解决这个问题。 在深度学习中,损失缩放技术通常是通过将梯度进行缩放来实现的。具…...

Django框架之视图层

【一】三板斧 【1】HttpResponse 返回字符串类型 【2】render 返回html页面&#xff0c;并且在返回给浏览器之前还可以给html页面传值 【3】redirect 重定向页面 在视图文件中写视图函数的时候不能没有返回值了&#xff0c;默认返回的是None&#xff0c;页面上就会报错 d…...

商城免费搭建之java商城 java电子商务Spring Cloud+Spring Boot+mybatis+MQ+VR全景+b2b2c

1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis 3. 前端框架…...

AI机器学习实战 | 使用 Python 和 scikit-learn 库进行情感分析

专栏集锦&#xff0c;大佬们可以收藏以备不时之需 Spring Cloud实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏&#xff1a;https:/…...

CANoe-Logging模块如何抓取总线数据

在CANoe测量期间(CANoe运行时),总线数据经由Measurement Setup界面的各分析模块的输入口流入Trace、Graphics、Data等窗口中,或统计、或显示、或分析。总线数据除了能流入分析窗口中做解析外,还可以保存到log文件中,留作其他人分析或复现的文件。 在Measurement Setup界…...

Unity中Shader的矩阵加减法

文章目录 前言一、什么是矩阵矩阵就是一组数的阵列 二、矩阵的加法三、矩阵的负值四、矩阵的减法五、矩阵的表示 前言 Unity中Shader用到的矩阵加减法&#xff0c;以及矩阵的一些基础常识 一、什么是矩阵 矩阵就是一组数的阵列 1 2 3 4 5 6 二、矩阵的加法 两个矩阵相加就是…...

IIC总线概述和通信时序代码详细图文解析

IIC总线 1 IIC总线概述 I2C总线两线制包括&#xff1a;串行数据SDA&#xff08;Serial Data&#xff09;、串行时钟SCL&#xff08;Serial Clock&#xff09;。总线必须由主机&#xff08;通常为微控制器&#xff09;控制&#xff0c;主机产生串行时钟&#xff08;SCL&#x…...

EtherCAT 伺服控制功能块实现

EtherCAT 是运动控制领域主要的通信协议&#xff0c;开源EtherCAT 主站协议栈 IgH 和SOEM 两个项目&#xff0c;IgH 相对更普及一些&#xff0c;但是它是基于Linux 内核的方式&#xff0c;比SOEM更复杂一些。使用IgH 协议栈编写一个应用程序&#xff0c;控制EtherCAT 伺服电机驱…...

如何基于OpenCV和Sklearn算法库开展机器学习算法研究

大家在做机器学习或深度学习研究过程中&#xff0c;不可避免都会涉及到对各种算法的研究使用&#xff0c;目前比较有名的机器学习算法库主要有OpenCV和Scikit-learn&#xff08;简称Sklearn&#xff09;&#xff0c;二者都支持各种机器学习算法&#xff0c;主要有监督学习、无监…...

在 Node.js 中发出 HTTP 请求的 5 种方法

在 Node.js 中发出 HTTP 请求的 5 种方法 学习如何在 Node.js 中发出 HTTP 请求可能会让人感到不知所措&#xff0c;因为有数十个可用的库&#xff0c;每个解决方案都声称比上一个更高效。一些库提供跨平台支持&#xff0c;而另一些库则关注捆绑包大小或开发人员体验。 在这篇…...

pipeline agent分布式构建

开启 agent rootjenkins:~/learning-jenkins-cicd/07-jenkins-agents# docker-compose -f docker-compose-inbound-agent.yml up -d Jenkins配置添加 pipeline { agent { label docker-jnlp-agent }parameters {booleanParam(name:pushImage, defaultValue: true, descript…...

MySQL(17):触发器

概述 MySQL从 5.0.2 版本开始支持触发器。MySQL的触发器和存储过程一样&#xff0c;都是嵌入到MySQL服务器的一段程序。 触发器是由 事件来触发 某个操作&#xff0c;这些事件包括 INSERT 、 UPDATE 、 DELETE 事件。 所谓事件就是指用户的动作或者触发某项行为。 如果定义了触…...

挖掘PostgreSQL事务的“中间态”----更加严谨的数据一致性?

1.问题 今天在上班途中&#xff0c;中心的妹纸突然找我&#xff0c;非常温柔的找我帮忙看个数据库的报错。当然以我的性格&#xff0c;妹子找我的事情对我来说优先级肯定是最高的&#xff0c;所以立马放下手中的“小事”&#xff0c;转身向妹子走去。具体是一个什么样的问题呢…...

多种方法实现conda环境迁移

Conda 为包管理器和虚拟环境管理器。在配置完项目环境&#xff0c;进行了编写和测试代码&#xff0c;需要大量数据测试运行时&#xff0c;需要将其移至另一台主机上。Conda 提供了多种保存和移动环境的方法。 方法1&#xff1a; scp拷贝法&#xff0c;直接将envs的环境文件夹…...

C++ string类(一)

1.C语言中的字符串 C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符 OOP(Object Oriented Programming)的思想&#xff0c;而且…...

系统时间和JVM的Date时间不一致问题解决

通过Java得到的时间与操作系统时间不一致&#xff0c;如何修改Java虚拟机时间&#xff1f; 造成这种问题的原因可能是&#xff1a;你的操作系统时区跟你JVM的时区不一致。 你的操作系统应该是中国的时区吧&#xff0c;而JVM的时区不一定是中国时区&#xff0c;你在应用服务器…...

23111701[含文档+PPT+源码等]计算机毕业设计javaweb点餐系统全套餐饮就餐订餐餐厅

文章目录 **项目功能简介:****点餐系统分为前台和后台****前台功能介绍&#xff1a;****后台功能介绍&#xff1a;** **论文截图&#xff1a;****实现&#xff1a;****代码片段&#xff1a;** 编程技术交流、源码分享、模板分享、网课教程 &#x1f427;裙&#xff1a;77687156…...

RabbitMQ 部署及配置详解(集群部署)

单机部署请移步&#xff1a; RabbitMQ 部署及配置详解 (单机) RabbitMQ 集群是一个或 多个节点&#xff0c;每个节点共享用户、虚拟主机、 队列、交换、绑定、运行时参数和其他分布式状态。 一、RabbitMQ 集群可以通过多种方式形成&#xff1a; 通过在配置文件中列出群集节点以…...

基于蝠鲼觅食算法优化概率神经网络PNN的分类预测 - 附代码

基于蝠鲼觅食算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于蝠鲼觅食算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于蝠鲼觅食优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...