赞
踩
以*.hex为后缀的文件我们称之为HEX文件。hex是intel规定的标准,hex的全称是Intel HEX,此类文件通常用于传输将被存于ROM或EEPROM中的程序和数据。是由一行行符合Intel HEX文件格式的文本所构成的ASCII文本文件。
HEX的英语原始意思是16进制。这种文件格式主要用于保存单片机固件。
整个文件以行为单位,每行以冒号开头,内容全部为16进制码,2个ASCII码字符表示1个Hex字节
下面转自文章,如有侵权请联系作者删除
https://blog.csdn.net/little_grapes/article/details/128497777
先上图:这是我用Notepad++ 直接打开的一个32bit的单片机编译器编译的一个hex文件(中间省略了部分):
我们解释一下文件的内容:
a)hex文件内部是以文本格式来存储内容的,每行以冒号(:)起始,后面每两个字母是一个8bit的16进制数;
b)每行的格式:BBAAAATTD……DCC;
BB表示本行数据的长度;AAAA表示本行数据存储的地址;TT表示数据类型;DD的长度可长可短,是实际的数据;CC是校验和;
我们以第一行为例:020000040800F2
02是数据长度,也就是后面的实际数据“0800”的长度,2字节;
0000表示地址0;
04是数据类型,后面在详细解释;
0800是实际的数据;
F2是校验和,计算方法是,本行所有字节累加和(累加和只用低8位)取反再加1,即计算过程为0xF2=0x01 + not(0x02+0x04+0x08);
c)这里需要补充说明的是TT表示的数据类型
数据类型一共有6种形式:
'00’数据记录:用来记录数据,HEX文件的大部分记录都是数据记录;
'01’文件结束记录:用来标识文件结束,放在文件的最后,标识HEX文件的结尾;
'02’扩展段地址记录:用来标识扩展段地址的记录;
'03’开始段地址记录:开始段地址记录;
'04’扩展线性地址记录:用来标识扩展线性地址的记录;
'05’开始线性地址记录:开始线性地址记录;
这里仍然举几个例子说明,第一行:020000040800F2的数据类型是04,即扩展线性地址记录,表示的是这样一行的内容是地址的高位,也即DD区域表示地址高位为0x0800;当地址长度超过16bit时,就需要扩展线性地址记录来声明高位地址;
第二行10000000000400200900000800F009F800F01CF8C6,数据类型是00,也就是数据记录,那么它的DD区域就是数据;同时,它的地址区域是0000,那么就表示,这一行的数据应该存在0000地址中;再结合上一行的扩展线性地址记录,它实际存储的地址应该是0x08000000。熟悉stm32单片机的朋友可能清楚,flash起始地址就是0x08000000:
第三行1000100000F026F800F01EF800F022F8F6E703B52D,格式与第二行一样,但是地址不同,表示这一行的数据存在0x08000010地址中;我们发现这两地址相隔0x10,刚好是第一行的数据内容实际长度。
倒数第三行,格式与第二、三行也是一样的,只是长度不足0x10,只有0x08,这是已经到了实际内容的末尾。
Hex文件内大部分都是这种数据记录。
d)最后两行
:0400000508000009E6
:00000001FF
我们先解释末尾一行,:00000001FF,这行是表示文件结尾,所有的hex文件最后一行都可以是这个。
倒数第二行,数据类型是05,开始线性地址记录,其实它表示的是一个函数入口地址,但是这个函数地址并不会影响实际烧写到flash中的内容,我们可以不管它,MDK官方的解释是大多数情况下可以忽略它:
The Start Linear Address specifies the address of the __main (pre-main) function but not the address of the startup code which usually calls __main after calling SystemInit(). An odd linear start address specifies that __main is compiled for the Thumb instruction set.
The Start Linear Address Record can appear anywhere in hex file. In most cases this record can be ignored because it does not contain information which is needed to program flash memory.
到这里,hex文件中常见的一些格式就介绍完了,如果需要研究更深入,可以通过http://www.keil.com/support/docs/1584/
找到keil官方的解析(这个链接好像已经404了,可以在文末关注公众号找到保存的原文档)。
我们在做有IAP功能的项目时,有时需要把boot和app两段代码合并以后烧写,这样可以大大简化操作步骤,此时,可以把两个hex文件手动合并。
操作方法是,把其中一个hex文件最后的两行(开始线性地址记录、文件结束记录)删除:
再把另一个hex文件的所有内容都复制粘贴到其后,就可以了。
但是要注意,两个文件的地址区不能有重叠!
相比hex文件,bin文件格式就简单得多了,它直接就是保存的需要烧写的目标文件内容,是没有任何附加格式的原始二进制文件。
我们把上一个工程设置为输出bin文件:
再编译输出,可以同时输出bin格式的目标文件。
使用十六进制文件编辑器打开,可以看到如下内容:
对比之前的hex文件格式,发现这些内容正好对应了hex文件中所有“数据记录”行中的实际数据内容。没有地址、校验、文件结尾等等一些附加内容。
从几个方面来看待它们的不同。
HEX文件格式,看文章前一节已经详细讲解了。
BIN文件格式,对二进制文件而言,其实没有”格式”。文件只是包括了纯粹的二进制数据。
Bin文件是MCU固件烧写的最终形式,也就是说芯片ROM中烧写的内容完全就是Bin文件的内容。
HEX文件是包括地址信息的,而BIN文件格式只包括了数据本身。在烧写或下载HEX文件的时候,一般都不需要用户指定地址,因为HEX文件内部的信息已经包括了地址。而烧写BIN文件的时候,用户是一定需要指定烧录的起始地址信息的。
HEX文件是用ASCII来表示二进制的数值。例如一般8BIT的二进制数值0x3F,用ASCII来表示就需要分别表示字符’3’和字符’F’,每个字符需要一个BYTE,所以对比同一个工程编译出来的HEX文件和BIN文件,HEX文件至少是BIN文件大小的两倍以上。
上面两张图分别以文本形式查看一个hex文件,以及使用十六进制形式查看该hex文件,可以更明显得看出:
hex文件是以ASCII码形式保存下来的。比如0x3a对应字符’:',0x30 0x32 0x30 0x30 对应字符0200,并且每行的末尾用了0D 0A进行回车换行。
对一个BIN文件而言,你查看文件的大小就可以知道文件包括的数据的实际大小。而对HEX文件而言,你看到的文件大小并不是实际的数据的大小。一是因为HEX文件是用ASCII来表示数据,二是因为HEX文件本身还包括别的附加信息。
通过前述的解释,我们了解了,bin文件只有最原始的程序数据,它与保存在单片机flash中的原始值是一样的;hex文件中,则除了程序数据外,还包含了地址、校验等等一些信息。
所以,一般在自己设计IAP程序时,直接传输bin文件可以简化bootloader软件的设计,减少一些处理过程,缩小boot程序的体积,但是要注意需要事先规定写入的地址;而通过上位机软件和下载器烧写时,使用hex文件,可以简化操作、增加可靠性。
一般软件IDE都可以生成hex文件,有的也能生成bin文件,如上文中提到的keil;st公司出品的STM32CubeProgrammer也可以将hex转bin。
如果软件没有这个功能,我们也不用重复造轮子,有很多前辈大佬已经做了转换工具,我们可以使用现成的。
我试用了多种,选了比较好用的一种hex转bin文件工具推荐给大家:
这个软件由“不咸不要钱”大佬编写,该大佬的软件开源地址:GitHub - mian2018/CSharp_Hex2Bin: 嵌入式 hex转bin
下面转自文章,如有侵权请联系作者删除https://blog.csdn.net/he__yuan/article/details/78036073
之前一直以为STM32flash空间大小和hex文件
相关,以为hex文件大小超过flas大小后程序就会
出问题但是我发现hex文件大于flash也可以正常
下载,有的程序也可以正常运行,有的不可以,所
以经过总结如下:
1、flhex文件其实是个格式规范的文本文件。程序代码大小与hex文件大小没有绝对的关联性,因为我们在用串口下载程序时一般都是用的hex文件下载,,所以大家会以为hex文件大小和flash大小息息相关,hex文件大小超过了flash大小就会出问题,我也以为是这样,直到最近我发现有hex文件大于flash的大小但是依然可以写进去,因为真正烧写进去的是二进制文件,在hex文件中包含了bin文件的信息
2、hex文件大小和bin文件大小没有决定性关系hex文件内容很多,其中就包含了bin文件二进制的内容,所有很多软件都能直接把hex文件转化成bin文件,烧写进flash的文件不是hex而是一堆bin文件
3、flash大小和bin文件大小息息相关
bin文件就是完全的程序文件,里面包含了所有的程序
内容,bin文件烧写进flash就可以执行,可以用STlink进入仿真查看相关的flash,就是bin文件内容
把单片机当做一个存储器,每一条程序指令都对应一个唯一的存储地址,把这些指令以字节为单位一条条存储到指定的存储地址中,这就是烧录程序的本质。对于STC89C52RC单片机,在下载程序时需要上位机软件和一根USB转串口线。上位机软件负责把.hex格式的机器码文件打开,机器码文件里面记录着每条程序指令所对应的地址信息,下载过程时,上位机软件根据.hex文件记录的指令内容和对应的地址信息,经过USB转串口线,跟单片机的预置系统程序进行串口通讯,从而把.hex记录的信息传输到单片机内部的flash存储器中,实现了程序的烧录下载。
可以配置IAR或Keil,用IDE下载。硬件工具需要使用ST-Link(分为SWD或Jtag方式,SWD连线少,比较常用于调试)或J-Link连接到板子的相应引脚(详见Jtag引脚定义)。需要注意的是ST-Link烧录盒分为隔离和非隔离,如果板子必须断电烧录,那么用非隔离的烧录(这个时候烧录器也会带电让STM32运行,某些DSP需要单独供电),如果板子需要上电烧录或在线调试,一般使用带隔离的ST-Link或JLink。
2. 用ST-LINK Utility工具烧录
下载HEX文件,设置好地址后,可以下载app(如果是STM32,那么起始地址一般是0x0800xxxx)和bootloader(如果是STM32,那么起始地址一般是0x08000000)。这个工具大概作用总结如下:
由于单片机发展到今天已经非常成熟了,如果我们想要了解程序下载这个一直都有讨论的命题,我觉得可以从其历史发展来看。
1 编程器编程
首先需要明确的是,单片机程序下载的本质就是将由0和1组成的hex文件写入到掉电数据不会消失的EEPROM(Electrically Erasable Programmable Read Only Memory,电可擦除可编程只读存储器)中。 最早使用的烧录程序的方式是使用单独的编程器,据说价格比较昂贵,而且每次编程时都需要把可编程芯片取下来放在编程器上,然后再写入程序。【似乎知道为什么现在普遍使用的51单片机最小系统板是用一个夹紧的绿色底座而不是接触更好的双列直插的芯片插座,估计就是历史遗留问题】
这里的编程器是电擦除的,据说更早还有紫外线擦除的,应该是匹配EPROM。
显然,这种烧录程序的方式一个是价格昂贵,意味着你每开发一款芯片,都需要先买一个可能比单片机还贵的编程器;另一方面就是这种编程方式意味着你每改动一次程序都需要拆装一次,不仅麻烦还会对电路板造成损伤,而且如果是成型的产品需要升级程序,还需要返厂或者让技术人员到现场解决,非常不便。于是后来就有了ISP。
2 ISP (In System Programming, 系统在线编程)
所谓ISP,即In System Programming,有些人翻译成“在系统中编程”,确实也有道理,因为原来的编程方式需要将芯片取下,即离开系统,而ISP不需要编程器即可完成程序烧录,此时单片机芯片可以焊在电路板上,调试完即是成品。但我比较喜欢另一种解释,那就是用编程器编程属于离线编程,而ISP属于在线编程,这个“线”大概就是指系统,到底有没有离开系统。因此个人觉得这个翻译成系统在线编程最为合适。
ISP基本是目前单片机烧录程序的主要方式。它的实现方式就是通过电脑端的上位机软件,通过某种数据传输协议,将程序编译产生的二进制文件烧录到单片机的EEPROM中。一般电路板上还需要添加少量的外围电路辅助程序的烧录。因此调试单片机程序时,只需要将相关的接口留出即可,而不需要来回取下芯片。
其中,因为对烧录速度和质量的要求,人们在 “某种数据传输协议” 上不断更新,因此也就有了各种不同的烧录方式。如STC的51单片机基于的就是串口协议,即程序通过串口写入到FLASH(EEPROM的一种)中;Atmel的AT89S51,AT89S52等系列单片机基于SPI协议将程序写入到FLASH中;STM32系列的芯片采用ST-Link和J-Link等设备来下载程序,其基于的协议为SWD和JTAG,当然,STM32也可以基于串口协议下载程序;Arduino单片机可以通过串口协议下载程序,也可以通过SPI协议下载(算是AVR单片机一个独有的特点吧)。
但是虽然大家都是ISP,但各自还是有区别的。
其中最为特殊的莫过于串口协议,因为其他的各种协议都是借助外界设备(如ST-Link、USBasp)来直接操作单片机的FLASH,而通过串口下载程序时,虽然也需要使用外部设备(一般是一个USB转TTL模块),但是其本质还是靠芯片内部已固化的一段程序来写入FALSH。
这也就是为什么网上很多资料都把串口下载称之为ISP,而基于其他协议下载的都不叫ISP。
另外,对于某些单片机,支持ISP模式烧写程序的协议可能不止串口协议,或者说不止一个通讯接口。如STM32F4支持多个串口写入和CAN协议【参考链接第二个】
用来写入FLASH的这部分程序是芯片出厂就已经固化到芯片当中的,称为引导程序,也叫自举程序(自己能举起自己嘛),英文名叫BootLoader。这部分程序是对用户保密的,也就是说用户无法知道这段程序到底是怎么写入FLASH的,只知道它能这么做。
因此,为实现这种功能,芯片内部ROM就可以分为两部分,一部分是系统存储区 (System Flash),一般在低地址,用来存放引导程序;另一部分是用户存储区(User Flash),有些也称为应用程序区(Application Flash),一般在高地址,用来存放用户编写的程序(主要执行的部分)。其示意图如下所示。
以STM32为例,由于它既支持SWD,JTAG这种直接操作FLASH的协议,也支持基于串口协议利用引导程序写入FLASH,因此它需要支持多种启动模式。如下图所示。
这里的“主闪存存储器”即上面提到的用户存储区,用来存放用户编写的程序。
所以,显而易见,如果手边有ST-Link或J-Link,就可以考虑从用户存储区开始运行,这样上位机就直接将数据写入到用户存储区的FLASH中;如果要采用串口下载,就需要从系统存储区开始启动,当芯片在这个部分开始执行程序时,会不断检测串口是否有写入FLASH的指令,如果没有,则开始执行后面的用户程序,如果有,则开始写入用户存储区的FLASH。
但是,一般串口下载要更慢,而且ST-Link或J-Link除了下载程序外,还支持硬件仿真,这也就是为什么用串口下载的比较少。
为了更好地了解这个过程,下面以STC单片机为例来展示这个过程。【图片来自官网手册】
这里值得注意的是,STC单片机对于从系统存储区启动有一个特别的要求,那就是冷启动,即单片机彻底没电(给2-3V供电也不行)。这个时候上电单片机才会执行ISP程序(一般按下RST单片机不会执行ISP程序,只是从头开始执行用户程序),检测是否有烧入程序的需求。
还有一种单独给STC单片机烧录的设备,不用冷启动就能烧录程序,我只知道它大概是通过软件复位到系统存储区去执行ISP程序(这个功能STC已提供,而且应该是独有的),但具体原理还不太明白。(为什么那个下载器能在芯片运行过程中修改芯片内部寄存器的数值呢?)
说了这么多ISP,感觉基本够用了,为什么还会有IAP呢?这个主要是用于一些特殊的情况,比如一个产品内程序的远程升级。
和上面的ISP一样,IAP也有翻译成“在应用中编程”,这个也有其合理性,但是个人感觉“应用在线编程”会更形象点,这个“线”就不是指系统了,而是指芯片正在执行应用程序,在这个过程中实现程序的自我更新,此即IAP的原理。也正是这种特殊操作,能够实现对一个已开发的产品进行远程的程序升级。
咋一看似乎感觉IAP和ISP差不多? 确实如此。因为ISP也是支持程序正在运行时执行程序烧录的指令的(STM32的串口下载和STC单片机的热启动),其原理和上面提到是一样的,那就是内部有相关的寄存器能够进行复位操作使得程序从ISP区开始执行,然后检测是否有烧录的操作。这样看来似乎IAP也差不多是这个需求,但是前面也提到,一般芯片出厂的时候,ISP程序是已固化到芯片当中的,关键它还是对用户保密的,所以对于使用这个芯片开发产品的开发者来说,是不知道这个芯片到底是怎么将程序烧录到用户FLASH中的,所以就不能通过ISP来实现需要的功能,而需要根据芯片提供的一些函数自定义一套协议和规范来写入FLASH从而实现IAP,因此,就还需要一块类似于存放ISP程序的区域的存放IAP程序的区域,如下图所示。【图片来自参考链接的第二个】
从上图可知,ISP程序引导加载IAP程序,IAP程序引导加载应用程序。在开发者开发产品时,IAP程序必须通过SWD、JTAG或者ISP(串口or其他协议)烧录,第二部分应用程序可以在第一部分烧录时一起烧录,也可以通过IAP程序烧录。
那在程序运行过程中,也就是正在执行应用程序时,是怎么跳转到IAP程序部分执行的呢?STM32中是采用中断的方式。一般中断向量都是存放在低地址,而IAP恰好在低地址段,所以IAP程序就相当于是一个中断服务程序,当相关中断被触发时,芯片就开始执行IAP程序,来进行自我更新。因此,在第二部分代码开始执行时,首先需要把CPU的中断向量表映像到自己的向量表,然后再执行其他的操作。
如果IAP程序被破坏,产品必须返厂才能重新烧写程序,这是很麻烦并且非常耗费时间和金钱的。针对这样的需求,STM32在对Flash区域实行读保护的同时,自动地对用户Flash区的开始4页设置为写保护,这样可以有效地保证IAP程序(第一部分代码)区域不会被意外地破坏。
1 ICP
ICP全称是In Circuit Programming,即在电路中编程,这个我感觉应该是和ISP是一个意思,因为芯片所在的系统不就是电路系统吗?不需要离开电路就能对芯片进行编程,感觉和ISP是一个意思,有些型号的芯片之所以区分这两者估计是使用的协议不同。
2 ICSP
ICSP全称是In Circuit Serial Programming,这个一般的翻译是在线串行编程,这个主要是出现在Arduino中,上面有六个引脚,也可能用来下载程序。其实这个算是AVR单片机的一个特性,其本质是通过SPI协议来写入程序,和AT89S52的烧录方式差不多(虽然一个是10引脚,一个是6引脚)。
但是值得一提的是,Arduino如果采用ICSP的方式烧录程序,那么它还是会从FLASH的起始地址开始烧录,也就是说会覆盖掉低地址段的引导程序!!! 这一点个人感觉很不合理。因此,如果要转为使用串口下载,需要在IDE中再次烧录引导程序。如下图所示。
在描述单片机程序时,需要区分“运行时”和“非运行时”
原文链接:https://blog.csdn.net/qq_28877125/article/details/108662427
非运行时的单片机程序在ROM内的分布
下图就是通过单片机下载工具烧录到单片机Flash里面去之后的Flash空间区域分布图:
其中:
Code:为程序代码部分
Ro-data: 表示程序定义的常量(const修饰的常量、#define 宏定义等);
Rw-data: 表示已初始化的全局变量
Zi-data: 表示未初始化的全局变量(Zi-data可以表示RAM未上电时整个区域的状态,或者上电初始化之后未被使用的区域,上表仅仅描述的是ROM区域的空间分布)
而栈区(stack)、堆区(heap)、全局区(静态区)(static)、文字常量区和程序代码区和上面所介绍的Code、Ro-data等的关系。
1、栈区(stack):由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 这些值是可读写的,那么stack应该被包含在RW-data(读写数据存储区),也就是单片机的sram中。
2、堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。可以理解,这些也是被包含在单片机的sram中的。
3、全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后由系统释放。这些数据也是可读可写的,和stack、heap一样,被包含在RAM中。
4、文字常量区:常量字符串就是放在这里的。这些数据是只读的,分配在Ro-data(只读数据存储区),则被包含在flash中。
5、程序代码区:存放函数体的二进制代码,可以想象也是被包含在flash,因为对于MCU来说,当其重新上电,代码还会继续运行,并不会消失,所以存储在flash中。
下图是初始化之前的ROM和RAM中的数据分布:
1、未初始化之前的RAM里面所有区域都是随机的值即:Zi-data
下图是初始化之后的ROM和RAM中的数据分布:
1、初始化的时候会由Boot程序(进入main函数之前)拷贝Flash里面的Rw-data区域到RAM
下图是初始化之后正常运行时,单片机内ROM和RAM区域分布图:
上电初始化之后Flash的Rw-data就不会再使用了,除非重新上电、复位了boot才会重新从ROM(Flash)中拷贝Rw-data区域到RAM中去。
运行时,根据上一节对哈佛模型的描述(51内核、Cortex-M3、Cortex-M4是哈佛模型),程序存储区对应ROM(Flash)数据存储区对应RAM,如此这般两个区域就是物理上的分开的–经典的哈佛模型。
哈哈我就不转载了,放个链接
https://www.dianyuan.com/eestar/article-3676.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。