Motorola S19(S-record)格式解析

S-Record文件格式是FreescaleCodeWarrior用于MCU编程的ASCII码格式,主要包含S0到S9类型的记录。本文详细介绍了S-record的格式结构,如记录类型、数据地址、数据和校验和等,并提供了从BIN到S19的转换工具代码实现。此外,还展示了S19到BIN的转换过程。转换工具涉及地址偏移、地址长度、行长度、校验和计算等多个关键步骤。
摘要由CSDN通过智能技术生成

S-record格式文件是Freescale CodeWarrior编译器生成的后缀名为.S19的程序文件,是一段直接烧写进MCU的ASCII码,英文全称问Motorola format for EEPROM programming。

1.格式

S-record 每行最大78字节,156个字符,由5部分组成

Image srec_motorola_1.png

Stype 1byte描述记录的类型((S0,S1,S2,S3,S5,S6,S7,S8,S9)。
Record Length1byte剩余此行后续数据 byte数,16进制
Address

2byte

3byte

4byte

记录数据地址信息,地址长度由载入地址的byte数决定
Data0-64byte代表内存载入数据或者描述信息16进制数
CheckSum1byteRecord length 、address、data 16进制数据相加求和,只保留最低byte 0xNN,CheckSum =0xFF - 0xNN 

stype描述
s0

Address没有被用,用零置位(0x0000)。数据场中的信息被划分为以下四个子域:

      name(名称):20个字符,用来编码单元名称

      ver(版本):2个字符,用来编码版本号

      rev(修订版本):2个字符,用来编码修订版本号

      description(描述):0-36个字符,用来编码文本注释

此行表示程序的开始,不需烧入memory。

s1Address 用2 byte 表示
s2Address 用3 byte 表示
s3Address 用4 byte 表示
s5Address 用 2byte 表示,包含之前的 s1,s2,s3 记录的计数,没有Data部分
s7Address 用4byte表示,包含了开始执行地址,没有Data 部分,表示程序结束,不需要烧写memory
s8Address 用3byte表示,包含了开始执行地址,没有Data 部分,表示程序结束,不需要烧写memory
s9Address 用2byte表示,包含了开始执行地址,没有Data 部分,表示程序结束,不需要烧写memory
s6Address 用 3byte 表示,包含之前的 s1,s2,s3 记录的计数,没有Data部分

2.实例

3.格式转换工具

SRecord 1.65

4.bin 转s19功能实现

/*
	BIN2SREC  - Convert binary to Motorola S-Record file
	Copyright (C) 1998-2015  Anthony Goffart
	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
 
#include "common.h"
 
#define HEADER1 "\nBIN2SREC " SREC_VER " - Convert binary to Motorola S-Record file.\n"
 
char *infilename;
char *outfilename;
FILE *infile, *outfile;
 
uint32_t addr_offset = 0;
uint32_t begin_addr;
uint32_t end_addr;
uint32_t addr_bytes = 2;
bool do_headers = true;
bool verbose = true;
uint32_t line_length = 32;
char *head_char;
bool have_header=false;
uint8_t headhex[255];
uint32_t end_flag =0;//end frame flag 
uint32_t checksum_flag =1;
 
 
/***************************************************************************/
 
void syntax(void)
{
	fprintf(stderr, HEADER1);
	fprintf(stderr, HEADER2);
	fprintf(stderr, "Syntax: BIN2SREC <options> INFILE > OUTFILE\n\n");
	fprintf(stderr, "-h               Show this help.\n");
	fprintf(stderr, "-b <begin>       Address to begin at in binary file (hex), default = 0.\n");
	fprintf(stderr, "-e <end>         Address to end at in binary file (hex), default = end of file.\n");
	fprintf(stderr, "-o <offset>      Generated address offset (hex), default = begin address.\n");
	fprintf(stderr, "-a <addrsize>    Number of bytes used for address (2-4),\n");
	fprintf(stderr, "                  default = minimum needed for maximum address.\n");
	fprintf(stderr, "-l <linelength>  Number of bytes per line (8-32), default = 32.\n");
	fprintf(stderr, "-s               Suppress header and footer records,if have -s ,not add header records.default  add header records\n");
	fprintf(stderr, "-n               Add S0 note ,default none\n");
	fprintf(stderr, "-q               Quiet mode - no output except S-Record.\n");
    fprintf(stderr, "-f <end flag>    have S7 S8 S9 frame  0--nothave  1 --have  default =0\n ");
	fprintf(stderr, "-c <checksum calc>   Add end data checksum   0--nothave  1 --have  default=0\n");
}
 
/***************************************************************************/
 
void process(void)
{
	int i;
	uint32_t max_addr, address;
	uint32_t byte_count, this_line;
	uint8_t checksum;
	uint32_t c;
	int record_count = 0;
	uint32_t head_count = 0;
	uint32_t head_checksum = 0;
 
	unsigned char buf[32];
 
	max_addr = addr_offset + (end_addr - begin_addr);
 
	fseek(infile, begin_addr, SEEK_SET);
 
	if ((max_addr > 0xffffl) && (addr_bytes < 3))
		addr_bytes = 3;
 
	if ((max_addr > 0xffffffl) && (addr_bytes < 4))
		addr_bytes = 4;
 
	if((outfile = fopen(outfilename, "wb")) != NULL)
	{
 
	}
	else
	{
		fprintf(stderr, "Can't create output file %s.\n", outfilename);
		//return(1);
		return;
	}
	
	if (verbose)
	{
		fprintf(stderr, HEADER1);
		fprintf(stderr, HEADER2);
		fprintf(stderr, "Input binary file: %s\n", infilename);
		fprintf(stderr, "Begin address   = %Xh\n", begin_addr);
		fprintf(stderr, "End address     = %Xh\n", end_addr);
		fprintf(stderr, "Address offset  = %Xh\n", addr_offset);
		fprintf(stderr, "Maximum address = %Xh\n", max_addr);
		fprintf(stderr, "Address bytes   = %u\n", addr_bytes);
	}
 
 
    if(do_headers)
	{
		
		if(have_header)
		{
			
			head_count = strlen(head_char);
			fprintf(outfile,"S0%02X0000",head_count+3);
			head_checksum = head_count+3;
			for(i=0;i<head_count;i++)
			{
				//headhex[i] = char_to_uint8(head_char[i]);
				fprintf(outfile,"%02X",head_char[i]);
				head_checksum +=(uint8_t)head_char[i];
			}
			checksum = 0xFF - head_checksum&0xFF;
			fprintf(outfile,"%02X\n",checksum);		
		}
		else
		{
			//fprintf(outfile,"S00600004844521B\n");
		}
	}
	address = addr_offset;
 
	for (;;)
	{
		if (verbose)
			fprintf(stderr, "Processing %08Xh\r", address);
 
		this_line = min(line_length, (max_addr - address) + 1);
		byte_count = (addr_bytes + this_line + 1);
		fprintf(outfile,"S%u%02X", addr_bytes - 1, byte_count);
 
		checksum = byte_count;
 
		for (i = addr_bytes - 1; i >= 0; i--)
		{
			c = (address >> (i << 3)) & 0xff;
			fprintf(outfile,"%02X", c);
			checksum += c;
		}
 
		if(fread(buf, 1, this_line, infile)) {}
 
		for (i = 0; i < this_line; i++)
		{
			fprintf(outfile,"%02X", buf[i]);
			checksum += buf[i];
		}
 
		
 
		record_count++;
 
		/* check before adding to allow for finishing at 0xffffffff */
		if ((address - 1 + line_length) >= max_addr)
		{
			if(checksum_flag ||end_flag)
			{
				fprintf(outfile,"%02X\n", 255 - checksum);
			}
			else
			{
				fprintf(outfile,"%02X", 255 - checksum);
			}		
			break;
		}
		else
		{
			fprintf(outfile,"%02X\n", 255 - checksum);
		}
 
		address += line_length;
	}
 
	if (1)
	{
		
		#if 0
		
		if (record_count > 0xffff)
		{
			checksum = 4 + (record_count & 0xff) + ((record_count >> 8) & 0xff) + ((record_count >> 16) & 0xff);
			fprintf(outfile,"S604%06X%02X\n", record_count, 255 - checksum);
		}
		else
		{
			checksum = 3 + (record_count & 0xff) + ((record_count >> 8) & 0xff);
			fprintf(outfile,"S503%04X%02X\n", record_count, 255 - checksum);
		}
		#endif 
 
		byte_count = (addr_bytes + 1);
        if(end_flag==1)
        {
            fprintf(outfile,"S%u%02X", 11 - addr_bytes, byte_count);
        }
 
		checksum = byte_count;
 
        if(checksum_flag)
		{
			for (i = addr_bytes - 1; i >= 0; i--)
			{
				c = (addr_offset >> (i << 3)) & 0xff;
				fprintf(outfile,"%02X", c);
				checksum += c;
			}
			fprintf(outfile,"%02X", 255 - checksum);
		}
	}
 
	if (verbose)
		//fprintf(stderr, "byte count %d\n",byte_count);
		fprintf(stderr, "Processing complete \n");
}
 
/***************************************************************************/
 
int main(int argc, char *argv[])
{
	int i;
	uint32_t size;
	bool offset_specified = false;
	bool end_specified = false;
 
	for (i = 1; i < argc; i++)
	{
		if (!strcmp(argv[i], "-o"))
		{
			addr_offset = str_to_uint32(argv[++i]);
			offset_specified = true;
			continue;
		}
 
		else if (!strcmp(argv[i], "-b"))
		{
			begin_addr = str_to_uint32(argv[++i]);
			continue;
		}
 
		else if (!strcmp(argv[i], "-e"))
		{
			end_addr = str_to_uint32(argv[++i]);
			end_addr -= 1;
			end_specified = true;
			continue;
		}
 
		else if (!strcmp(argv[i], "-a"))
		{
			sscanf(argv[++i], "%u", &addr_bytes);
			addr_bytes = max(2, addr_bytes);
			addr_bytes = min(4, addr_bytes);
			continue;
		}
 
		else if (!strcmp(argv[i], "-l"))
		{
			sscanf(argv[++i], "%u", &line_length);
			line_length = max(8, line_length);
			line_length = min(32, line_length);
			continue;
		}
 
		else if (!strcmp(argv[i], "-s"))
		{
			do_headers = false;
			continue;
		}
        else if(!strcmp(argv[i],"-f"))
		{
            sscanf(argv[++i], "%u", &end_flag);
            //fprintf(stderr, "end flag %u\n",end_flag);
		}
		else if(!strcmp(argv[i],"-c"))//checksum flag
		{
			sscanf(argv[++i], "%u", &checksum_flag);
			
		}
		else if(!strcmp(argv[i],"-n"))
		{
			have_header  = true;
			head_char = argv[++i];
			if(head_char == NULL)
			{
				
				fprintf(stderr, "\n** No  head note specified\n");
				return(1);
			}
		}
		else if (!strcmp(argv[i], "-q"))
		{
			verbose = false;
			continue;
		}
 
		else if (!strncmp(argv[i], "-h", 2))		 /* -h or -help */
		{
			syntax();
			return(0);
		}
      
 
		else
		{
			infilename = argv[i];
			outfilename = argv[++i];
		}
	}
 
	if (infilename == NULL)
	{
		syntax();
		fprintf(stderr, "\n** No input infilename specified\n");
		return(1);
	}
	if (outfilename == NULL)
	{
		//syntax();
		fprintf(stderr, "\n** No output infilename specified\n");
		return(1);
	}
 
	if ((infile = fopen(infilename, "rb")) != NULL)
	{
		size = file_size(infile) - 1;
 
		if (end_specified)
			end_addr = min(size, end_addr);
		else
			end_addr = size;
 
		if (begin_addr > size)
		{
			fprintf(stderr, "Begin address %Xh is greater than file size %Xh\n", begin_addr, size);
			return(3);
		}
 
		if (end_addr < begin_addr)
		{
			fprintf(stderr, "End address %Xh is less than begin address %Xh\n", end_addr, begin_addr);
			return(3);
		}
 
		if (!offset_specified)
			addr_offset = begin_addr;
 
		process();
		fclose(infile);
		return(0);
	}
	else
	{
		fprintf(stderr, "Input file %s not found\n", infilename);
		return(2);
	}
}
 
/***************************************************************************/

5.s19转bin 实现


#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>

#include "common.h"

#define HEADER1 "\nSREC2BIN " SREC_VER " - Convert Motorola S-Record to binary file.\n"

#define LINE_LEN 1024

char *infilename;
char *outfilename;
FILE *infile, *outfile;

uint32_t max_addr = 0;
uint32_t min_addr = 0;

uint8_t filler = 0xff;
bool verbose = true;

/***************************************************************************/

void syntax(void)
{
	fprintf(stderr, HEADER1);
	fprintf(stderr, HEADER2);
	fprintf(stderr, "Syntax: SREC2BIN <options> INFILE OUTFILE\n\n");
	fprintf(stderr, "-help            Show this help.\n");
	fprintf(stderr, "-o <offset>      Start address offset (hex), default = 0.\n");
	fprintf(stderr, "-a <addrsize>    Minimum binary file size (hex), default = 0.\n");
	fprintf(stderr, "-f <fillbyte>    Filler byte (hex), default = FF.\n");
	fprintf(stderr, "-q               Quiet mode\n");
}

/***************************************************************************/

void parse(int scan, uint32_t *max, uint32_t *min)
{
	int i, j;
	char line[LINE_LEN] = "";
	uint32_t address;
	uint32_t rec_type, addr_bytes, byte_count;
	char c;
	uint8_t buf[256];

	do
	{
		if(fgets(line, LINE_LEN, infile)) {}

		if (line[0] == 'S')								/* an S-record */
		{
			rec_type = line[1] - '0';

			if ((rec_type >= 1) && (rec_type <= 3))		/* data record */
			{
				address = 0;
				addr_bytes = rec_type + 1;

				for (i = 4; i < (addr_bytes * 2) + 4; i++)
				{
					c = line[i];
					address <<= 4;
					address += char_to_uint8(c);
				}

				byte_count = (char_to_uint8(line[2]) << 4) + char_to_uint8(line[3]);
				byte_count -= (addr_bytes + 1);

				if (scan)
				{
					if (*min > address)
						*min = address;

					if (*max < (address + (byte_count - 1)))
						*max = address + (byte_count - 1);
				}
				else
				{
					address -= min_addr;

					if (verbose)
						fprintf(stderr, "Writing %3u bytes at %08X\r", byte_count, address);

					j = 0;
					for (i = (addr_bytes * 2) + 4; i < (addr_bytes * 2) + (byte_count * 2) + 4; i += 2)
					{
						buf[j] = (char_to_uint8(line[i]) << 4) + char_to_uint8(line[i+1]);
						j++;
					}
					fseek(outfile, address, SEEK_SET);
					fwrite(buf, 1, byte_count, outfile);
				}
			}
		}
	}
	while(!feof(infile));

	rewind(infile);
}

/***************************************************************************/
#define BLOCK_SIZE 512

int process(void)
{
	uint32_t i;
	uint32_t blocks, remain;
	uint32_t pmax = 0;
	uint32_t pmin = 0xffffffff;

	uint8_t buf[BLOCK_SIZE];

	if (verbose)
	{
		fprintf(stderr, HEADER1);
		fprintf(stderr, HEADER2);
		fprintf(stderr, "Input Motorola S-Record file: %s\n", infilename);
		fprintf(stderr, "Output binary file: %s\n", outfilename);
	}

	parse(true, &pmax, &pmin);

	min_addr = min(min_addr, pmin);
	max_addr = max(pmax, min_addr + max_addr);

	blocks = (max_addr - min_addr + 1) / BLOCK_SIZE;
	remain = (max_addr - min_addr + 1) % BLOCK_SIZE;

	if (verbose)
	{
		fprintf(stderr, "Minimum address  = %Xh\n", min_addr);
		fprintf(stderr, "Maximum address  = %Xh\n", max_addr);
		i = max_addr - min_addr + 1;
		fprintf(stderr, "Binary file size = %u (%Xh) bytes.\n", i, i);
	}

	if ((outfile = fopen(outfilename, "wb")) != NULL)
	{
		for (i = 0; i < BLOCK_SIZE; i++)
			buf[i] = filler;
		for (i = 0; i < blocks; i++)
			fwrite(buf, 1, BLOCK_SIZE, outfile);
		fwrite(buf, 1, remain, outfile);

		parse(false, &pmax, &pmin);
		fclose(outfile);
	}
	else
	{
		fprintf(stderr, "Can't create output file %s.\n", outfilename);
		return(1);
	}

	if (verbose)
		fprintf(stderr, "Processing complete          \n");

	return(0);
}

/***************************************************************************/

int main(int argc, char *argv[])
{
	int i;
	int result = 0;

	for (i = 1; i < argc; i++)
	{
		if (!strcmp(argv[i], "-q"))
			verbose = false;

		else if (!strcmp(argv[i], "-a"))
			max_addr = str_to_uint32(argv[++i]) - 1;

		else if (!strcmp(argv[i], "-o"))
			min_addr = str_to_uint32(argv[++i]);

		else if (!strcmp(argv[i], "-f"))
			filler = str_to_uint32(argv[++i]) & 0xff;

		else if (!strncmp(argv[i], "-h", 2))			/* -h or -help */
		{
			syntax();
			return(0);
		}
		else
		{
			infilename = argv[i];
			outfilename = argv[++i];
		}
	}

	if (infilename == NULL)
	{
		syntax();
		fprintf(stderr, "\n** No input filename specified\n");
		return(1);
	}

	if (outfilename == NULL)
	{
		syntax();
		fprintf(stderr, "\n** No output filename specified\n");
		return(1);
	}

	if ((infile = fopen(infilename, "rb")) != NULL)
	{
		result = process();
		fclose(infile);
		return(result);
	}
	else
	{
		printf("Input file %s not found\n", infilename);
		return(2);
	}
}

 


#include <sys/stat.h>
#include "common.h"

/***************************************************************************/

uint8_t char_to_uint8(char c)
{
	uint8_t res = 0;

	if (c >= '0' && c <= '9')
		res = (c - '0');
	else if (c >= 'A' && c <= 'F')
		res = (c - 'A' + 10);
	else if (c >= 'a' && c <= 'f')
		res = (c - 'a' + 10);

	return(res);
}

/***************************************************************************/

uint32_t str_to_uint32(char *s)
{
	int i;
	char c;
	uint32_t res = 0;

	for (i = 0; (i < 8) && (s[i] != '\0'); i++)
	{
		c = s[i];
		res <<= 4;
		res += char_to_uint8(c);
	}

	return(res);
}

/***************************************************************************/

uint32_t file_size(FILE *f)
{
	struct stat info;

	if (!fstat(fileno(f), &info))
		return((uint32_t)info.st_size);
	else
		return(0);
}

参考

1.http://srecord.sourceforge.net/man/man5/srec_motorola.html

2.S19格式文件详解(S-record) 分享-lantianyu520-ChinaUnix博客

s19格式是一种常用的二进制文件格式,通常用于存储嵌入式系统的固件或程序。它由多行16进制记录组成,每行记录包含了记录长度、地址、数据和校验等信息。其中,地址可以是16位或24位的线性地址或段地址,数据按字节顺序存储。s19格式使用校验和算法来确保数据的完整性。 以下是一个简单的s19格式解析的示例源码: ```python def parse_s19(filename): with open(filename, 'r') as f: for line in f: if line.startswith('S1') or line.startswith('S2') or line.startswith('S3'): length = int(line[2:4], 16) # 获取记录长度 address = int(line[4:8], 16) # 获取地址 data = line[8:8 + length * 2] # 获取数据 # 数据校验 checksum = line[8 + length * 2:8 + length * 2 + 2] record = line[2:-2] calculated_checksum = sum(int(record[i:i + 2], 16) for i in range(0, len(record), 2)) calculated_checksum = (~calculated_checksum) & 0xFF if calculated_checksum == int(checksum, 16): # 解析有效数据 for i in range(0, len(data), 2): byte = int(data[i:i + 2], 16) # 处理解析得到的数据 # ... # 使用示例 parse_s19('firmware.s19') ``` 上述示例代码使用Python编写,它会逐行解析s19文件,并提取出长度、地址、数据和校验等信息。接着,通过校验和算法对数据进行校验,确保数据的完整性。最后,可以对解析得到的数据进行进一步处理,比如保存到文件或写入嵌入式系统的闪存中。注意,这只是一个简单的示例,实际的s19格式解析可能还需要处理更多的细节和异常情况。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谢娘蓝桥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值