Spare Time Labs 2.0

Welcome


EazyCNC


jDraft 2.0




PureJavaComm


PIC CDC ACM


Weather


Ten-Buck Furnace



H8S Bootloader



Camera Calibration



Multitouch



Myford VFD


Fun with HC08


bl08


printf II


Java Goes Native



Densitometer


printf


jApp


Igloo


New Furnace


New Furnace
Part II


Linux 101


H8S/gcc


Quickie


Gas Fired Furnace


Down Memory Lane


Exlibris


Wheel Patterns


Glitches


CHIP-8


eDice


Animato


jDraft


JNA Benchmark


Contact Info
Created 15.4.2009

A Bootloader for Renesas H8S

A few years ago I wrote a simple bootloader with built in terminal emulator for Renesas H8S processor that I was working with at the time.

It is not a big deal, just a simple commmand line tool to get the job done. It reads an S-record file and downloads it via serial port to the target CPU. Just something I wrote in about an hour. However, it has one big merit in my eyes, it is a single file that you should be able to compile and build by just typing the following in your shell (in any reasonable operating system that is):



gcc bload.c -o bload

You can download the code from here or browse it at the end of this page. If you are into Renesas H8S processors you might be interested in the following pages:

gcc/H8S for dummies

and

SC1 - a Shareware Controller

That's all folks, cheers Kusti

/*
File: bload.c

Copyright (C) 2004  Kustaa Nyholm

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 2.0 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
Lesser General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <string.h>
#include <stdlib.h> 

#define DEFAULT_COM "/dev/ttyS0"
#define DEFAULT_FILENAME "boot.sr"
#define DEFAULT_BASE 0xFFE400

int outcnt=0;
char verbose=0;
char quiet=0;

void putChar(int com,unsigned char ch)
	{
	if (verbose) printf("%02X ",ch);
	else if (!quiet) printf(".");
	write(com, &ch, 1);
	if (++outcnt>=16) {
		outcnt=0;
		if (verbose || !quiet) printf("\n");
		}
	}


void setCommPort(char* comname,int com)
	{
	static struct termios pts;
	int     pfda;

    tcgetattr(com, &pts);
    pts.c_lflag &= ~ICANON;
    pts.c_lflag &= ~(ECHO | ECHOCTL | ECHONL);
    pts.c_cflag |= HUPCL | CLOCAL | CREAD;
    pts.c_cflag &= ~PARENB;
    pts.c_cflag &= ~PARODD;
	pts.c_cflag &= ~CSIZE;
	pts.c_cflag |= CS8;
    pts.c_cc[VMIN] = 1;
    pts.c_cc[VTIME] = 0;
    pts.c_oflag &= ~ONLCR;
    pts.c_iflag &= ~ICRNL;

    cfsetospeed(&pts, B9600);   
    cfsetispeed(&pts, B9600);   
	if (tcsetattr(com,TCSANOW,&pts)!=0) {
		perror(comname); 
		exit(-1); 
		}
	}

char* getArg(int argc, char *argv[],char chr)
	{
	int i;
	for (i=1; i<argc; ++i)
		if ((argv[i][0]=='-') && (argv[i][1]==chr))
			return &(argv[i][2]);
	return NULL;
	}



void termEmu(int com, char* args)
	{
	// get rid of stuff that has been echoed to us
	tcflush(com,TCIFLUSH ); // .. then get rid of the echoes and what ever...

	int	con= open("/dev/console", O_RDWR );
	if (con <0) {perror("/dev/console"); exit(-1); }

	printf("\nTerminal mode, press CTRL-C to exit.\n");

	struct termios newtio,oldtio;
	tcgetattr(con,&oldtio);  // we do not want to change the console setting forever, so keep the old

	tcgetattr(con,&newtio);  // configure the console to return as soon as it a key is pressed
    newtio.c_lflag = 0;    
    newtio.c_cc[VTIME]    = 0;   
    newtio.c_cc[VMIN]     = 1;   
    tcsetattr(con,TCSANOW,&newtio);

    fd_set readfs;    
    int    maxfd;     
    int res;
	char buf[2];
    maxfd = (con>com ? con : com)+1;  
    
    while (1) {
		// wait for something from console or serial port
		FD_SET(con, &readfs);  
		FD_SET(com, &readfs);  
		struct timeval tout;
		tout.tv_usec = 10; 
		tout.tv_sec  = 0; 
		select(maxfd, &readfs, NULL, NULL, &tout);

		// copy console stuff to the serial port
		if (FD_ISSET(con,&readfs))   {    
			res=read(con,buf,1);
			if (buf[0]==3) break; // CTRL-C terminates terminal mode
			write(com,buf,res);
		}
		// copy serial port stuff to console				
		if (FD_ISSET(com,&readfs)){    
			res=read(com,buf,1);
			write(con,buf,res);
		}
	}

    tcsetattr(con,TCSANOW,&oldtio); // restore console settings

	close(con);
 
}

void delay(int delay)
{
	time_t t0=clock();
	while (clock()-t0<CLOCKS_PER_SEC*delay/1000) ;
}

int main(int argc, char *argv[])
	{
	unsigned char bcode[0x20000];  // 128kB
	char* comname=DEFAULT_COM;
	char* filename=DEFAULT_FILENAME;
	int base=DEFAULT_BASE;
	int size=0x1780;
	char * arg;
	char * termargs;
	int termMode=0;
	int dly=0;
	int sum;

	arg=getArg(argc,argv,'-');
	if (arg && strcmp(arg,"help")==0) {
		printf("Usage: \n");
		printf(" bload [-b address] [-s size] [-c comport] [-q] [-n] [srecord filename]\n");
		printf("  -b address to rip from \n");
		printf("  -s max rip size\n");
		printf("  -c comm port/device to dump to\n");
		printf("  -C send check sum (sum of all data bytes sent)\n");
		printf("  -n do not set commport baud, char size, parity, use comm port 'as is' \n");
		printf("  -v verbose operation\n");
		printf("  -q quiet operation\n");
		printf("  -d delay n msec after download (before exit or terminal mode (\n");
		printf("  -t enter terminal mode after download\n");
		printf("  -T enter terminal mode without download\n");
		printf("  Commport is set, if '-n' option NOT used, to 9600 baud, 8 bit char size, no parity, one stop bit, no handshake\n");
		printf("  No space between option and value, for example -b10000, not -b 10000\n");
		printf("  Address and size must be in hexadecimal\n");
		printf("  If no arguments given, then a default file name used, otherwise filename required\n");
		printf("Example (same as using all defaults):\n");
		printf("  bload -b%X -s%X -c%s %s\n",base,size,comname,filename);
		return 0;
		}

	int i;
	for (i=1; i<argc; i++) {
		if (argc>1 && (argv[i][0]!='-'))
			filename=argv[i];
		}

	arg=getArg(argc,argv,'b');
	if (arg)
		sscanf(arg,"%x",&base);

	arg=getArg(argc,argv,'s');
	if (arg)
		sscanf(arg,"%x",&size);

	arg=getArg(argc,argv,'c');
	if (arg)
		comname=arg;

	arg=getArg(argc,argv,'d');
	if (arg)
		sscanf(arg,"%d",&dly);

	arg=getArg(argc,argv,'t');
	if (arg) {
		termMode=1;
		termargs=arg;
	}

	arg=getArg(argc,argv,'T');
	if (arg) {
		termMode=2;
		termargs=arg;
	}

	verbose=getArg(argc,argv,'v')!=NULL;
	quiet=getArg(argc,argv,'q')!=NULL;
	if (quiet) verbose=0;

	if (verbose) {
		printf("This program reads in a S-record froms file '%s' and \n",filename);
		printf("rips code from  address range %06X..%06X and \n",base,base+size-1);
		printf("dumps it to '%s' in the H8S2357 boot mode compatible format.\n",comname);
		printf("This is a blind dump, this does not wait for the H8S to respond.\n");
		printf("\n");

		printf("Reading in boot code...\n");
		}
	int c, n;
	struct termios options;
	char ob[]={0,0,0,0,0};
	char ib[1];


	int com= open(comname, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
	if (com <0) {perror(comname); exit(-1); }

	if (!getArg(argc,argv,'n'))
		setCommPort(comname,com);

	if (termMode==2) {
		termEmu(com,termargs);
		exit(0);
	}
		
	
	FILE* sf=fopen(filename,"r");
	if (sf==NULL) { 
	   printf("Failed to open '%s'\n",filename);
	   exit(-1);
	}


	memset(bcode,0xff,sizeof(bcode));
	char line[80];
	int amax=0;
	while (fgets(line,255,sf)!=NULL) {
	   if (verbose) printf("%s",line);
	   if (line[0]=='S') {
			int n,a,o=0;
			sscanf(line+2,"%2x",&n);
			n--;
			if (line[1]=='1') {
				sscanf(line+4,"%4x",&a);
				n=n-2;
				o=8;
			}
			if (line[1]=='2') {
				sscanf(line+4,"%6x",&a);
				n=n-4;
				o=10;
			}
			if (o!=0) {
				int i;
				for (i=0; i<n; ++i) {
					int d;
					sscanf(line+o+i*2,"%2x",&d);
					if ( (a>=base) && (a<base+size)) {
						bcode[a-base]=d;
						a++;
						amax= a>amax ? a : amax;
						}
						
					}
				}
			else
				if (!quiet) printf("Ignored S-record: %s\n",line);
			}
		}
	fclose(sf);
	if (verbose) printf("\n");


	int dlen=amax-base;
	if (dlen<0) {
	   printf("Nothing to download, no S-records in address range %06X..%06X\n",base,base+size-1);
	   exit(-1);
	}


	if (verbose) printf("Sending boot mode bitrate adjustment and acknowledge bytes...\n");
	putChar(com,0x00);
	putChar(com,0x00);
	putChar(com,0x00);
	putChar(com,0x00);
	putChar(com,0x00);
	putChar(com,0x55);

	if (verbose) printf("\n");
	if (verbose) printf("\n");
	outcnt=0;

	if (verbose) printf("Sending boot code length bytes...\n");
	putChar(com,dlen/256);
	putChar(com,dlen%256);
	if (verbose) printf("\n");
	if (verbose) printf("\n");
	outcnt=0;

	if (verbose) printf("Downloading %d bytes of boot code...\n",dlen);
	
	for (i=0; i<dlen; ++i) {
		putChar(com,bcode[i]);
		sum+=bcode[i];
		}
	
	if (getArg(argc,argv,'C')) {
		sum=sum&0xFF;
		if (verbose) printf("\nSending check sum ...\n");
		putChar(com,sum);
			
	}

	if (!quiet || verbose) printf("\n\n");

	if (verbose) printf("Done downloading %d bytes, the H8S should be executing the code by now!\n",dlen);

	tcdrain(com);  // wait until we have transmitted all...
	
	if (dly)
		delay(dly);

	if (termMode)
		termEmu(com,termargs);

	close(com);
	}






syntax highlighted by Code2HTML, v. 0.9.1