X-Git-Url: https://hackdaworld.org/gitweb/?p=my-code%2Farm.git;a=blobdiff_plain;f=betty%2Flpcload.c;h=38d53864c778ab7922392c2327c326955bc3cec6;hp=bdb39482c205ae97db92a3a89c7b7f6b760e0e12;hb=945d83a31473b984473f571bb92486991d14aa16;hpb=a2e8f16f2d595f007ebf1bfe041927702e161c9c diff --git a/betty/lpcload.c b/betty/lpcload.c index bdb3948..38d5386 100644 --- a/betty/lpcload.c +++ b/betty/lpcload.c @@ -1,8 +1,10 @@ /* * lpcload.c - load firmware into ram of lpc2220 via uart0 * - * author: hackbard@hackdaworld.org + * author: hackbard@hackdaworld.org, rolf.anders@physik.uni-augsburg.de * + * build: make + * usage: sudo ./lpcload -d /dev/ttyS0 -f firmware.hex -D0 fw0.bin [-v] */ #include @@ -14,236 +16,911 @@ #include #include -#define VERBOSE (1<<0) -#define FIRMWARE (1<<1) - -#define CRYSTFREQ "10000" - -#define BUFSIZE 64 +#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_CMD 0x02 +#define TXRX_TYPE_DATA 0x03 +#define TXRX_TYPE_GO 0x04 + +#define CMD_SUCCESS "0\r\n" +#define INVALID_COMMAND "1\r\n" +#define SRC_ADDR_ERROR "2\r\n" +#define DST_ADDR_ERROR "3\r\n" +#define SRC_ADDR_NOT_MAPPED "4\r\n" +#define DST_ADDR_NOT_MAPPED "5\r\n" +#define COUNT_ERROR "6\r\n" +#define COMPARE_ERROR "10\r\n" +#define BUSY "11\r\n" +#define PARAM_ERROR "12\r\n" +#define ADDR_ERROR "13\r\n" +#define ADDR_NOT_MAPPED "14\r\n" +#define CMD_LOCKED "15\r\n" +#define INVALID_CODE "16\r\n" +#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 + +#define BUFSIZE 128 + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +typedef struct s_lpc { + int sfd; /* serial fd */ + char sdev[128]; /* seriel device */ + int fwfd; /* fimrware fd */ + char fwfile[128]; /* firmware file */ + u32 info; /* info/mode */ + char freq[8]; /* frequency */ + 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(" -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"); } -int txrx(int fd,char *buf,int *len,unsigned char v) { +int open_serial_device(t_lpc *lpc) { + + struct termios term; + + //memset(&term,0,sizeof(struct termios)); + + /* open serial device */ + + lpc->sfd=open(lpc->sdev,O_RDWR); + if(lpc->sfd<0) { + perror("tts open"); + return lpc->sfd; + } + + /* configure the serial device */ + + tcgetattr(lpc->sfd,&term); + + // input/output baudrate + + cfsetispeed(&term,B38400); + cfsetospeed(&term,B38400); + + // control options -> 8n1 + + term.c_cflag&=~PARENB; // no parity + term.c_cflag&=~CSTOPB; // only 1 stop bit + term.c_cflag&=~CSIZE; // no bit mask for data bits + term.c_cflag|=CS8; // 8 data bits + + // line options -> raw input + + term.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG); + + // input options -> enable flow control + + 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]=20; // 2 seconds timeout + //term.c_cc[VSTART]=0x11; + //term.c_cc[VSTOP]=0x13; + + tcsetattr(lpc->sfd,TCSANOW,&term); + + return lpc->sfd; +} + +int reconfig_serial_device(t_lpc *lpc) { + + struct termios term; + int ret; + + /* 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) { + perror("fw open"); + return lpc->fwfd; + } + + if(lpc->info&FLASHFW) { + lpc->ffwfd=open(lpc->ffwfile,O_RDONLY); + if(lpc->ffwfd<0) { + perror("ffw open"); + return lpc->ffwfd; + } + } + + 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; int i; /* write */ - if(v&VERBOSE) + if(lpc->info&VERBOSE) printf(" >> "); cnt=0; - while(*len) { - ret=write(fd,buf+cnt,*len); + while(len) { + ret=write(lpc->sfd,buf+cnt,len); if(ret<0) { perror("txrx write"); return ret; } - if(v&VERBOSE) + if(lpc->info&VERBOSE) for(i=0;i0x19)&(buf[cnt+i]<0x7f))? buf[cnt+i]:'.'); - *len-=ret; + len-=ret; cnt+=ret; } - if(v&VERBOSE) - printf(" (%d)\n",cnt); + if(lpc->info&VERBOSE) { + printf(" | "); + for(i=0;isfd,buf,cnt); + if(ret<0) { + perror("txrx echo cut"); + return ret; + } + cnt-=ret; + } + } + + /* return if type is go */ + + if(type==TXRX_TYPE_GO) + return cnt; + + /* return here if type is data */ - /* cut the echo */ - // add more checking here! - while(cnt) - cnt-=read(fd,buf,cnt); + if(type==TXRX_TYPE_DATA) + return cnt; /* read */ - if(v&VERBOSE) - printf(" << "); + ret=read(lpc->sfd,buf,1); + if(ret<0) { + perror("txrx read (first byte)"); + return ret; + } + + switch(buf[0]) { + case 'S': + cnt=13; + break; + case 'O': + cnt=3; + break; + case 'R': + cnt=7; + break; + case '0': + cnt=2; + break; + default: + printf("txrx read: bad return byte '%02x'\n",buf[0]); + break; + } + ret=1; - cnt=0; - while(ret>0) { - ret=read(fd,buf+cnt,BUFSIZE-cnt); + i=cnt; + while(i) { + ret=read(lpc->sfd,buf+1+cnt-i,i); if(ret<0) { - perror("txrx read"); + perror("txrx read (next bytes)"); return ret; } - if(ret+cnt>BUFSIZE) { - printf("txrx read: too small buf size (%d)!\n",BUFSIZE); + i-=ret; + } + if(lpc->info&VERBOSE) { + printf(" << "); + for(i=0;i0x19)&(buf[i]<0x7f))? + buf[i]:'.'); + printf(" | "); + for(i=0;i0x19)&(buf[cnt+i]<0x7f))? - buf[cnt+i]:'.'); - cnt+=ret; } - if(v&VERBOSE) - printf(" (%d)\n",cnt); - *len=cnt; return cnt; } -int main(int argc,char **argv) { +int bl_init(t_lpc *lpc) { - int i; - char tts[128]; - int tts_fd; - char fw[128]; - int fw_fd; - unsigned char info; - struct termios term; - char cfreq[8]; + char buf[BUFSIZE]; int len; + + /* auto baud sequence */ + buf[0]='?'; + txrx(lpc,buf,1,TXRX_TYPE_BAUD); + if(strncmp(buf,"Synchronized\r\n",14)) { + printf("auto baud detection failed\n"); + return -1; + } + + /* tell bl that we are synchronized (it's allready in buf) */ + txrx(lpc,buf,14,TXRX_TYPE_SYNC); + if(strncmp(buf,"OK\r\n",4)) { + printf("sync failed\n"); + return -1; + } + + /* tell bl the crystal frequency */ + len=strlen(lpc->freq)+2; + strncpy(buf,lpc->freq,BUFSIZE); + buf[len-2]='\r'; + buf[len-1]='\n'; + txrx(lpc,buf,len,TXRX_TYPE_SYNC); + if(strncmp(buf,"OK\r\n",4)) { + printf("freq set failed\n"); + return -1; + } + + return 0; +} + +int unlock_go(t_lpc *lpc) { + char buf[BUFSIZE]; + int ret; - /* - * initial ... - */ + memcpy(buf,"U 23130\r\n",9); + ret=txrx(lpc,buf,9,TXRX_TYPE_CMD); - info=0; - memset(&term,0,sizeof(struct termios)); - strncpy(cfreq,CRYSTFREQ,7); + return ret; +} - /* parse argv */ +int go(t_lpc *lpc) { - for(i=1;ijaddr); + len=strlen(buf); + ret=txrx(lpc,buf,len,TXRX_TYPE_GO); + + return ret; +} + +int uuencode(u8 *in,u8 *out,int len) { + + out[0]=0x20+len; + out[1]=0x20+((in[0]>>2)&0x3f); + out[2]=0x20+(((in[0]<<4)|(in[1]>>4))&0x3f); + out[3]=0x20+(((in[1]<<2)|(in[2]>>6))&0x3f); + out[4]=0x20+(in[2]&0x3f); + + return 0; +} + +int write_to_ram(t_lpc *lpc,char *buf,u32 addr,int len) { + + int lcount; + u32 checksum; + char txrxbuf[BUFSIZE]; + int count,bcnt; + int nlen,slen; + int i; + + /* check length */ + if(len%4) { + printf("ram write: not a multiple of 4\n"); + return -1; + } + + /* make it a multiple of 3 (reason: uuencode) */ + nlen=(!(len%3))?len:((len/3+1)*3); + if(nlen>BUFSIZE) { + printf("ram write: too much data\n"); + return -1; + } + for(i=len;iroff; + + /* prepare write command */ + if(lpc->info&VERBOSE) + printf("writing 0x%02x bytes to 0x%08x\n",len,addr); + snprintf(txrxbuf,BUFSIZE,"W %d %d\r\n",addr,len); + slen=strlen(txrxbuf); + + /* send command and check return code */ + txrx(lpc,txrxbuf,slen,TXRX_TYPE_CMD); + + /* send data */ + lcount=0; + bcnt=0; + count=0; + checksum=0; + while(bcntsfd,txrxbuf+4,4); + printf("ram write: resending ...\n"); + bcnt-=count; + } + if(strncmp(txrxbuf,"OK\r\n",4)) { + printf("ram write: bad response\n"); + return -1; + } + /* reset checksum & counter */ + checksum=0; + count=0; + } + + } + + return 0; +} + +int send_cmd(int sfd,u32 addr,u32 len,u8 cmd) { + + int ret,i,cnt,size; + int as,ls; + u8 send[9]; + + switch(cmd) { + case CMD_READ: + case CMD_WRITE: + as=4; + ls=4; + break; + case CMD_CHIP_ERASE: + as=0; + ls=1; + break; + default: + printf("send cmd: cmd '%02x' not supported\n",cmd); return -1; + } + + size=1+as+ls; + send[0]=cmd; + + for(i=0;i>((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; + } - switch(argv[i][1]) { - case 'd': - strncpy(tts,argv[++i],127); + /* 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(fd,buf,1); + switch(buf[0]) { + case '\r': + continue; + case '\n': + continue; + case ':': + /* start code */ break; - case 'f': - strncpy(fw,argv[++i],127); - info|=FIRMWARE; + default: + printf("fw to mem: no ihex format\n"); + return -1; + } + /* read len */ + ret=read(fd,buf,2); + sscanf(buf,"%02x",&len); + /* read addr */ + ret=read(fd,buf,4); + sscanf(buf,"%04x",&addr); + /* read type */ + 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(fd,buf,2*(len+1)); + if(ret!=(2*(len+1))) { + printf("fw to mem: data missing\n"); + return -1; + } + for(ret=0;retroff=((buf[0]<<24)|(buf[1]<<16)); break; - case 'c': - strncpy(cfreq,argv[++i],7); + case 0x05: + lpc->jaddr=((buf[0]<<24)|(buf[1]<<16)); + lpc->jaddr|=((buf[2]<<8)|buf[3]); break; default: - usage(); + printf("fw to mem: unknown type %02x\n",type); return -1; } - } - /* - * open serial device - */ + return 0; +} - tts_fd=open(tts,O_RDWR); - if(tts_fd<0) { - perror("tts open"); - return tts_fd; - } +int lpc_txbuf_flush(t_lpc *lpc) { - /* - * configure serial device - */ + int i,ret; + u8 buf[16]; - tcgetattr(tts_fd,&term); + ret=1; + printf("flushing lpc tx buffer: "); + while(ret) { + ret=read(lpc->sfd,buf,16); + for(i=0;i 8n1 + int ret; + int size; + int cnt; + u8 buf[16]; - term.c_cflag&=~PARENB; // no parity - term.c_cflag&=~CSTOPB; // only 1 stop bit - term.c_cflag&=~CSIZE; // no bit mask for data bits - term.c_cflag|=CS8; // 8 data bits + printf("dumping content (addr=0x%08x, len=0x%08x) ...\n",addr,len); - // line options -> raw input - - term.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG); + /* send the cmd */ + send_cmd(sfd,addr,len,CMD_READ); - // input options -> disable flow control - - term.c_iflag&=~(IXON|IXOFF|IXANY); + /* receive data and dump it to file */ + ret=1; + cnt=0; + printf(" receiving data ...\n"); + while(ret) { + ret=read(sfd,buf,16); + if(ret<0) { + perror("dump file: read data"); + return ret; + } + size=ret; + cnt=0; + while(size) { + ret=write(dfd,buf+cnt,size-cnt); + if(ret<0) { + perror("dump file: write data"); + return ret; + } + cnt+=ret; + size-=ret; + } + } - // more control options -> timeout - - term.c_cc[VMIN]=0; - term.c_cc[VTIME]=10; // 1 second timeout + return 0; +} - tcsetattr(tts_fd,TCSANOW,&term); +int main(int argc,char **argv) { - /* auto baud sequence */ + t_lpc lpc; + int i; + int ret; - printf("auto baud sequence ...\n"); - write(tts_fd,"?",1); - len=0; - txrx(tts_fd,buf,&len,info); - if(strncmp(buf,"Synchronized\r\n",14)) { - printf("auto baud detection failed\n"); - return -1; - } + /* + * initial ... + */ - /* tell bl that we are synchronized (it's allready in buf) */ + memset(&lpc,0,sizeof(t_lpc)); + strncpy(lpc.freq,CRYSTFREQ,7); + lpc.roff=RAMOFFSET; + lpc.jaddr=RAMOFFSET; - printf("sync sequence ...\n"); - len=14; - txrx(tts_fd,buf,&len,info); - if(strncmp(buf,"OK\r\n",4)) { - printf("sync failed\n"); - return -1; - } + /* parse argv */ - /* tell bl the crystal frequency */ + for(i=1;i aborting\n"); + goto end; + } - // to be continued ... (parsing fw file and poking it to ram) + /* 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_mem(&lpc,RAM); + + /* unlock go cmd */ + printf("unlock go command ...\n"); + unlock_go(&lpc); + + /* go! */ + 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(tts_fd); + 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; }