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

基于 STM32F407 的 SPI Flash下载算法

目录

  • 一、概述
  • 二、自制 FLM 文件
    • 1、修改使用的芯片
    • 2、修改输出算法的名称
    • 3、其它设置
    • 4、修改配置文件 FlashDev.c
    • 5、文件 FlashPrg.c 的实现
  • 三、验证算法


一、概述

本文将介绍如何使用 MDK 创建 STM32F407SPI Flash 下载算法。

其中,SPI Flash 芯片使用的是 W25Q128,其相关操作源码可以参考 STM32 通过 SPI 驱动 W25Q128,本文所使用的驱动 SPI Flash 的 API 和里面是一样的。

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

想要制作下载算法,先要了解下载算法的工作原理。我们下载一个程序的流程大概是这样的:

  1. 下载工具(比如 jlink)读取 FLM 文件
  2. 然后 JLINK 提取 FLM 文件的信息,将其传输到单片机的内部 SRAM
  3. 下载算法开始在 SRAM 中运行,由于下载算法包含了一系列对 Flash 的操作,那么下载工具通过下发初始化、擦除、写入、校验等指令给单片机,单片机去执行这些指令操作,实现对单片机 Flash 的下载。

二、自制 FLM 文件

我参照的是 MDK 给的程序模板来完成 Flash 下载程序,然后在模板的基础上加上自己的代码。

模板路径如下:D:\Keil_v5\ARM\Packs\ARM\CMSIS\5.8.0\Device\_Template_Flash,不同的 MDK 版本可能路径不一样。

然后将项目拷贝到你的工作目录下,并取消该工程项目的只读属性。

打开项目如下:

然后开始我们的工作。

1、修改使用的芯片

首先选择你的芯片类型和型号。

2、修改输出算法的名称

这一步不是必须的,改个名称方便自己查看。

注意这个名称只是项目最终生成输出的 FLM 文件的名称,和下面位置识别出的算法名(后面会介绍这个名称如何修改)无关。


3、其它设置

注意

这里的设置在模板文件中已经设置好了,这里主要是介绍一些,可以跳过


这两个设置是为了保证生成的算法文件中 RO 和 RW 段的独立性,即与地址无关。

如果程序的所有只读段都与位置无关,则该程序为只读位置无关(ROPIRead-only position independence)。ROPI 段通常是位置无关代码(PICposition-independent code),但可以是只读数据,也可以是 PIC 和只读数据的组合。选择“ ROPI”选项,可以避免用户不得不将代码加载到内存中的特定位置。这对于以下例程特别有用:

  • 加载以响应运行事件。
  • 在不同情况下使用其他例程的不同组合加载到内存中。
  • 在执行期间映射到不同的地址。

使用 Read-Write position independence 同理,表示的可读可写数据段。

通过下面的命令就可以将生成的 axf 可执行文件修改为 FLM

我们这里的分散加载文件直接使用 MDK 模板工程里提供好的即可,无需任何修改。

4、修改配置文件 FlashDev.c

模板工程里面提供简单的配置说明:

struct FlashDevice const FlashDevice  =  {FLASH_DRV_VERS,             // Driver Version, do not modify!"New Device 256kB Flash",   // Device Name ONCHIP,                     // Device Type0x00000000,                 // Device Start Address0x00040000,                 // Device Size in Bytes (256kB)1024,                       // Programming Page Size0,                          // Reserved, must be 00xFF,                       // Initial Content of Erased Memory100,                        // Program Page Timeout 100 mSec3000,                       // Erase Sector Timeout 3000 mSec// Specify Size and Address of Sectors0x002000, 0x000000,         // Sector Size  8kB (8 Sectors)0x010000, 0x010000,         // Sector Size 64kB (2 Sectors) 0x002000, 0x030000,         // Sector Size  8kB (8 Sectors)SECTOR_END
};

这里的注释已经说得很明白了,大家根据自己的芯片来进行修改即可,我使用的是 W25Q128,其存储大小为 16MB,一个扇区 4KB,所以修改如下:

W25Q128 一页是 256KB,但这里写的 4096 是为了提高下载速率和擦除速率,如果你把 4096 改为 8,可以很明显得感受到下载速度变慢了

struct FlashDevice const FlashDevice  =  {FLASH_DRV_VERS,                  /* 驱动算法,由 MDK 制定,勿动 */"Yux_STM32F407VE_SPI_W25Q128",   /* 算法名称 */ EXTSPI,                          /* 设备类型,外扩展 SPI-Flash */SPI_FLASH_MEM_ADDR,              /* Flash 起始地址 */0x01000000,                      /* Flash 大小,16MB */4096,                            /* 编程页大小 */0,                               /* 保留,必须为 0 */0xFF,                            /* 擦除后的数值 */3000,                            /* 页编程等待时间 */3000,                            /* 扇区擦除等待时间 */0x001000, 0x000000,              /* 扇区大小,扇区地址 */SECTOR_END
};

其中,SPI_FLASH_MEM_ADDR 是我在 FlashOS.h 文件中定义的一个宏,表示 Flash 的起始地址:

#define SPI_FLASH_MEM_ADDR     0x00000000

这里的算法名称就体现在这里:

5、文件 FlashPrg.c 的实现

模板文件中提供了这几个函数,也是我们完成 Flash 下载算法最关键的地方:

// Flash 初始化
int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {/* Add your Code */return (0);                                  // Finished without Errors
}// Flash 复位
int UnInit (unsigned long fnc) {/* Add your Code */return (0);                                  // Finished without Errors
}// 擦除整个 Flah 芯片
int EraseChip (void) {/* Add your Code */return (0);                                  // Finished without Errors
}// 擦除指定扇区
int EraseSector (unsigned long adr) {/* Add your Code */return (0);                                  // Finished without Errors
}// 页编程
int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {/* Add your Code */return (0);                                  // Finished without Errors
}// 校验
unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf)
{/* Add your Code */return (0);                                  // Finished without Errors
}

这里涉及到了对 W25Q128 的相关操作,详细内容参照: STM32 通过 SPI 驱动 W25Q128,这里主要是调用之前实现的函数。

我使用的是标准库,所以还要添加一些相关的文件进来:

实现如下:

  • 初始化函数
int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {SystemInit();   // 初始化系统和时钟w25qxx_init();  // 初始化 w25q128 /* Add your Code */return (0);                                  // Finished without Errors
}

这里的 SystemInitsystem_stm32f4xx.c 中的函数,在 STM32 时钟树(基于 STM32F407) 一文中讨论过。

  • 复位函数

Uninit 没有用到,所以不用改。

  • 擦除整个芯片
int EraseChip (void) {w25qxx_erase_chip();/* Add your Code */return (0);                                  // Finished without Errors
}
  • 擦除指定扇区
int EraseSector (unsigned long adr) {uint32_t sector = 0;adr -= SPI_FLASH_MEM_ADDR;sector = adr / 4096;w25qxx_erase_sector(sector);/* Add your Code */return (0);                                  // Finished without Errors
}
  • 页编程
int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {adr -= SPI_FLASH_MEM_ADDR;w25qxx_write(buf, adr, sz);/* Add your Code */return (0);                                  // Finished without Errors
}
  • 校验
unsigned char aux_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 - 0xC0000000;while(remain >= 4096){w25qxx_read(aux_buf, current_add, 4096);for(int i = 0; i < 4096; i++){if(aux_buf[i] != buf[index+i])return adr+index+i;}current_add += 4096;remain -= 4096;index += 4096;}w25qxx_read(aux_buf, current_add, remain);for(int i = 0; i < remain; i++){if(aux_buf[i] != buf[index+i])return adr + index + i;}return (adr + sz);                      // 校验成功
}

为什么要 adr -= SPI_FLASH_MEM_ADDR;

因为实际传递进来的地址是带了首地址的,即 0x00000000(如果你定义的是其它地址,而不执行 adr -= SPI_FLASH_MEM_ADDR; 就会出错)。特别注意,我们这里的 0xC0000000 是随意设置的,因为 STM32F4 的标准 SPI 外设并不支持内存映射。

这里执行的擦除大小要前面 FlashDev.c 文件中配置的扇区大小一致,这里是执行的 4KB 为扇区进行擦除。

现在编译之后就可以在项目目录下看见一个 FLM 文件。下面就来验证一下我们的下载算法是否正确。

三、验证算法

首先把我们的 FLM 文件放到如下目录中:D:\Keil_v5\ARM\Flash,可以看到这里有很多 FLM 和 FLX 文件。

这里我随便找了一个项目,按如下方式添加自己的 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)}
}

有关链接脚本的部分可以参考:
浅析 Keil 中的 sct 文件,
分散加载文件 scatter files。

这部分的内容比较复杂,我就直接给出解决方案了:

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)}
}

这下编译成功了。但至于写没写入并不清楚,写没写对也不知道。所以我又写了个 W25Q128 的读取程序:

	w25q32_dev.rd(data, 0x00000000, sizeof(data));for (int i = 0; i < sizeof(data); ++i){printf("%2x ", data[i]);if ( (i + 1) % 16 == 0 )printf("\r\n");}

话不多说,看结果(比较的是 bin 文件):

说明算法编写成功 (^人^)。

相关文章:

基于 STM32F407 的 SPI Flash下载算法

目录 一、概述二、自制 FLM 文件1、修改使用的芯片2、修改输出算法的名称3、其它设置4、修改配置文件 FlashDev.c5、文件 FlashPrg.c 的实现 三、验证算法 一、概述 本文将介绍如何使用 MDK 创建 STM32F407 的 SPI Flash 下载算法。 其中&#xff0c;SPI Flash 芯片使用的是 W…...

力扣之1355.活动参与者

题目&#xff1a; Sql 测试用例&#xff1a; Create table If Not Exists Friends (id int, name varchar(30), activity varchar(30)); Create table If Not Exists Activities (id int, name varchar(30)); Truncate table Friends; insert into Friends (id, name, acti…...

数据资产治理:构建敏捷与安全的数据管理体系

在当今数字化的盛况下&#xff0c;作为核心资产的数据已经越发受到企业的重视。但是随着公司的逐步壮大&#xff0c;如何分析这些数据以及如何有效治理数据资产&#xff0c;以确保安全性、合规性以及易用性&#xff0c;是企业面临的重大挑战。数聚股份将从多年从业经验深度探讨…...

Nodejs连接Mysql笔记

框架搭建 安装Node.js 首先&#xff0c;确保你已经在系统上安装了Node.js和npm&#xff08;Node Packaged Modules&#xff09;。你可以通过以下命令检查是否已经安装&#xff1a;shell 或者 node -v 或者 npm -v 数据库连接代码 1.导入MySQL2库 npm install mysql2 2.在文件…...

Canvas:AI协作的新维度

在人工智能的浪潮中&#xff0c;OpenAI的最新力作Canvas&#xff0c;不仅是一款新工具&#xff0c;它标志着人工智能协作方式的一次革命性飞跃。Canvas为写作和编程提供了一个全新的交互界面&#xff0c;让用户能够与ChatGPT进行更紧密、更直观的协作。 ​​​​​​​ Canvas的…...

【深度学习】— softmax回归、网络架构、softmax 运算、小批量样本的向量化、交叉熵

【深度学习】— softmax回归、网络架构、softmax 运算、小批量样本的向量化、交叉熵 3.4 Softmax 回归3.4.1 分类问题3.4.2 网络架构 3.4.3 全连接层的参数开销3.4.4 softmax 运算3.4.5 小批量样本的向量化3.4.6 损失函数对数似然softmax 的导数 3.4.7 信息论基础熵信息量重新审…...

C# Wpf 图片按照鼠标中心缩放和平移

C# Wpf 图片按照鼠标中心缩放和平移 1、缩放事件 MouseWheel(object sender, MouseWheelEventArgs e)2、平移相关的事件 MouseMove(object sender, MouseEventArgs e) MouseDown(object sender, MouseButtonEventArgs e) MouseUp(object sender, MouseButtonEventArgs e)3、…...

网络安全产品类型

1. 防火墙&#xff08;Firewall&#xff09; 功能&#xff1a;防火墙是网络安全的第一道防线&#xff0c;通过检查进出网络的流量来阻止未经授权的访问。它可以基于预定义的安全规则&#xff0c;过滤数据包和阻止恶意通信。 类型&#xff1a; 硬件防火墙&#xff1a;以专用设备…...

【开源风云】从若依系列脚手架汲取编程之道(五)

&#x1f4d5;开源风云系列 &#x1f34a;本系列将从开源名将若依出发&#xff0c;探究优质开源项目脚手架汲取编程之道。 &#x1f349;从不分离版本开写到前后端分离版&#xff0c;再到微服务版本&#xff0c;乃至其中好玩的一系列增强Plus操作。 &#x1f348;希望你具备如下…...

金融市场的衍生品交易及其风险管理探讨

金融衍生品市场是现代金融体系的重要组成部分&#xff0c;其交易量和复杂性在过去几十年中迅速增长。衍生品&#xff0c;如期权、期货、掉期等&#xff0c;因其灵活性和杠杆效应&#xff0c;广泛应用于风险管理、投机和资产配置等多个领域。本文将探讨金融衍生品交易的关键特点…...

一、创建型(单例模式)

单例模式 概念 单例模式是一种创建型设计模式&#xff0c;确保一个类只有一个实例&#xff0c;并提供一个全局访问点。它控制类的实例化过程&#xff0c;防止外部代码创建新的实例。 应用场景 日志记录&#xff1a;确保只有一个日志记录器&#xff0c;以便于管理和避免重复记…...

毕业设计项目-古典舞在线交流平台的设计与实现(源码/论文)

项目简介 基于springboot实现的&#xff0c;主要功能如下&#xff1a; 技术栈 后端框框&#xff1a;springboot/mybatis 前端框架&#xff1a;html/JavaScript/Css/vue/elementui 运行环境&#xff1a;JDK1.8/MySQL5.7/idea&#xff08;可选&#xff09;/Maven3&#xff08…...

【秋招笔试】10.09华子秋招(已改编)-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 大厂实习经历 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 本次的三题全部上线…...

【算法笔记】双指针算法深度剖析

【算法笔记】双指针算法深度剖析 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;算法笔记 文章目录 【算法笔记】双指针算法深度剖析前言一.移动零1.1题目1.2思路分析1.3代码实现 二.复写零2.1题目2.2思路分析2.3代码实现 三.快乐数3.1题目…...

第二十二天|回溯算法| 理论基础,77. 组合(剪枝),216. 组合总和III,17. 电话号码的字母组合

目录 回溯算法理论基础 1.题目分类 2.理论基础 3.回溯法模板 补充一个JAVA基础知识 什么时候用ArrayList什么时候用LinkedList 77. 组合 未剪枝优化 剪枝优化 216. 组合总和III 17. 电话号码的字母组合 回溯法的一个重点理解&#xff1a;细细理解这句话&#xff01;…...

关闭IDM自动更新

关闭IDM自动更新 1 打开注册表2 找到IDM注册表路径 1 打开注册表 winR regedit 2 找到IDM注册表路径 计算机\HKEY_CURRENT_USER\Software\DownloadManager 双击LstCheck&#xff0c;把数值数据改为0 完成 感谢阅读...

Go 性能剖析工具 pprof 与 Graphviz 教程

在 Golang 开发中&#xff0c;性能分析是确保应用高效运行的重要环节。本文介绍如何使用 gin-contrib/pprof 在 Gin 应用中集成性能剖析工具&#xff0c;并结合 Graphviz 生成图形化的性能分析结果&#xff0c;如火焰图。这套流程帮助开发者更好地理解和优化 Go 应用的性能。 目…...

【题目解析】蓝桥杯23国赛C++中高级组 - 斗鱼养殖场

【题目解析】蓝桥杯23国赛C中高级组 - 斗鱼养殖场 题目链接跳转&#xff1a;点击跳转 前置知识&#xff1a; 了解过基本的动态规划。熟练掌握二进制的位运算。 题解思路 这是一道典型的状压动态规划问题。设 d p i , j dp_{i, j} dpi,j​ 表示遍历到第 i i i 行的时候&a…...

JavaScript可视化:探索顶尖的图表库

JavaScript可视化&#xff1a;探索顶尖的图表库 在这个被数据驱动的时代&#xff0c;你有没有想过&#xff0c;数据本身是如何变得有意义的&#xff1f;答案就是数据可视化。通过图表和图形&#xff0c;我们不仅可以看到数据&#xff0c;还可以感受到它&#xff0c;从而做出明…...

谷歌AI大模型Gemini API快速入门及LangChain调用视频教程

1. 谷歌Gemini API KEY获取及AI Studio使用 要使用谷歌Gemini API&#xff0c;首先需要获取API密钥。以下是获取API密钥的步骤&#xff1a; 访问Google AI Studio&#xff1a; 打开浏览器&#xff0c;访问Google AI Studio。使用Google账号登录&#xff0c;若没有账号&#xf…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准

城市路内停车管理常因行道树遮挡、高位设备盲区等问题&#xff0c;导致车牌识别率低、逃费率高&#xff0c;传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法&#xff0c;正成为破局关键。该设备安装于车位侧方0.5-0.7米高度&#xff0c;直接规避树枝遮…...

Python竞赛环境搭建全攻略

Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型&#xff08;算法、数据分析、机器学习等&#xff09;不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...