S-record格式文件是Freescale CodeWarrior编译器生成的后缀名为.S19的程序文件,是一段直接烧写进MCU的ASCII码,英文全称问Motorola format for EEPROM programming。
1.格式
S-record 每行最大78字节,156个字符,由5部分组成
Stype | 1byte | 描述记录的类型((S0,S1,S2,S3,S5,S6,S7,S8,S9)。 |
Record Length | 1byte | 剩余此行后续数据 byte数,16进制 |
Address | 2byte 3byte 4byte | 记录数据地址信息,地址长度由载入地址的byte数决定 |
Data | 0-64byte | 代表内存载入数据或者描述信息16进制数 |
CheckSum | 1byte | Record length 、address、data 16进制数据相加求和,只保留最低byte 0xNN,CheckSum =0xFF - 0xNN |
stype | 描述 |
s0 | Address没有被用,用零置位(0x0000)。数据场中的信息被划分为以下四个子域: name(名称):20个字符,用来编码单元名称 ver(版本):2个字符,用来编码版本号 rev(修订版本):2个字符,用来编码修订版本号 description(描述):0-36个字符,用来编码文本注释 此行表示程序的开始,不需烧入memory。 |
s1 | Address 用2 byte 表示 |
s2 | Address 用3 byte 表示 |
s3 | Address 用4 byte 表示 |
s5 | Address 用 2byte 表示,包含之前的 s1,s2,s3 记录的计数,没有Data部分 |
s7 | Address 用4byte表示,包含了开始执行地址,没有Data 部分,表示程序结束,不需要烧写memory |
s8 | Address 用3byte表示,包含了开始执行地址,没有Data 部分,表示程序结束,不需要烧写memory |
s9 | Address 用2byte表示,包含了开始执行地址,没有Data 部分,表示程序结束,不需要烧写memory |
s6 | Address 用 3byte 表示,包含之前的 s1,s2,s3 记录的计数,没有Data部分 |
2.实例
3.格式转换工具
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