X-Git-Url: https://hackdaworld.org/gitweb/?p=my-code%2Farm.git;a=blobdiff_plain;f=betty%2Flpcload.c;h=38d53864c778ab7922392c2327c326955bc3cec6;hp=6ec118628d38eb537e43662cc408256159427bce;hb=3e0847553a5d514589116f8cf933d454a0db491c;hpb=14acad803dec0c6e18b1825f2b84e9bbcd409554 diff --git a/betty/lpcload.c b/betty/lpcload.c index 6ec1186..38d5386 100644 --- a/betty/lpcload.c +++ b/betty/lpcload.c @@ -4,7 +4,7 @@ * author: hackbard@hackdaworld.org, rolf.anders@physik.uni-augsburg.de * * build: make - * usage: sudo ./lpcload -d /dev/ttyS0 -f firmware.hex [-v] + * usage: sudo ./lpcload -d /dev/ttyS0 -f firmware.hex -D0 fw0.bin [-v] */ #include @@ -18,12 +18,28 @@ #define VERBOSE (1<<0) #define FIRMWARE (1<<1) - +#define BANK0 (1<<2) +#define BANK2 (1<<3) +#define BL (1<<4) +#define FLASHFW (1<<5) +#define BINARY (1<<6) + +#define BANK0_ADDR 0x80000000 +#define BANK2_ADDR 0x82000000 +#define BANK_SIZE 0x00100000 +#define BL_ADDR 0x7fffe000 +#define BL_SIZE 0x00002000 + +#define CMD_READ 'R' // stay compatible to fwflash! +#define CMD_WRITE 'W' +#define CMD_CHIP_ERASE 'E' + +#define TXRX_TYPE_SYNC 0x00 +#define TXRX_TYPE_CKSM 0x00 #define TXRX_TYPE_BAUD 0x01 -#define TXRX_TYPE_SYNC 0x02 -#define TXRX_TYPE_CMD 0x03 -#define TXRX_TYPE_DATA 0x04 -#define TXRX_TYPE_CKSM 0x05 +#define TXRX_TYPE_CMD 0x02 +#define TXRX_TYPE_DATA 0x03 +#define TXRX_TYPE_GO 0x04 #define CMD_SUCCESS "0\r\n" #define INVALID_COMMAND "1\r\n" @@ -42,6 +58,9 @@ #define INVALID_BAUD_RATE "17\r\n" #define INVALID_STOP_BIT "18\r\n" +#define RAM 0x01 +#define FLASH 0x02 + #define CRYSTFREQ "10000" #define RAMOFFSET 0x40000200 @@ -56,19 +75,30 @@ typedef struct s_lpc { char sdev[128]; /* seriel device */ int fwfd; /* fimrware fd */ char fwfile[128]; /* firmware file */ - u8 info; /* info/mode */ + u32 info; /* info/mode */ char freq[8]; /* frequency */ - u32 hoff; /* start addr of ihex file */ + char bank0[127]; /* flash dump bank0 */ + int b0fd; /* dumpfile fd bank0 */ + char bank2[127]; /* flash dump bank2 */ + int b2fd; /* dumpfile fd bank0 */ + char bl[127]; /* flash dump bootloader */ + int blfd; /* dumpfile fd bootloader */ + char ffwfile[127]; /* file with firmware to be flashed */ + int ffwfd; /* fd of the above */ u32 roff; /* ram offset of uc */ + u32 jaddr; /* addr for the jump */ } t_lpc; void usage(void) { printf("possible argv:\n"); - printf(" -d \n"); - printf(" -f \n"); - printf(" -c \n"); - printf(" -r \n"); + printf(" -d \n"); + printf(" -f \n"); + printf(" -c \n"); + printf(" -Dx \n"); + printf(" x=0: bank0, x=2: bank2, x=b: bootloader\n"); + printf(" -w \n"); + printf(" -b (if firmware for flash is a binary)\n"); printf(" -v\n"); } @@ -93,8 +123,8 @@ int open_serial_device(t_lpc *lpc) { // input/output baudrate - cfsetispeed(&term,B9600); - cfsetospeed(&term,B9600); + cfsetispeed(&term,B38400); + cfsetospeed(&term,B38400); // control options -> 8n1 @@ -109,47 +139,106 @@ int open_serial_device(t_lpc *lpc) { // input options -> enable flow control - //term.c_iflag&=~(IXON|IXOFF|IXANY|INLCR|ICRNL); term.c_iflag&=~(INLCR|ICRNL|IXANY); term.c_iflag|=(IXON|IXOFF); + + // output options + + term.c_oflag=0; // more control options -> timeout / flow control term.c_cc[VMIN]=0; - term.c_cc[VTIME]=10; // 1 second timeout - term.c_cc[VSTART]=0x11; - term.c_cc[VSTOP]=0x13; + term.c_cc[VTIME]=20; // 2 seconds timeout + //term.c_cc[VSTART]=0x11; + //term.c_cc[VSTOP]=0x13; tcsetattr(lpc->sfd,TCSANOW,&term); return lpc->sfd; } -int open_firmware(t_lpc *lpc) { +int reconfig_serial_device(t_lpc *lpc) { + struct termios term; int ret; - char buf[BUFSIZE]; + + /* reconfigure the serial device for our lousy loader tool */ + + tcgetattr(lpc->sfd,&term); + + // disable flow control + + term.c_iflag&=~(IXON|IXOFF|IXANY|INLCR|ICRNL); + + // change baudrate + + cfsetispeed(&term,B115200); + cfsetospeed(&term,B115200); + + // timeouts + + term.c_cc[VMIN]=0; + term.c_cc[VTIME]=100; // 10 seconds timeout + + ret=tcsetattr(lpc->sfd,TCSANOW,&term); + + return ret; +} + +int open_firmware(t_lpc *lpc) { /* open firmware file */ lpc->fwfd=open(lpc->fwfile,O_RDONLY); - if(lpc->fwfd<0) + if(lpc->fwfd<0) { perror("fw open"); + return lpc->fwfd; + } - /* read hex file offset */ - - ret=read(lpc->fwfd,buf,7); - if(buf[0]!=':') { - printf("fw open: not an intel hex file?\n"); - return -1; + if(lpc->info&FLASHFW) { + lpc->ffwfd=open(lpc->ffwfile,O_RDONLY); + if(lpc->ffwfd<0) { + perror("ffw open"); + return lpc->ffwfd; + } } - sscanf(buf+3,"%04x",&(lpc->hoff)); - lseek(lpc->fwfd,0,SEEK_SET); return lpc->fwfd; } +int open_dumpfiles(t_lpc *lpc) { + + /* open dumpfiles */ + + if(lpc->info&BANK0) { + lpc->b0fd=open(lpc->bank0,O_WRONLY|O_CREAT); + if(lpc->b0fd<0) { + perror("bank0 dump file open"); + return lpc->b0fd; + } + } + + if(lpc->info&BANK2) { + lpc->b2fd=open(lpc->bank2,O_WRONLY|O_CREAT); + if(lpc->b2fd<0) { + perror("bank2 dump file open"); + return lpc->b2fd; + } + } + + if(lpc->info&BL) { + lpc->blfd=open(lpc->bl,O_WRONLY|O_CREAT); + if(lpc->blfd<0) { + perror("bootloader dump file open"); + return lpc->blfd; + } + } + + return 0; + +} int txrx(t_lpc *lpc,char *buf,int len,u8 type) { int ret,cnt; @@ -181,6 +270,8 @@ int txrx(t_lpc *lpc,char *buf,int len,u8 type) { printf("| (%d)\n",cnt); } + + /* cut the echo if not of type auto baud */ if(type!=TXRX_TYPE_BAUD) { @@ -194,6 +285,11 @@ int txrx(t_lpc *lpc,char *buf,int len,u8 type) { } } + /* return if type is go */ + + if(type==TXRX_TYPE_GO) + return cnt; + /* return here if type is data */ if(type==TXRX_TYPE_DATA) @@ -315,9 +411,9 @@ int go(t_lpc *lpc) { char buf[BUFSIZE]; int ret,len; - snprintf(buf,BUFSIZE,"G %d A\r\n",lpc->roff); + snprintf(buf,BUFSIZE,"G %d A\r\n",lpc->jaddr); len=strlen(buf); - ret=txrx(lpc,buf,ret,TXRX_TYPE_CMD); + ret=txrx(lpc,buf,len,TXRX_TYPE_GO); return ret; } @@ -349,7 +445,7 @@ int write_to_ram(t_lpc *lpc,char *buf,u32 addr,int len) { } /* make it a multiple of 3 (reason: uuencode) */ - nlen=(len/3+1)*3; + nlen=(!(len%3))?len:((len/3+1)*3); if(nlen>BUFSIZE) { printf("ram write: too much data\n"); return -1; @@ -357,7 +453,7 @@ int write_to_ram(t_lpc *lpc,char *buf,u32 addr,int len) { for(i=len;iroff-lpc->hoff); + addr+=lpc->roff; /* prepare write command */ if(lpc->info&VERBOSE) @@ -376,7 +472,8 @@ int write_to_ram(t_lpc *lpc,char *buf,u32 addr,int len) { while(bcnt>((as-1-i)*8))&0xff; + for(i=0;i>((ls-1-i)*8))&0xff; + + cnt=0; + while(size) { + ret=write(sfd,send+cnt,size); + if(ret<0) { + perror("dump file: send cmd "); + return ret; + } + size-=ret; + cnt+=ret; + } + + /* flush */ + tcflush(sfd,TCIOFLUSH); + + return 0; +} + +int write_to_flash(t_lpc *lpc,u8 *buf,u32 addr,int len) { + + int cnt,ret; + u8 cksml,cksmr; + int i; + + /* prepare addr */ + addr+=lpc->roff; + + /* send cmd */ + send_cmd(lpc->sfd,addr,len,CMD_WRITE); + + /* transfer data */ + cnt=0; + cksml=0; + while(len) { + ret=write(lpc->sfd,buf+cnt,len); + if(ret<0) { + perror("transmit flash content (w)"); + return ret; + } + for(i=cnt;isfd,&cksmr,1); + if(ret<0) { + perror("write to flash: read cksm"); + return ret; + } + if(ret==1) break; + } + if(cksml!=cksmr) { + printf("FATAL: wrong checksum or failure in flash write!\n"); + if(cksml+1==cksmr) + printf(" -> most probably due to flash write!\n"); + else + printf(" -> most probably failure in transfer!\n"); + printf(" addr:0x%08x l:%02x r:%02x\n",addr,cksml,cksmr); + } + + return 0; +} + +int firmware_to_mem(t_lpc *lpc,u8 memtype) { char buf[BUFSIZE]; u32 addr,len,type; int ret,temp; + int fd; + + /* prepare for memory type */ + if(memtype==RAM) + fd=lpc->fwfd; + else if(memtype==FLASH) + fd=lpc->ffwfd; + else + return -1; + + /* another evil hack to support binary format */ + if((lpc->info&BINARY)&&(memtype==FLASH)) { + addr=0; + ret=1; + while(ret) { + ret=read(fd,buf,16); + if(ret!=16) { + printf("D'OH ...\n"); + return -1; + } + buf[16]='s'; // skip + for(temp=0;temp<16;temp++) + if((u8)buf[temp]!=0xff) + buf[16]='w'; // write + printf("addr:%08x\r",addr+lpc->roff); + fflush(stdout); + if(buf[16]=='w') + write_to_flash(lpc,(u8 *)buf,addr,16); + addr+=16; + } + return 0; + } /* read a line */ ret=1; while(ret) { /* sync line */ - ret=read(lpc->fwfd,buf,1); + ret=read(fd,buf,1); switch(buf[0]) { case '\r': continue; @@ -439,29 +663,25 @@ int firmware_to_ram(t_lpc *lpc) { /* start code */ break; default: - printf("fw to ram: no ihex format\n"); + printf("fw to mem: no ihex format\n"); return -1; } /* read len */ - ret=read(lpc->fwfd,buf,2); + ret=read(fd,buf,2); sscanf(buf,"%02x",&len); - if(len%4) { - printf("fw to ram: len not a multiple of 4\n"); - return -1; - } /* read addr */ - ret=read(lpc->fwfd,buf,4); + ret=read(fd,buf,4); sscanf(buf,"%04x",&addr); /* read type */ - ret=read(lpc->fwfd,buf,2); + ret=read(fd,buf,2); sscanf(buf,"%02x",&type); /* successfull return if type is end of file */ if(type==0x01) return 0; /* read data (and cksum) */ - ret=read(lpc->fwfd,buf,2*(len+1)); + ret=read(fd,buf,2*(len+1)); if(ret!=(2*(len+1))) { - printf("fw to ram: data missing\n"); + printf("fw to mem: data missing\n"); return -1; } for(ret=0;retroff=((buf[0]<<24)|(buf[1]<<16)); + break; + case 0x05: + lpc->jaddr=((buf[0]<<24)|(buf[1]<<16)); + lpc->jaddr|=((buf[2]<<8)|buf[3]); break; default: - printf("fw to ram: unknown type %02x\n",type); + printf("fw to mem: unknown type %02x\n",type); return -1; } } @@ -485,10 +719,66 @@ int firmware_to_ram(t_lpc *lpc) { return 0; } +int lpc_txbuf_flush(t_lpc *lpc) { + + int i,ret; + u8 buf[16]; + + ret=1; + printf("flushing lpc tx buffer: "); + while(ret) { + ret=read(lpc->sfd,buf,16); + for(i=0;i aborting\n"); + goto end; + } + + /* open firmware file */ + if(open_firmware(&lpc)<0) + goto end; + + /* open dump files */ + if(open_dumpfiles(&lpc)<0) + goto end; + /* parse intel hex file and write to ram */ printf("write firmware to ram ...\n"); - firmware_to_ram(&lpc); + firmware_to_mem(&lpc,RAM); /* unlock go cmd */ + printf("unlock go command ...\n"); unlock_go(&lpc); /* go! */ - go(&lpc); + printf("go ...\n"); + ret=go(&lpc); + + /* flush the lpc2220 tx buf */ + lpc_txbuf_flush(&lpc); + + /* reconfigure the serial port */ + if(reconfig_serial_device(&lpc)<0) + goto end; + + /* download flash/bootloader content */ + if(lpc.info&BANK0) + dump_files(lpc.sfd,lpc.b0fd,BANK0_ADDR,BANK_SIZE); + if(lpc.info&BANK2) + dump_files(lpc.sfd,lpc.b2fd,BANK2_ADDR,BANK_SIZE); + if(lpc.info&BL) + dump_files(lpc.sfd,lpc.blfd,BL_ADDR,BL_SIZE); + + /* write a firmware to the lpc flash */ + if(lpc.info&FLASHFW) { + printf("writing firmware to flash ...\n"); + send_cmd(lpc.sfd,0,'0',CMD_CHIP_ERASE); + /* ack */ + ret=0; + while(!ret) + read(lpc.sfd,&ret,1); + lpc.roff=BANK0_ADDR; + firmware_to_mem(&lpc,FLASH); + } end: - close(lpc.sfd); - close(lpc.fwfd); + if(lpc.sfd) + close(lpc.sfd); + if(lpc.fwfd) + close(lpc.fwfd); + if(lpc.b0fd) + close(lpc.b0fd); + if(lpc.b2fd) + close(lpc.b2fd); + if(lpc.blfd) + close(lpc.blfd); + if(lpc.ffwfd) + close(lpc.ffwfd); return 0; }