基于Keil生成外部Nor Flash下载算法,并使用J-Flash直接烧录(以W25Q64为例)

news2024/11/28 15:52:28

需要的软件:
Keil
STM32CubeMX
J-Flash

参考文档:
方法1:在Keil中点击Help→uVision Help,然后再搜索框中输入FLM,点击列出主题,可以看到生成下载算法的大致步骤:
在这里插入图片描述

方法2:在ARM Keil官网,搜索KAN333,可以找到生成算法说明的PDF文档以及例程源码。链接
在这里插入图片描述

方法3:在Keil安装路径下Keil_v5\ARM\Flash_Template,找到Abstract.txt,打开后有一个生成算法说明的文档。链接
在这里插入图片描述
先说一下大致原理,生成的算法文件也就是FLM文件,实际上会先下载进你板子的RAM中,然后在板子的RAM中运行,进而去写外部Nor Flash或者片内Flash。
在这里插入图片描述
参考上面任意一个说明文档都可以,但是不要完全按照上面描述的来,我之前是按照第二个方法下载的pdf来的,但是折腾了两天才有结果,下面是具体实现的方法。

1.复制Keil安装路径下Keil_v5\ARM\Flash_Template文件夹,并重命名为自己的算法工程名,我这以STM32L4xx_W25Q64为例。
2.将文件夹的只读属性取消,并将keil工程的名字改为自己的工程名。
在这里插入图片描述
3.打开工程,选择魔术棒,在Device一栏中选择自己板子上对应的MCU,在Target一栏中ARM Compiler保持默认V5就好,不用像PDF中描述的一样改成V6的,两个版本用的编译方法不一样,V6版本的生成的FLM文件小一点,但是好像没办法使用MicroLIB,会报错。
在这里插入图片描述
在Output一栏中改为自己工程的名字
在这里插入图片描述
User一栏中不要动,cmd.exe /C copy “Objects%L” ".@L.FLM"在工程编译后会执行。
C/C++和Asm中确认Read-Only Position Independent和Read-Write Position Independent勾选,表明这个是与位置无关的算法,因为要放在RAM中执行。C/C++一栏中Define中对应填入需要的宏,代码量不大的话编译器优化等级可以设置为0,后边会提到代码量具体有什么限制。
在这里插入图片描述
Linker一栏中使用自定义分散加载文件,保持默认就好。
在这里插入图片描述
4.打开Manage Run-Time Environment,勾选如下内容,并点击绿色按钮,启动STM32CubeMX。
在这里插入图片描述
5.在STM32CubeMX中配置工程,先配置为自己需要的时钟频率,不要像PDF中一样保持默认,不然的话时钟频率只有4M。
在这里插入图片描述
然后配置好SPI,GPIO等,如果有需要的话也可以配置一下串口用于输出Log,我是配置了两个LED灯,一个用于指示擦除,一个用于指示编写。
在Project Manager中,Project一栏中不用像PDF中描述的勾选Do not generate the main(),这样会生成main函数,可以用于测试生成的代码是否可用,不用自己写。
Code Generator一栏中按如下勾选:
在这里插入图片描述
Advanced Settings一栏保持函数调用。
在这里插入图片描述
然后点击Generate Code生成代码。

6.在STM32L4xx_W25Q64\RTE\Device\STM32L431CCTx\STCubeGenerated\MDK-ARM路径下,打开生成的的工程,然后可以在里面测试一下生成的工程,添加一下自己的读写外部Nor Flash的代码,能正常操作就行。

7.回到生成算法的工程里面,把main.c中的main函数屏蔽掉,否则在生成算法文件的时候会报错。此外也不要像PDF中描述的重新定义HAL_InitTick(),HAL_Delay()等几个函数,因为使用HAL库的话用到的一些超时检测什么的都会有影响。
在这里插入图片描述

8.在Device目录右键Options for Component Class ‘Device’,选择启动文件,取消勾选Include in target build。
在这里插入图片描述
9.新建一个目录,添加自己操作外部Nor Flash的代码和System文件。
在这里插入图片描述
10.实现FlashDev.c,这个是设备描述文件,改为自己合适的就好。
在这里插入图片描述
Device Type根据实际设置。
在这里插入图片描述
Device Start Address可以直接从0x00000000开始,这样就不用在FlashPrg.c中额外处理地址。

Programming Page Size根据自己的外部Nor Flash设置,比如W25Q64每页256字节,设置为256的话一个扇区就需要多次调用ProgramPage()函数,所以可以直接设置成一个扇区大小(4096),这样调用ProgramPage()函数的时候直接写一个扇区。

Specify Size and Address of Sectors指的是扇区划分,比如有的MCU有不同大小的扇区,第一个参数就是扇区大小,第二个参数就是扇区起始地址;比如W25Q64,每个扇区都是16个页,每个页256字节,所以第一个参数就是0x001000(4096),第二个表示从0地址开始,如果有其他的扇区大小类型,在SECTOR_END之前添加。

Erase Sector Timeout为擦除超时时间,全片擦除也受这个参数影响,W25Q64全片擦除需要14s左右,所以适当设置大一点。

10.实现FlashPrg.c,必须要实现的函数是Init,UnInit,EraseChip,EraseSector,ProgramPage。可根据需要实现的函数Verify,BlankCheck。

Init函数需要初始化时钟,GPIO,SPI等,正确执行返回0,执行错误返回1。不要像PDF中一样关中断,因为需要用到滴答定时器中断。

int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {
  int ret = 0;
  volatile int i;
  volatile unsigned char * ptr = (volatile unsigned char * )&hspi2;

  for (i = 0; i < sizeof(hspi2); i++) {
    *ptr++ = 0U;
  }
  SystemInit();
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_InitLed();
  if(W25Q64_Init() != W25Q64_ID)
  {
	ret = 1;
  }
  return (ret);                                  // Finished without Errors
}

UnInit函数可以什么都不做,因为我在擦除和写的时候翻转LED,所以添加了关LED操作。

int UnInit (unsigned long fnc) {

  HAL_GPIO_WritePin(Prog_Led_GPIO_Port,Prog_Led_Pin,GPIO_PIN_RESET);
  HAL_GPIO_WritePin(Erase_Led_GPIO_Port,Erase_Led_Pin,GPIO_PIN_RESET);
  return (0);                                  // Finished without Errors
}

擦除分为全片擦除和擦除扇区,流程图如下:
在这里插入图片描述
EraseChip函数直接调用自己的全片擦除函数。

int EraseChip (void) {
	
  HAL_GPIO_TogglePin(Erase_Led_GPIO_Port,Erase_Led_Pin);
  W25Q64_Erase_Chip();
  return (0);                                  // Finished without Errors
}

EraseSector 函数直接调用自己的擦除扇区函数。

int EraseSector (unsigned long adr) {
	
  HAL_GPIO_TogglePin(Erase_Led_GPIO_Port,Erase_Led_Pin);
  W25Q64_Erase_Sector((uint32_t)adr);
  return (0);                                  // Finished without Errors
}

ProgramPage函数直接调用自己的写扇区函数。要写的大小跟FlashDev.c中的Programming Page Size大小一致。写Flash流程图如下:
在这里插入图片描述

int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {

  HAL_GPIO_TogglePin(Prog_Led_GPIO_Port,Prog_Led_Pin);
//	W25Q64_Write_Page(buf,(uint32_t)adr,(uint16_t)sz);
  W25Q64_Write_Sector(buf,(uint32_t)adr,(uint16_t)sz);
  return (0);                                  // Finished without Errors
}

Verify和BlankCheck函数可以不实现。
Verify函数作用是判断写成功了多少字节数据,这个值跟FlashDev.c中Device Start Address值有关,如果Device Start Address值不为0,那么就是Device Start Address加上写成功了多少字节。校验函数流程图:
在这里插入图片描述

unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf) {
  uint32_t i;
  W25Q64_ReadData(W25Q64_BufferA,(uint32_t)adr,(uint16_t)sz);
  for (i = 0; i < sz; i++) 
  {
	if (W25Q64_BufferA[i] != buf[i]) 
	{
	  return (adr + i); 
	}
  }
  return (adr + sz); 
}

BlankCheck函数作用是在擦除块的时候判断一下这个块需不需要擦除,实际上就是比较块内的值是不是都是FlashDev.c中定义的Initial Content of Erased Memory值一样,如果有一个字节不是,说明块需要擦除。

int BlankCheck (unsigned long adr, unsigned long sz, unsigned char pat) {
  uint32_t i, j;
  uint32_t read_len = 0;
  if((adr + sz) > W25Q64_TOTAL_NUM)
  {
	return (1);
  }
  for (i = 0; i < sz; i += W25Q64_SECTOR_NUM) 
  {
	if(sz >= W25Q64_SECTOR_NUM)
	{
		read_len = W25Q64_SECTOR_NUM;
	}
	else
	{
		read_len = sz;
	}
	W25Q64_ReadData(W25Q64_BufferA,(adr+i),read_len);
	for(j = 0; j < read_len; j++)
	{
	  if (W25Q64_BufferA[j] != pat) 
	    return (1);
	}
	sz -= read_len;
  }
  return (0);                           // Memory is blank
}

然后编译之后就会生成下载算法文件FLM。注意不要添加太多没用的调试代码,否则会导致生成的代码量太大,就不得不提高优化等级,还可能导致生成的算法文件使用时报错。可以在编译之后通过map文件确认一下代码占用的空间,不能超过RAM的大小,因为算法是需要在RAM中运行的。
在这里插入图片描述
如果算法代码量太大,可能会导致报错RAM area configured for this target is too small.
在这里插入图片描述

11.将生成的下载算法文件复制到Keil_v5\ARM\Flash路径下,就可以在KEIL中看到。
在这里插入图片描述
12.在J-link安装目录下SEGGER\JLink_V640\Devices中新建一个文件夹,比如命名为W25Qxx,然后把下载算法文件复制过来。
在这里插入图片描述
13.在SEGGER\JLink_V640路径下打开JLinkDevices文件,在末尾添加如下内容。

  <!--         -->
  <!-- W25QXX  -->
  <!--         -->
<Device>
<ChipInfo Vendor="W25QXX" Name="STM32L4xx_W25Q64" Core="JLINK_CORE_CORTEX_M4" WorkRAMAddr="0x20000000" WorkRAMSize="0x0000C000"/>
<FlashBankInfo Name="SPI Flash" BaseAddr="0x00000000" MaxSize="0x00800000" Loader="Devices/W25Qxx/STM32L4xx_W25Q64.FLM" LoaderType="FLASH_ALGO_TYPE_OPEN" AlwaysPresent="1"/>
</Device>

WorkRAMAddr和WorkRAMSize就是自己MCU的RAM参数,BaseAddr和MaxSize设置的和FlashDev.c中一样。

之后就可以使用J-Flash直接把数据烧写进外部Nor Flash中。

测试:
使用J-Flash新建工程,选择下载算法文件。
在这里插入图片描述
全片擦除:
在这里插入图片描述
擦除扇区:
在这里插入图片描述
写入:
在这里插入图片描述
Flash为空:
在这里插入图片描述
Flash不为空:
在这里插入图片描述
写入并校验:
在这里插入图片描述

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

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

相关文章

带你玩转三子棋—【C语言】

目录 前言&#xff1a; 1. 菜单的打印 2. game函数的实现 2.1 初始化棋盘 2.2 显示棋盘 2.3 玩家下棋 2.4 电脑下棋 2.5 判断输赢 2.6 判断棋盘是否满了 3. 全部代码 3.1 game.h 3.2 game.c 3.3 test.c 前言&#xff1a; 为了实现三子棋&#xff0c;首先我们应该…

frp将配置写在代码中重新打包

frp 是一个专注于内网穿透的高性能的反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。在有些情况下我们需要隐藏配置信息&#xff0c;尤其是客户端&#xff08;比如我们要在第三方电脑…

第五章 总结及作业(123)【编译原理】

第五章 作业【编译原理】 前言推荐第五章 总结5.1自下而上分析基本问题 5.1.1归约5.1.2规范归约简述5.1.3 符号栈的使用与语法树的表示 5.2 算符优先分析5.2.1算符优先文法及优先表构造算法&#xff1a;构造FIRSTVT集算法&#xff1a;构造LASTVT集算法&#xff1a;构造优先表5.…

Google I/O 2023 - 一文快速总结 Flutter Dart 的现状和未来

随着 Google I/O 2023 的发布&#xff0c; Flutter 3.10 和 Dart 3.0 也都正式发&#xff0c;不得不说如今 Dart 的版本号终于快追上 Flutter 得版本号了&#xff0c;特别随着 Dart 3 的发布&#xff0c; Flutter 在 records 和 patterns 的加持下&#xff0c;开发体验终于开始…

LlamaIndex :面向QA 系统的全新文档摘要索引

在这篇博文中&#xff0c;我们介绍了一种全新的 LlamaIndex 数据结构&#xff1a;文档摘要索引。我们描述了与传统语义搜索相比&#xff0c;它如何帮助提供更好的检索性能&#xff0c;并通过一个示例进行了介绍。 背景 大型语言模型 (LLM) 的核心场景之一是对用户自己的数据进…

MapReduce框架

TextInputFormat 1&#xff09;FileInputFormat实现类 思考&#xff1a;在运行MapReduce程序时&#xff0c;输入的文件格式包括&#xff1a;基于行的日志文件、二进制格式文件、数据库表等。那么&#xff0c;针对不同的数据类型&#xff0c;MapReduce是如何读取这些数据的呢&…

Postman 如何关联接口测试并设置全局变量(带有token鉴权)

一、登陆接口 创建一个request请求 在Tests中添加JavaScript代码&#xff0c;用来获取鉴权&#xff1a; var jsonData JSON.parse(responseBody); var Authorization jsonData.data.access_token; console.log(Authorization) pm.globals.set(‘Authorization’,Authorizatio…

solr快速上手:solr简介及安装(一)

0. 引言 虽然现在主流的搜索引擎组件已经es主导&#xff0c;但不乏有部分“老”项目依旧在采用solr&#xff0c;当遇到这类项目时&#xff0c;如何快速上手solr组件&#xff0c;以及后续如何拓展深入研究solr的途径成为问题&#xff0c;本期我们的目的就是带大家来快速上手sol…

2023 年第三届长三角高校数学建模竞赛赛题浅析

为了更好地让大家本次长三角比赛选题&#xff0c;我将对本次比赛的题目进行简要浅析。数模模型通常分为优化、预测、评价三类&#xff0c;而本次数学题目就正好对应着A、B、C分别为优化、预测、评价。整体难度不大&#xff0c;主要难点在于A题的优化以及B、C的数据收集。稍后&a…

QT5.12.6 + mysql5.5.9 出现 Driver not loaded Driver not loaded

由于我重装了电脑系统&#xff0c;qt 和mysql均进行了软件版本的升级&#xff0c; 在使用数据库模块时&#xff0c;出现了如下问题&#xff1a; Driver not loaded Driver not loaded 排除问题一&#xff1a; pro文件中是否加载了sql模块 查看pro文件&#xff0c;发现 有此模…

React的两种组件创建方式(二)

react是面向组件编程的一种模式&#xff0c;它包含两种组件类型&#xff1a;函数式组件及类式组件 函数式组件 一个基本的函数组件长这个样子 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><title>hell…

java报错-->java.lang.IllegalAccessError

1、前言 在gradle中运行main方法突然出现如下错误 Exception in thread "main" java.lang.IllegalAccessError: class XXX.util.ImageBorderUtils (in unnamed module 0x4bd4bcd4) cannot access class sun.font.FontDesignMetrics (in module java.desktop) becaus…

使用宝塔在Linux面板搭建网站,并实现公网远程访问「内网穿透」

文章目录 前言1. 环境安装2. 安装cpolar内网穿透3. 内网穿透4. 固定http地址5. 配置二级子域名6. 创建一个测试页面 转载自远程内网穿透的文章&#xff1a;Linux使用宝塔面板搭建网站&#xff0c;并内网穿透实现公网访问 前言 宝塔面板作为简单好用的服务器运维管理面板&#…

数据结构与算法(Java版) | 数组模拟队列的思路分析与代码实现

思路分析 上一讲我们讲过&#xff0c;队列既可以用数组来实现&#xff0c;也可以用链表来实现&#xff0c;但由于我们比较熟悉数组这种结构&#xff0c;所以这里我会先给大家讲一下数组这种实现方式&#xff0c;至于链表这种实现方式&#xff0c;那就以后有机会再说吧&#xf…

探索人工智能新纪元:Pre-Training 快速指南,轻松上手

theme: orange 预训练 Pre-Training 已被证明是当前人工智能范式中最重要的方面之一&#xff0c;大型语言模型&#xff0c;要转变为通用引擎&#xff0c;需要预训练。 什么是预训练模型 人工智能中的预训练至少部分受到人类学习方式的启发。我们不需要从零开始学习一个主题&…

肝一肝设计模式【七】-- 代理模式

系列文章目录 肝一肝设计模式【一】-- 单例模式 传送门 肝一肝设计模式【二】-- 工厂模式 传送门 肝一肝设计模式【三】-- 原型模式 传送门 肝一肝设计模式【四】-- 建造者模式 传送门 肝一肝设计模式【五】-- 适配器模式 传送门 肝一肝设计模式【六】-- 装饰器模式 传送门 文…

JavaWeb:Cookie、Session、JSP、JavaBean、MVC 三层架构

文章目录 JavaWeb - 03一、Cookie1. Cookie 应用2. 注意点 二、Session三、JSP1. 概述2. JSP 基础语法和指令&#xff08;了解&#xff09;3. 内置对象及作用域4. JSP 标签、JSTL 标签 四、JavaBean五、MVC 三层架构1. 之前的架构2. 现在的 MVC 三层架构 注意&#xff1a; Java…

Feign和OpenFeign

1.Feign和OpenFeign的关系 Feign Feign是一个声明式的Web服务客户端&#xff08;Web服务客户端就是Http客户端&#xff09;&#xff0c;让编写Web服务客户端变得非常容易&#xff0c;只需创建一个接口并在接口上添加注解即可。 Feign是Spring Cloud组件中一个轻量级RESTful的H…

MySQL基础学习---7、子查询

子查询 子查询指的是一个查询语句嵌套在另一个查询语句内部的查询&#xff08;从MySQL4.1开始引入&#xff09;。1、子查询的基本使用 语法格式&#xff1a;select select_listfrom tablewhere expr operator(select select_listfrom table); 说明&#xff1a;1、子查询&…

【终极解决方案】IDEA maven 项目修改代码不生效。

【终极解决方案】IDEA maven 项目修改代码不生效。 文章目录 【终极解决方案】IDEA maven 项目修改代码不生效。1、项目问题描述2、可能的解决方案3、分析原因4、解决方案5、参考文献 1、项目问题描述 遇到一个非常奇怪的问题&#xff0c;修改了一个基于maven搭建的SSM项目&am…