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

keil下载程序具体过程4:flash下载算法

引言

        本篇文章将介绍flash算法文件,阐述从jlink如何下载镜像文件写入到内部的falsh。

一、XIP

        在谈flash下载算法文件时,先说明XIP是什么。

        芯片的启动方式有很多种:可以从RAM中启动、内部的flash、外部的flash等等(还有从sd卡、emmc、nor flash、nand flash等),这里我们只考虑内部的flash的情况。
        我们都知道flash只是一块ROM,flash有两种类型,分为nor flash、nand flash,一般32位处理器里面使用的是nor flash作为ROM,存放镜像文件。

        在专业课(计算机组成原理或者操作系统)中,有提到,CPU从内存(RAM)中读取、运行程序。但在stm32这种微处理器上,一般都是直接从内部的flash启动。这牵扯到一个技术,叫做XIP(eXecute In Place ),即芯片内执行。其含义就是CPU直接从存储器读取指令,将指令送给译码器和执行器等部件使用。 有了XIP就不必将代码读取到RAM中,可以直接在flash运行。好处即是程序代码无需占用内存,减少内存的要求。XIP是复杂性和速度的权衡,而这就意味着XIP通常仅用于BIOS或RAM极度短缺(MCU的情况就是如此)的情况。

要实现XIP,必须要有如下几个条件:
1. 存储器必须提供与内存相似的接口给CPU。
2. 该接口必须提供足够快的读取操作,并具有随机访问模式。
3. 如有文件系统,则需要提供合适的映射功能
4. 程序链接时需要知道存储器的地址或地址与位置无关。
5. 程序不能修改已加载映像中的数据。

因为nor flash和EEPROM通常能满足上述要求,所以其可以XIP。 而nand flash因为有地址,数据,命令共用IO口的问题,cpu发送来地址之后,还要nand flahs控制器再处理一下才能得到数据,因此不适合(不是不能XIP,只是不适合)。nor flash的访问和RAM类似,提供地址,就可以得到数据。因此,一般处理器内部都是使用nor flash作为XIP的方案,而且,nor flash读取速度比nand flash要快很多。

        当bin文件经过JLink、SW-DP接口,经过AHB-DP将数据传到AHB总线上之后,已经具备可以写入到falsh里面的条件了。这里随便找了一个芯片内部图作为例子。

        从上图中可以看到,FLASH上面有Controller接口、XIP接口、EEPROM仿真接口。Controller接口就是我们在平常使用程序往flash写入数据的控制部分(一般流程是:先解锁flash写保护、写入数据、上锁写保护)。这个例子应该很容易想起来的,不懂的可以搜索一下:stm32往内部flash写入数据。就可以得到相关信息了。这里我们写入bin文件到flash同样通过Controller接口。
        SWD接口将数据传到AHB-DP、到总线之后,就会在控制信号的指引下,控制Controller,然后将bin文件写入到flash,写入完成、校验之后,就可以reset启动芯片了,使用XIP技术,从flash某个地址启动(常用的stm32一般是0x08000000)。

        知道了往哪里写之后,也大概了解了数据写入的流程,那么该如何写?这里就要用到了flash下载算法了。

二、FLM文件

        FLM文件是keil进行代码下载时的必须文件,该文件主要包含被下载芯片的存储器的相关信息(芯片型号、存储器页大小等)和存储器写入算法。FLM文件本质上也是一种ELF(Executable and Linkable Format)文件,ELF文件的具体格式我们放到后面介绍。

         上图中就是FLM文件,他指导jlink如何下载镜像文件。镜像文件本质上就是一堆二进制,我们都知道keil会生成axf文件、hex、bin文件,镜像文件其实就是bin文件,下载到flash里面的内容就是bin文件的内容。算法的名字叫做NEW_DEVICE.FLM,路径在keil的安装目录里面:ARM\PACK\ARM\CMSIS\4.5.0\Device\ARM\Flash。

        在C:\Keil_v5\ARM\Flash_Template(默认安装的情况下)下面会有一个keil工程,这个工程就是keil官方提供给我们制作flash下载算法的。

打开之后很简单,就两个文件

 FlashDev.c就只有一个struct FlashDevice类型的结构体,上图是一个例子,具体定义在FlashOS.H中。

struct FlashSectors {unsigned long szSector; // Sector Size in Bytesunsigned long AddrSector; // Address of Sector
};
struct FlashDevice {unsigned short Vers; // Version Number and Architecturechar DevName[128]; // Device Name and Descriptionunsigned short DevType; // Device Type: ONCHIP, EXT8BIT, EXT16BIT, ...unsigned long DevAdr; // Default Device Start Addressunsigned long szDev; // Total Size of Deviceunsigned long szPage; // Programming Page Sizeunsigned long Res; // Reserved for future Extensionunsigned char valEmpty; // Content of Erased Memoryunsigned long toProg; // Time Out of Program Page Functionunsigned long toErase; // Time Out of Erase Sector Functionstruct FlashSectors sectors[SECTOR_NUM];
};

从上面的结构体中我们可以知道,我们的flash地址、大小、扇区大小等信息,这些都会在下载bin文件的时候用到。

在FlashDev.c中,我们可以看到16行,表示flash设备的类型,有如下几种情况。

#define UNKNOWN 0 // Unknown
#define ONCHIP 1 // On-chip Flash Memory
#define EXT8BIT 2 // External Flash Device on 8-bit Bus
#define EXT16BIT 3 // External Flash Device on 16-bit Bus
#define EXT32BIT 4 // External Flash Device on 32-bit Bus
#define EXTSPI 5 // External Flash Device on SPI

17--23就是指flash的参数,有多大,每页多少字节等等。
FlashPrg.c里面就只是一些函数的接口,具体有哪些函数接口在下面。

// Flash Programming Functions (Called by FlashOS)
extern int Init (unsigned long adr, // Initialize Flashunsigned long clk,unsigned long fnc);
extern int UnInit (unsigned long fnc); // De-initialize Flash
extern int BlankCheck (unsigned long adr, // Blank Checkunsigned long sz,unsigned char pat);
extern int EraseChip (void); // Erase complete Device
extern int EraseSector (unsigned long adr); // Erase Sector Function
extern int ProgramPage (unsigned long adr, // Program Page Functionunsigned long sz,unsigned char *buf);
extern unsigned long Verify (unsigned long adr, // Verify Functionunsigned long sz,unsigned char *buf);

其实就是对flash的操作,以前搞过spi flash(就是w25qxx系列),对上面的回调函数很好理解。
直接将keil官方提供的例子进行编译,如下图。

 其他的跟keil生成程序一样,画横线的log是在编译结束之后,将axf拷贝位flx文件,从这里可以看出,
flm文件其实就是axf文件,看看二者的文件大小,均为10500Byte。

 axf文件是什么?是在bin文件的基础山添加了地址信息和调试信息的文件。使用记事本打开,确实有调试信息。

 能生成axf文件,说明有sct(分散加载文件)指导整个工程,生成axf,我们在keil配置里面找到之后,发现只有一个叫做Target.lin的文件,打开之后看到:

 跟平常见到的sct文件不太一样。

 其实,本质上并无差别,无非就是指定code中的各种属性(RO、RW、ZI)放到某些位置。

三、操作flash接口

        现在来看看FlashPrg.c里面的函数接口。

int Init (unsigned long adr, unsigned long clk, unsigned long fnc)

功能:用于初始化Flash
adr参数表示设备基地址(Base Address)
clk参数表示时钟频率
adr参数表示功能码(1 - 擦除, 2 - 程序, 3 -验证)

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

功能:将代码写入到flash中。
adr参数表示flash起始地址
sz参数表示写入数据的大小
buf参数表示缓存区
这里强调一点,falsh是以块为单位组织的,在FlashDev里面也有指定,大小为szPage。主机系统往flash写入数据的时候会确保不会出现跨块写入数据(就是一块一块的写入)。在前面的内容中,

T5324 000:563.106 Data: 88 08 00 20 D5 01 00 10 8B 0A 00 10 65 0A 00 10 ...
T5324 000:563.126 CPU_WriteMem(512 bytes @ 0x20000670)

写入是以512B大小的内容往flash写入。其他的函数都比较好理解,就不细讲了。

回过头来再看jlink下载日志(写入flash的部分已删掉):

T5324 000:386.354 JLINK_WriteMem(0xE0001000, 0x1C Bytes, ...)
T5324 000:386.358 Data: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...
T5324 000:386.372 CPU_WriteMem(28 bytes @ 0xE0001000)
T5324 000:390.509 JLINK_WriteMem(0x20000000, 0x670 Bytes, ...)
T5324 000:390.517 Data: 00 BE 0A E0 0D 78 2D 06 68 40 08 24 40 00 00 D3 ...
T5324 000:390.720 CPU_WriteMem(1648 bytes @ 0x20000000)
T5324 000:527.583 JLINK_WriteMem(0x20000000, 0x670 Bytes, ...)
T5324 000:527.598 Data: 00 BE 0A E0 0D 78 2D 06 68 40 08 24 40 00 00 D3 ...
T5324 000:527.622 CPU_WriteMem(1648 bytes @ 0x20000000)
.....
T1A34 000:768.192 JLINK_WriteMem(0x20000000, 0x670 Bytes, ...)
T1A34 000:768.209 Data: 00 BE 0A E0 0D 78 2D 06 68 40 08 24 40 00 00 D3 ...
T1A34 000:768.232 CPU_WriteMem(1648 bytes @ 0x20000000)
T1A34 000:884.512 JLINK_WriteMem(0x20000000, 0x2 Bytes, ...)
T1A34 000:884.533 Data: FE E7
T1A34 000:884.552 CPU_WriteMem(2 bytes @ 0x20000000)

以下的部分内容,有些是猜测(根据自己的实践和网上的内容进行合理猜测)。
T5324 000:386.354:跟DWT通信,开始写入flash算法(也就时一段短的程序)。

T5324 000:390.509:将flash写入算法的内容写入到RAM中,地址在这里设置。

         之后,通过jlink,按照块(512B)大小发送程序的镜像文件(内容和bin文件一样),由flash写入算法接受数据,将镜像文件写入到flash中。最后完成校验、复位等工作(还有一些工作就不展开了,跟本文内容不是很紧密),jlink就可以断开了。

        这部内容简单的总结下就是:jlink先和M3内核沟通,然后将flash下载算法传输到到RAM中,再发送bin文件到RAM中,由flash下载算法将RAM中的bin文件(前面接受到的)写入到内部的flash。最后进行校验,复位(若有)等扫尾工作。

        到这里也明白了,下载bin文件到flah中的过程,其实是由我们指定的(flm文件),这个flm文件一般由芯片厂商提供,keil只是将这个接口(具体的下载bin的过程)开放出去了,各个芯片厂家适配他们自己的芯片。

四、芯片启动过程

        bin下载的过程基本上已经讲完了,如果还有内容的话,以后再更。最后谈一谈芯片如何启动。再说明芯片启动之前,我们先看看芯片的地址空间。

         上面时M3内核定义的地址空间使用,一般芯片厂商会根据自己的需要,在划分的区域里面实现自己的地址划分。(博主这里不想找了,就简单的画一个我需要讲解的部分,作为说明素材)

         玩过stm32的同学应该知道,stm32有两个boot引脚:boot0、boot1,二者配合起来选择从哪里启动(boot[0:1] 均为0的时候从内部flash启动,也就是从地址0x0800  0000,其他的情况从RAM或者外部flash启动,现在各位同学应该知道如果从外部flash启动该如何做了0^0)。

        在配置boot0/1为低电平时,芯片从0x0800  0000地址出读取两个字,一个sp,一个pc,然后配置中断向量表、进入复位中断(就是startup_stm32xxxx.s的内容)。但按理说,pc、sp一开始的值应该为0,那如何跳到0x0800  0000进而读取那里的bin文件呢?问题就在Boot里面

        看上图,Boot是一段代码,由厂商烧录。芯片在启动的时候,pc值为0,运行Boot程序,Boot程序会去检测boot0/1引脚,进而决定是从内部flash还是ram或者其他的地方启动(其实就是一个地址的区别,内部flash启动就是0x0800  0000,ram就是0x2000 0000),之后跳转到0x0800  0000(boot0/1为低电平),下面才是startup_stm32xxxx.s的内容。

相关文章:

keil下载程序具体过程4:flash下载算法

引言 本篇文章将介绍flash算法文件,阐述从jlink如何下载镜像文件写入到内部的falsh。 一、XIP 在谈flash下载算法文件时,先说明XIP是什么。 芯片的启动方式有很多种:可以从RAM中启动、内部的flash、外部的flash等等(还有从sd卡、…...

如何快速的让自己从月入2000变成月入两万?

从月入2000变成月入两万 前言我们可以这么做:1.提升自己的技能:2.寻找更好的工作机会:寻找更好的工作机会是一个重要的目标,以下是几个建议: 3.开展副业或兼职工作:4.创业或投资:5.构建个人品牌…...

使用 CycleGAN 进行图像到图像转换

介绍 在人工智能和计算机视觉领域,CycleGAN 是一项非凡的创新,它重新定义了我们感知和操作图像的方式。这种尖端技术彻底改变了图像到图像的转换,实现了领域之间的无缝转换,例如将马变成斑马或将夏日风景变成雪景。在本文中,我们将揭开 CycleGAN 的魔力,并探索其在各个领…...

Svg使用和注册components文件夹内部全部为全局组件

1.安装SVG依赖插件 pnpm install vite-plugin-svg-icons -D 2. 封装SvgIcon <template><div><svg :style"{ width: width, height: height }"><use :xlink:href"prefix name" :fill"color"></use></svg>…...

解决idea编辑application.yml文件或properties文件没有提示问题

注意&#xff1a;这里说的没有提示&#xff0c;是针对application.properties和application.yml文件 解决办法&#xff1a;在idea的插件面板中&#xff0c;禁用或卸载 wl Spring Assistant插件即可解决问题。...

前端懒加载

懒加载的概念 懒加载也叫做延迟加载、按需加载&#xff0c;指的是在长网页中延迟加载图片数据&#xff0c;是一种较好的网页性能优化的方式。在比较长的网页或应用中&#xff0c;如果图片很多&#xff0c;所有的图片都被加载出来&#xff0c;而用户只能看到可视窗口的那一部分…...

【手动配置ip地址后,电脑仍自动分配ip的问题】

现象 手动给电脑分配了一个ipv4地址&#xff0c;但是电脑会自动分配一个169开头的ipv4&#xff0c;导致虽然可以上网&#xff0c;但访问不了局域网内其他的设备&#xff08;我配置的另一个网关&#xff0c;所以可以上网&#xff09; 原因 ip地址冲突了&#xff0c;把电脑的i…...

移远RM500U-CN模块直连嵌入式ubuntu实现拨号上网

目录 1 平台&#xff1a; 2 需要准备的资料 3 参考文档 4 编译环境与驱动移植 4.1 内核驱动添加厂家ID和产品ID 4. 2.添加零包处理 4.3 增加复位恢复机制 4.4 增加批量输出 批量输出 URB 的数量和容量 的数量和容量 4.5 内核配置与编译 5 QM500U-CN拨号&#xff08;在开…...

【JavaWeb】MySQL基础操作

1 通用语法规则 SQL语句可以单行或者多行书写&#xff0c;以分号结尾SQL语句不区分大小写&#xff0c;关键字建议使用大写单行注释 --注释内容&#xff08;通用&#xff09; # 注释内容&#xff08;MySQL独有&#xff09;多行注释 /* 注释内容 */ 2 语句 数据库 -- 查…...

【Tool】虚拟机安装与调试与设置与主机共享文件

前言 安装了vm17&#xff0c;实现了与主机文件共享&#xff0c; 步骤 下载虚拟机&#xff08;试用版&#xff09; Download VMware Workstation Pro 双击安装 暂不激活或者 使用如下激活码 KRNJX-22GXY-HCW46-MWYHY-YWRDB RDHTN-YFFKY-8YVR7-Q996Y-K74X3 N2XRH-GCH84-MV…...

Spring中的接口使用

技术主题 在我们的项目中,经常会使用一些注解,注解带给我们代码简洁,本质是用于在代码中添加元数据信息,从而实现更加灵活、高效和可维护的代码结构。 技术原理 注解一@Target(ElementType.TYPE) 这个注解表示被它修饰的注解可以应用在类、接口、枚举等类型上。换句话说…...

爬虫017_urllib库_get请求的quote方法_urlencode方法_---python工作笔记036

按行来看get请求方式 比如这个地址 上面这个地址复制粘贴过来以后 可以看到周杰伦变成了一堆的Unicode编码了 所以这个时候我们看,我们说https这里,用了UA反爬,所以这里 我们构建一个自定义的Request对象,里面要包含Us...

Http、SSE、Websocket的区别

从传输方向上看 http是客户端发送请求&#xff0c;然后服务端进行响应的单向通道网络传输协议&#xff1b; SSE&#xff08; Server-sent Events &#xff09;则相反&#xff0c;只能是服务器向客户端发送消息&#xff0c;如果客户端需要向服务器发送消息&#xff0c;则需要一…...

【资料分享】全志科技T507工业核心板硬件说明书(一)

目 录 前言 1硬件资源 1.1CPU 1.2ROM 1.3RAM 1.4时钟系统 1.5电源 1.6LED...

JavaScript类

JavaScript 类(class) 类是用于创建对象的模板。 我们使用 class 关键字来创建一个类&#xff0c;类体在一对大括号 {} 中&#xff0c;我们可以在大括号 {} 中定义类成员的位置&#xff0c;如方法或构造函数。 每个类中包含了一个特殊的方法 constructor()&#xff0c;它是类…...

One-4-All: Neural Potential Fields for Embodied Navigation 论文阅读

论文信息 题目&#xff1a;One-4-All: Neural Potential Fields for Embodied Navigation 作者&#xff1a;Sacha Morin, Miguel Saavedra-Ruiz 来源&#xff1a;arXiv 时间&#xff1a;2023 Abstract 现实世界的导航可能需要使用高维 RGB 图像进行长视野规划&#xff0c;这…...

【ES】笔记-函数参数默认值

函数参数默认值 ES6 允许给函数参数赋值初始值 1. 形参初始值 具有默认值的参数&#xff0c;一般放到最后 function add(a,b,c10){return abc}let resultadd(1,2);console.log(result);2. 与解构赋值结合 function connect({host"127.0.0.1",username,password,port…...

安装harbor

目录 1. 安装docker-compose Compose 项目是 Docker 官方的开源项目&#xff0c;负责实现对 Docker 容器集群的快速编排。使用前面介绍的Dockerfile我们很容易定义一个单独的应用容器。然而在日常开发工作中&#xff0c;经常会碰到需要多个容器相互配合来完成某项任务的情况。例…...

kube-prometheus 使用 blackbox-exporter 进行icmp 监控

安装kube-prometheus 后默认在monitoring namespace中有创建 blackbox-exporter deployment。但默认没有icmp的module配置&#xff0c;无法执行ping探测。因为即使有icmp module&#xff0c;默认配置也是无法执行ping探测的&#xff08;这篇文章要解决的就是这个问题&#xff0…...

【python技巧】文本文件的读写操作

【python技巧】文本文件的读写操作 0. 背景1. file库的文件操作1.1 打开文件---file.open()1.2 读取文件---file.read()1.3 写入文件---file.write()1.4 查找内容---file.seek() 2. re库的文本处理参考资料 0. 背景 最近在写后端接口的时候&#xff0c;需要对.c、.conf等类型的…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

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

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

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...