STM32的hex文件格式的分析

本文详细解析了STM32的HEX文件格式,包括基地址、数据记录、校验和等关键信息,并介绍了如何处理大于64KB的HEX文件。
                                                      STM32的hex文件格式的分析

日常开发工作中hex文件是经常要接触到的一种文件格式,就算平时你的开发是各种link直接下载,但如果你的项目批量量产了,那么一种生成文件(.bin或hex…)交给生产部门或是你的终端产品需要支持远程升级交给平台工程师那么是不可避免要接触到的。所以还是要必须了解的。

下面开始结合stm32分析hex的文件格式:
官方定义:
<0x3a>[数据长度1Byte][数据地址2Byte][数据类型1Byte][数据nByte][校验1Byte]<0x0d><0x0a>
打开一个stm32生成的hex文件:
在这里插入图片描述
1)结合格式分析第一行(指定基地址)
:020000040800F2
断句
: 02 0000 04 0800 F2

我们已经按格式说明分割开

“:” 对应格式中的<0x3a>,0x3a就是冒号的ASCII码

“02”对应的就是长度,这里就如所见,就是长度为2

“0000”对应数据地址,长度为2个字节。Stm32一个32位的芯片两个字节肯定不足以表示地址(要四个),所以这里地址的具体用法要结合后面的数据类型分析。这里为4指定基地址,所以这两个字节并没有什么用。

“04”对应的数据类型,具体的含义见【注释1】,这里的4是指定基地址。

“0800”对应的是数据,长度是浮动的,这里是2个字节,和前面的长度相呼应。这里指定的是基地址。当然指定的是高16的地址,如常见的0x0800 0000 ,所以这个基地址<<16使用。

“F2”对应的是校验结果,result = 256 - (date[0] + … +date[n])% 256 ,这一行数据比较少,我就给大家带入一下 0xF2 = 0x100 - (0x02 +0x00 + 0x00 + 0x04 + 0x08 + 0x00)%0x100。
校验范围大家都看见了,是从长度到数据结束字节的这么一个范围,不少同学以为只是校验数据段,那是错误的,你的意思是长度和类型不重要可以存储出错吗?

“”对应<0x0d><0x0a>,就是回车和换行,这个东西大家应该很熟悉,因为stm32串口发送例程中,串口数据的结束用的就是这两个符号做标识。

2)结合格式分析第二行(数据)
第二行开始到文件快结束的绝大部分内容都是对应的数据,我个人认为就相当于bin文件中所携带的内容,其他例如基地址,文件起始,文件结束等内容是hex文件才有的附加信息。这里我只是试着分析一下其特殊部分,和第一行中相同且没变化的部分就不再赘述了。

:10000000600700200D0C0008050400080704000824
断句:
:10 0000 00 60 07 00 20 0D 0C 00 08 05 04 00 08 07 04 00 08 24

“10”对应数据长度16,即60 07 00 20 0D 0C 00 08 05 04 00 08 07 04 00 08这16个字节。

“0000”对应地址,这里类型是数据,准确的说是低16位,高十六位由第一行的04基地址类型指定,上面指定的是0800 这里指定的是0000,那么后面的16个字节的目标位置就是addr = 0x800 << 16 + 0x0000, 就是0x0800 0000,是不是很熟悉?不熟悉的看下图,帮助回忆一下
在这里插入图片描述
我修改一下给大家看一看。
修改为0x0800 1000:
在这里插入图片描述
再来看一下生成的hex文件,上图为0x800 0000 下图为0x800 1000
在这里插入图片描述
在这里插入图片描述
大家看到了,数据类型(0)中的地址都改变了,比原来大了0x1000,当然数据段中有绝对地址还有hex文件校验数据也都会因为这个数据的修改有所改变。

“600700200D0C00080504000807040008”对应的是数据,这里的数据也就是我们实实在在要写入到产品flash中的东西,这里我放一张同一工程中bin文件,大家对比着看一下就清楚多了。
hex文件数据
在这里插入图片描述
3)分析最后两行(入口地址和文件结束)
在这里插入图片描述
顾名思义,我没有什么好说的了,对这块也没什么体会,就不赘述了。以后如果发现这里有什么知识点我再补充。水平有限,如有疏漏差错还请见谅

【20190407补充】
每行数据的地址是两个字节,可以携带64K的数据,但是如果生成的hex准确的说bin数据大于64k,这时候hex会有如何的变化呢,我用内联函数扩大了生成文件的大小,让生成hex远大于64K,结果hex文件的处理如下图所示:

在这里插入图片描述
我们看到了,是重新的指定了基地址,新开辟了64K字节的空间,00类型中的数据的<地址>又开始由0000开始累加了,当我们日常自己要处理hex文件,例如自己写离线下载上位机程序,或是IAP目标板程序,这一点要明确,基地址不仅是只会有一条。

【注释1】
‘00’ Data Record 数据
‘01’ End of File Record 文件结束标志
‘02’ Extended Segment Address Record 延伸段地址
‘03’ Start Segment Address Record 起始延伸地址
‘04’ Extended Linear Address Record 扩展线性地址 也就是基地址
‘05’ Start Linear Address Record 程序起始地址也就是程序入口地址(main)

<think>我们正在处理一个关于解析STM32HEX文件的问题。用户提供了一个HEX文件行示例:"020000042000DA"。根据引用[1]和引用[2],HEX文件包含地址和数据信息,每行有特定格式。HEX文件格式解析(基于IntelHEX格式):-每行以冒号(:)开始。-接下来两个字符是数据长度(字节数)。-接着四个字符是地址(偏移地址)。-然后两个字符是记录类型(00:数据记录,01:结束记录,02:扩展段地址记录,03:开始段地址记录,04:扩展线性地址记录等)。-之后是数据(字节数由数据长度指定)。-最后两个字符是校验和。示例行解析:":020000042000DA"-起始符::(已省略,但通常每行以冒号开始)-数据长度:02->2个字节-地址:0000->地址为0x0000(偏移地址)-记录类型:04->扩展线性地址记录(用于32位地址)-数据:2000->扩展线性地址的高16位(0x2000),因此线性地址为0x2000<<16=0x20000000(这是STM32Flash的起始地址之一)-校验和:DA扩展线性地址记录(类型04)的含义:它提供后续数据记录的高16位地址(即基地址)。后续的数据记录中的地址都是偏移地址,需要与这个基地址组合形成完整的32位地址。组合方式:完整的32位地址=(扩展线性地址<<16)+偏移地址在这个例子中,扩展线性地址为0x2000,偏移地址为0x0000,所以完整地址为0x20000000。注意,这个记录本身并不包含实际数据,而是为后续的数据记录设置基地址。校验和计算:从数据长度到数据结束的所有字节(两个字符为一个字节)的和的模256的补码(即:校验和=0x100-(summod0x100)),然后取低8位。计算示例行:02+00+00+04+20+00=0x02+0x00+0x00+0x04+0x20+0x00=0x26校验和=0x100-0x26=0xDA(正确)因此,这一行记录的意思是:设置后续数据记录的基地址为0x20000000。在解析HEX文件时,我们需要记录当前的扩展线性地址(如果有的话),然后对于每个数据记录(类型00),将其偏移地址加上当前的扩展线性地址(左移16位)得到完整地址。用户的需求是提取地址和数据,并输出为“地址:数据”的格式。注意,扩展线性地址记录(04)本身没有数据(这里的数据字段实际上是地址的高16位),所以不需要输出为数据记录。而数据记录(类型00)才需要输出。因此,对于数据记录,我们输出完整地址(32位)和对应的数据(十六进制字符串)。步骤:1.逐行读取HEX文件。2.解析每一行:数据长度、地址、记录类型、数据、校验和。3.如果记录类型是04(扩展线性地址记录),则更新当前基地址(将数据字段解析为16位数,然后左移16位)。4.如果记录类型是00(数据记录),则计算完整地址=当前基地址+偏移地址(解析的地址字段)。然后将数据字段按字节分割(每两个字符一个字节),并输出为“完整地址:数据”(数据可以表示为连续的十六进制字符串,也可以按字节用空格分隔,但用户示例要求是“地址:数据”,且每行对应一个记录行?注意:一个数据记录可能包含多个字节,但用户示例中每行一个地址对应一个数据?实际上,一个记录行可能有多个数据字节,每个字节有连续的地址。因此,我们需要将每个字节的地址都输出?还是整个记录行输出一行?根据需求,应该是每个数据记录行输出一行,格式为“起始地址:该记录行的所有数据(按顺序)”。根据引用[1]中的描述:“每行的数据格式为:地址:数据”,这里的数据应该是该地址开始的一系列字节。因此,一个记录行输出一行,地址为该记录行的起始地址(完整地址),数据为连续的十六进制字符串(不带空格)或按字节用空格分隔?但示例没有给出具体格式。我们可以参考常见做法:将数据按字节连续排列(每两个字符一个字节)形成一个字符串,例如“01020304”。但注意:HEX文件中一个记录行可能包含多个字节(最多255个字节),所以地址是连续的。输出时,我们可以输出起始地址,然后输出该行所有数据(作为一个连续的字符串,或者按字节用空格分隔)。根据需求描述,我们输出为“地址:数据”,其中数据为连续的十六进制字符串(无空格)即可,因为后续可能需要按地址写入,每个地址对应一个字节,但这里一个记录行包含多个字节,所以地址是起始地址,数据是多个字节的连续表示。例如,一个数据记录行::1024620048595F475245415420535441434B21EA-数据长度:0x10(16字节)-地址:0x2462(偏移地址)-类型:00(数据)-数据:48595F475245415420535441434B21(16字节)-校验和:EA假设当前基地址为0x20000000,则完整起始地址为0x20002462,输出为:20002462:48595F475245415420535441434B21但注意:数据部分在HEX文件中是十六进制ASCII表示,每个字节用两个字符表示,所以直接拼接即可。另外,结束记录(类型01)不需要输出。所以,解析程序的大致逻辑:-初始化当前基地址为0(如果没有扩展线性地址记录,则基地址为0)-逐行处理:-去掉行首的冒号(如果有的话,有时读取时可能已经去掉)-解析数据长度(1字节)-解析偏移地址(2字节)-解析记录类型(1字节)-解析数据(长度为数据长度*2个字符)-解析校验和(1字节)-计算校验和(可选,用于验证)-根据记录类型:-04:更新基地址=(解析数据字段得到的16位值)<<16-00:计算完整地址=基地址+偏移地址,然后输出“完整地址(8位十六进制):数据字符串(连续)”-01:结束,停止-其他类型:根据需求,可能不需要处理(如02,03等,但常见的是04和00)注意:一个HEX文件中可能有多个扩展线性地址记录,所以每次遇到04记录都要更新基地址。用户提供的示例行是扩展线性地址记录,所以不输出数据,只更新基地址。现在,我们根据用户需求,编写解析程序(使用Python)的伪代码或代码框架。代码步骤:1.打开hex文件,读取每一行。2.初始化变量:base_address=03.对每一行:-去掉行首的冒号(如果有)和行尾的换行符。-检查行是否为空。-提取:byte_count=int(line[0:2],16)#两个字符address=int(line[2:6],16)#四个字符record_type=int(line[6:8],16)#两个字符data=line[8:8+2*byte_count]#数据部分,长度为2*byte_count个字符checksum=int(line[8+2*byte_count:8+2*byte_count+2],16)-可选:验证校验和(将这一行所有字节加起来,包括byte_count,address,record_type,data等,然后取低8位,计算校验和是否匹配)-根据record_type处理:ifrecord_type==0x00:#数据记录full_address=base_address+address#输出full_address和data#格式:full_address的8位十六进制(前面补0):data#例如:full_address_hex="{:08X}".format(full_address)#然后写入输出文件:full_address_hex+":"+data+"\n"elifrecord_type==0x04:#扩展线性地址记录#数据字段是两个字节(4个字符),例如"2000"base_address=int(data,16)<<16#更新基地址elifrecord_type==0x01:#结束记录break#或者跳过,通常结束记录在最后else:#其他记录类型,如02,03等,这里忽略(不输出数据)pass4.将解析结果写入output.txt文件。注意:HEX文件中的地址是字节地址,而STM32的Flash编程也是按字节的,所以直接使用。下面我们根据用户示例行进行测试:":020000042000DA"解析:byte_count=0x02->2address=0x0000record_type=0x04data="2000"->2个字节(0x20和0x00,但组合成16位值0x2000)校验和=0xDA处理:更新base_address=0x2000<<16=0x20000000然后后续的数据记录行,其偏移地址加上0x20000000就是完整地址。现在,我们编写一个Python脚本来实现这个解析。注意:用户要求输出到output.txt,每行格式:地址(8位十六进制,大写):数据(连续的十六进制字符串,大写)示例代码:</think>### 解析STM32 HEX文件内容 针对您提供的HEX文件行`020000042000DA`,以下是详细解析过程: #### 1. **HEX文件格式结构** HEX文件每行采用标准Intel HEX格式,结构如下: ``` :BBAAAARRDD...DDCC ``` - `:` :行起始符 - `BB` :字节数(2字符) - `AAAA` :地址(4字符) - `RR` :记录类型(2字符) - `DD...DD` :数据(长度=2×字节数) - `CC` :校验和(2字符) #### 2. **具体行解析**:`020000042000DA` - **字节数(BB)**:`02` → 2字节数据 - **地址(AAAA)**:`0000` → 偏移地址0x0000 - **记录类型(RR)**:`04` → **扩展线性地址记录** - **数据(DD)**:`2000` → 高16位地址0x2000 - **校验和(CC)**:`DA` → 验证数据完整性 #### 3. **关键信息提取** - **地址计算**: 完整32位地址 = `(数据值 << 16) + 偏移地址` 即:$0x2000 \times 2^{16} + 0x0000 = \text{0x20000000}$ - **物理意义**: 该行指定Flash操作的**基地址**为0x20000000(STM32 SRAM起始地址)[^2] - **校验验证**: 计算校验和:$\text{0x100} - (\text{0x02} + \text{0x00} + \text{0x00} + \text{0x04} + \text{0x20} + \text{0x00}) \mod \text{0x100} = \text{0xDA}$(验证通过) #### 4. **Python解析示例** ```python def parse_hex_line(line): if not line.startswith(':'): return None byte_count = int(line[1:3], 16) address = int(line[3:7], 16) record_type = int(line[7:9], 16) data = line[9:9+2*byte_count] checksum = int(line[9+2*byte_count:11+2*byte_count], 16) # 计算校验和验证 calc_sum = sum(bytes.fromhex(line[1:-2])) calc_checksum = (0x100 - (calc_sum & 0xFF)) & 0xFF if record_type == 0x04: # 扩展线性地址 base_address = int(data, 16) << 16 return f"基地址: 0x{base_address:08X}" return f"地址: 0x{base_address + address:08X}, 数据: {data}" # 测试解析 print(parse_hex_line(":020000042000DA")) # 输出: 基地址: 0x20000000 ``` #### 5. **应用场景** - **IAP编程**:HEX文件包含地址信息,可实现精准烧写[^2] - **内存分析**:解析SRAM/Flash中的数据结构 - **固件调试**:验证代码实际存储位置 - **安全校验**:通过校验和检测传输错误
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值