一、SRecord文件简介
SRecord文件是由Motorola公司定义的一种ASCII文本文件,文件扩展名包括:.s19、.s28、.s37、.s、.s1、.s2、.s3、.sx、.srec、.exo、.mot、.mxt,都是同一种格式,文件内容没有差异,主要用于记录微控制器、EPROM和其他类型的可编程设备的程序记录。
二、SRecord解析格式
SRecord文件一般格式如下:
type | count | address | data | checksum |
2 Byte | 2 Byte | 4 or 6 or 8 Byte | 0~64 Byte | 2 Byte |
- type:表示该行的数据记录类型
类型字段(type) | 记录内容 | 地址字段 | 数据字段 | 记录描述 |
---|---|---|---|---|
S0 | 标题信息 | 0x0000 | √ | 1. mname is char[20] and is the module name. 2. ver is char[2] and is the version number. 3. rev is char[2] and is the revision number. 4. description is char[0-36] and is a text comment. |
S1 | 数据 | 16位地址 | √ | 该记录包含从 16 位地址字段开始的数据。该记录通常用于 8 位微控制器 |
S2 | 数据 | 24位地址 | √ | 该记录包含从 24 位地址开始的数据 |
S3 | 数据 | 32位地址 | √ | 该记录包含从 32 位地址开始的数据。该记录通常用于 32 位微控制器 |
S4 | Resverd | Resverd | × | |
S5 | 计数 | 16 位计数 | × | 此可选记录包含S1 / S2 / S3记录的 16 位计数。如果记录计数小于或等于 65,535 (0xFFFF),则使用此记录,否则将使用S6记录 |
S6 | 计数 | 24 位计数 | × | 此可选记录包含S1 / S2 / S3记录的 24 位计数。如果记录计数小于或等于 16,777,215 (0xFFFFFF),则使用此记录。如果小于 65,536 (0x010000),则将使用S5记录 |
S7 | 记录起始地址,并且终止S3记录 | 32位地址 | × | 该记录包含 32 位地址的起始执行位置。这用于终止一系列 S3 记录 |
S8 | 记录起始地址,并且终止S2记录 | 24位地址 | × | 该记录包含 24 位地址的起始执行位置。这用于终止一系列 S2 记录 |
S9 | 记录起始地址,并且终止S1记录 | 16位地址 | × | 该记录包含 16 位地址的起始执行位置。这用于终止一系列 S1 记录 |
- count:(address + data + checksum)区域的字节总数
- address:对应记录数据的起始地址信息
- data:数据内容或者描述信息
- checksum:(cout + address + data)区域的字节累加和S,保留最低有效字节,计算有效字节的补码checksum = ~(S & 0xFF) & 0xFF
(1)SRecord S0/S3/S7解析示例
S01200004B4C5F333030395F4150502E733139E0
S30B100693F00000000000005B
S30910080000FECACEFA4E
S7051006818DD6
- S0 12 0000 4B4C5F333030395F4150502E733139 E0
S0 表示记录标题信息
12 表示 addr + data + checksum 区域的字节数为12个字节
0000 固定为0000
4B4C5F333030395F4150502E733139 记录相关信息
E0 表示count + addr + data 区域的校验和为E0
- S3 09 10080000 FECACEFA 4E 表示0x10080000地址起始的数据为FECACEFA
0x10080000 | 0xFE |
0x10080001 | 0xCA |
0x10080002 | 0xCE |
0x10080003 | 0xFA |
- S7 05 1006818D D6 表示main函数的入口地址为0x1006818D,并且结束S3的记录(类似文件末尾)
(2)SRecord S0/S1/S5/S9解析
S00600004844521B
S1130000285F245F2212226A000424290008237C2A
S11300100002000800082629001853812341001813
S113002041E900084E42234300182342000824A952
S107003000144ED492
S5030004F8
S9030000FC
- S1 13 0000 285F245F2212226A000424290008237C 2A 表示0x0000起始地址的数据为285F245F2212226A000424290008237C
- S5 03 0004 F8
S5 表示记录S1/S2/S3的计数
03 表示 addr + data + checksum 区域的字节数为3个字节
0004 表示前面S1记录的数量为4个
F8 表示count + addr + data 区域的校验和为F8
累加和 S = (03 + 00 + 00 + 04)= 0x07
校验和 checksum = ~(S & 0xFF)& 0xFF = 0xF8
- S9 03 0000 FC 表示main函数的入口地址为0x0000,并且结束S1的记录(类似文件末尾)
三、SRecord解析Python代码示例
s19(SRecord)文件的内容行解析python代码示例:
def _line_analyse(self, line:str):
# string fliter
line = line.strip() # 去除开头与结尾的空格或换行符
# S19 file format
type = line[0:2]
count = int(line[2:4], 16) # addr + data + checksum
checksum = int(line[-2:], 16)
# S19 file info string dispose
# 标题类型
if (type == "S0"):
pass
# 数据类型
# ( S1: 地址段 2个字节; S2: 地址段 3个字节; S3: 地址段 4个字节)
elif (type == "S1" or\
type == "S2" or\
type == "S3"):
# 地址索引和数据索引
ADDRESS_LINE_INDEX = 4
ADDRESS_LEN = DATA_TYPE_ADDR_LEN_ENUM.get(type)
DATA_LINE_INDEX = ADDRESS_LINE_INDEX + ADDRESS_LEN
DATA_LEN = (count * 2) - ADDRESS_LEN - 2 # data = cout - addr - checksum
# 地址数据
address = int(line[ADDRESS_LINE_INDEX : ADDRESS_LINE_INDEX + ADDRESS_LEN], 16)
# 地址对应的data数据
data_hex_list = []
for i in range(DATA_LINE_INDEX, DATA_LINE_INDEX + DATA_LEN, 2):
data_hex = int(line[i : i+2], 16)
data_hex_list.append(data_hex)
# checksum 校验
# 该行所有16进制累加和S,保留最低有效字节,计算有效字节补码
checksum_temp = 0
for i in range(2, len(line) - 2, 2):
checksum_temp += int(line[i:i+2], 16)
checksum_temp = ~(checksum_temp & 0xFF) & 0xFF
# 检验checksum
if checksum_temp == checksum:
self.data_dict[address] = data_hex_list
else:
print("checksum_temp:0x{:2x}, checksum:0x{:2x}, line:{:s}".format(checksum_temp, checksum, line))
# Resverd
elif (type == "S4"):
pass
# 数据计数类型(包含S1/S2/S3的计数)
elif (type == "S5" or\
type == "S6"):
pass
# 起始地址类型
# ( S9: 终止S1记录; S8: 终止S2记录; S7: 终止S3记录)
elif (type == "S7" or\
type == "S8" or\
type == "S9"):
self.is_finished_analyse = True
# 起始地址索引与长度
MAIN_ADDRESS_INDEX = 4
MAIN_ADDRESS_ADDRESS_LEN = (count * 2) - 2 # 减去checksum长度
self.main_address = int(line[MAIN_ADDRESS_INDEX: MAIN_ADDRESS_INDEX + MAIN_ADDRESS_ADDRESS_LEN], 16)