From: travisutk Date: Sat, 20 Jun 2009 18:27:17 +0000 (+0000) Subject: The GoodFET can program an MSP430's flash memory! X-Git-Url: http://git.rot13.org/?p=goodfet;a=commitdiff_plain;h=3e900862cd87255c698e516c37078163ce343e77;hp=af5f45117ebd63f829465cf209b4967b4051daaa The GoodFET can program an MSP430's flash memory! git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@45 12e2690d-a6be-4b82-a7b7-67c4a43b65c8 --- diff --git a/client/GoodFET.py b/client/GoodFET.py index 054f648..a4d07c2 100755 --- a/client/GoodFET.py +++ b/client/GoodFET.py @@ -34,7 +34,6 @@ class GoodFET: if(self.verb!=0x7F): print "Verb is wrong. Incorrect firmware?"; - def writecmd(self, app, verb, count, data): """Write a command and some data to the GoodFET.""" self.serialport.write(chr(app)); @@ -69,7 +68,18 @@ class GoodFET: self.data=[address&0xff,address>>8,value]; self.writecmd(0,0x03,3,self.data); return ord(self.data[0]); - + def setBaud(self,baud): + rates=[9600, 9600, 19200, 38400]; + self.data=[baud]; + print "Changing baud." + self.serialport.write(chr(0x00)); + self.serialport.write(chr(0x80)); + self.serialport.write(chr(1)); + self.serialport.write(chr(baud)); + + print "Changed baud." + self.serialport.setBaudrate(rates[baud]); + return; def monitortest(self): """Self-test several functions through the monitor.""" print "Performing monitor self-test."; @@ -114,6 +124,9 @@ class GoodFET: def MSP430start(self): """Start debugging.""" self.writecmd(0x11,0x20,0,self.data); + ident=self.MSP430ident(); + print "Target identifies as %04x." % ident; + def MSP430stop(self): """Stop debugging.""" self.writecmd(0x11,0x21,0,self.data); @@ -138,15 +151,13 @@ class GoodFET: """Set the instruction fetch mode.""" self.writecmd(0x11,0xC1,0,self.data); return self.data[0]; + def MSP430ident(self): + """Grab self-identification word from 0x0FF0 as big endian.""" + i=self.MSP430peek(0x0ff0); + return ((i&0xFF00)>>8)+((i&0xFF)<<8) def MSP430test(self): """Test MSP430 JTAG. Requires that a chip be attached.""" - #self.MSP430setup(); - #self.MSP430start(); - self.MSP430haltcpu(); - - ident=self.MSP430peek(0x0ff0); - print "Target identifies as %04x." % ident; - if ident==0xffff: + if self.MSP430ident()==0xffff: print "Is anything connected?"; print "Testing RAM."; temp=self.MSP430peek(0x0200); @@ -155,8 +166,25 @@ class GoodFET: print "Poke of 0x0200 did not set to 0xDEAD properly."; return; self.MSP430poke(0x0200,temp); #restore old value. - self.MSP430releasecpu(); - + def MSP430flashtest(self): + self.MSP430masserase(); + i=0x2500; + while(i<0x2600): + if(self.MSP430peek(i)!=0xFFFF): + print "ERROR: Unerased flash at %04x."%i; + self.MSP430writeflash(i,0x0000); + i+=2; + def MSP430masserase(self): + """Erase MSP430 flash memory.""" + self.writecmd(0x11,0xE3,0,None); + def MSP430writeflash(self,adr,val): + """Write a word of flash memory.""" + data=[adr&0xFF,(adr&0xFF00)>>8,val&0xFF,(val&0xFF00)>>8]; + self.writecmd(0x11,0xE1,4,data); + rval=ord(self.data[0])+(ord(self.data[1])<<8); + if(val!=rval): + print "FLASH WRITE ERROR AT %04x. Found %04x, wrote %04x." % (adr,rval,val); + sys.exit(1); def MSP430dumpbsl(self): self.MSP430dumpmem(0xC00,0xfff); def MSP430dumpallmem(self): diff --git a/client/goodfet.msp430 b/client/goodfet.msp430 index c2d70f1..2286695 100755 --- a/client/goodfet.msp430 +++ b/client/goodfet.msp430 @@ -7,19 +7,26 @@ from GoodFET import GoodFET; from intelhex import IntelHex16bit; -client=GoodFET(); -client.serInit("/dev/ttyUSB0") if(len(sys.argv)==1): print "Usage: %s verb [objects]\n" % sys.argv[0]; print "%s test" % sys.argv[0]; print "%s dump $foo.hex [0x$start 0x$stop]" % sys.argv[0]; + print "%s erase" % sys.argv[0]; + print "%s flash $foo.hex [0x$start 0x$stop]" % sys.argv[0]; + print "%s verify $foo.hex [0x$start 0x$stop]" % sys.argv[0]; sys.exit(); +#Initailize FET and set baud rate +client=GoodFET(); +client.serInit("/dev/ttyUSB0") +#client.setBaud(1); + #Connect to target client.MSP430setup(); client.MSP430start(); + if(sys.argv[1]=="test"): client.MSP430test(); if(sys.argv[1]=="dump"): @@ -35,11 +42,57 @@ if(sys.argv[1]=="dump"): h = IntelHex16bit(None); i=start; while i>1]=client.MSP430peek(i); if(i%0x100==0): print "Dumped %04x."%i; i+=2; - #h.dump();#(tofile=f); h.write_hex_file(f); +if(sys.argv[1]=="erase"): + client.MSP430masserase(); +if(sys.argv[1]=="ivt"): + client.MSP430dumpmem(0xFFE0,0xFFFF); +if(sys.argv[1]=="flash"): + f=sys.argv[2]; + start=0; + stop=0xFFFF; + if(len(sys.argv)>3): + start=int(sys.argv[3],16); + if(len(sys.argv)>4): + stop=int(sys.argv[4],16); + + h = IntelHex16bit(f); + + + client.MSP430masserase(); + for i in h._buf.keys(): + #print "%04x: %04x"%(i,h[i>>1]); + if(i>=start and i>1]); + if(i%0x100==0): + print "%04x" % i; +if(sys.argv[1]=="flashtest"): + client.MSP430flashtest(); +if(sys.argv[1]=="verify"): + f=sys.argv[2]; + start=0; + stop=0xFFFF; + if(len(sys.argv)>3): + start=int(sys.argv[3],16); + if(len(sys.argv)>4): + stop=int(sys.argv[4],16); + + h = IntelHex16bit(f); + for i in h._buf.keys(): + if(i>=start and i>1]!=peek): + print "ERROR at %04x, found %04x not %04x"%(i,peek,h[i>>1]); + if(i%0x100==0): + print "%04x" % i; + +if(sys.argv[1]=="whatever"): + for i in [0x24FF, 0x2500, 0x2502, 0x2504]: + print "%04x" % client.MSP430peek(i); + +client.MSP430releasecpu(); client.MSP430stop(); diff --git a/firmware/Makefile b/firmware/Makefile index 2d831e4..8e7d7ff 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -10,8 +10,8 @@ GCCINC=-T ldscripts/161x.x CC=msp430-gcc -g -mmcu=$(mcu) -DGCC $(GCCINC) -I include -apps= apps/monitor/monitor.c apps/spi/spi.c apps/i2c/i2c.c apps/chipcon/chipcon.c apps/jtag/jtag.c apps/jtag/jtag430.c -libs= lib/msp430f1612.c lib/command.c +apps= apps/monitor/monitor.o apps/spi/spi.o apps/i2c/i2c.o apps/chipcon/chipcon.o apps/jtag/jtag.o apps/jtag/jtag430.o +libs= lib/msp430f1612.o lib/command.o app=goodfet all: $(app).hex @@ -23,7 +23,7 @@ run: install: $(app).hex $(BSL) -e -p $(app).hex - $(BSL) -P $(app).hex -r + #$(BSL) -P $(app).hex -r $(app): $(app).c $(libs) $(apps) $(app).hex: $(app) msp430-objcopy goodfet -O ihex goodfet.hex @@ -32,4 +32,4 @@ m4s: $(app).hex erase: $(BSL) -e clean: - rm -f $(app) + rm -f $(app) $(app).hex $(libs) $(apps) diff --git a/firmware/apps/jtag/jtag430.c b/firmware/apps/jtag/jtag430.c index 03541c1..cc2ecc2 100644 --- a/firmware/apps/jtag/jtag430.c +++ b/firmware/apps/jtag/jtag430.c @@ -77,12 +77,108 @@ void jtag430_writemem(unsigned int adr, unsigned int data){ jtag_ir_shift8(IR_DATA_TO_ADDR); jtag_dr_shift16(data); SETTCLK; +} + +//! Pulse TCLK at 350kHz +/- 100kHz +void jtag430_tclk_flashpulses(unsigned int i){ + //TODO check this on a scope. + + //At 2MHz, 350kHz is obtained with 5 clocks of delay + /** Pondering: + What happens if the frequency is too low or to high? + Is there any risk of damaging the chip, or only of a poor write? + */ + while(i--){ + SETTCLK; + _NOP(); + _NOP(); + _NOP(); + _NOP(); + _NOP(); + CLRTCLK; + } } -//! Write data to address. +//! Write data to flash memory. Must be preconfigured. +void jtag430_writeflashword(unsigned int adr, unsigned int data){ + //jtag430_haltcpu(); + /* + CLRTCLK; + jtag_ir_shift8(IR_CNTRL_SIG_16BIT); + jtag_dr_shift16(0x2408);//word write + jtag_ir_shift8(IR_ADDR_16BIT); + jtag_dr_shift16(adr); + jtag_ir_shift8(IR_DATA_TO_ADDR); + jtag_dr_shift16(data); + SETTCLK; + + //Return to read mode. + CLRTCLK; + jtag_ir_shift8(IR_CNTRL_SIG_16BIT); + jtag_dr_shift16(0x2409); + */ + + jtag430_writemem(adr,data); + CLRTCLK; + jtag_ir_shift8(IR_CNTRL_SIG_16BIT); + jtag_dr_shift16(0x2409); + + + //Pulse TCLK + jtag430_tclk_flashpulses(35); + //jtag430_releasecpu(); +} + +//! Configure flash, then write a word. void jtag430_writeflash(unsigned int adr, unsigned int data){ - //TODO; this is complicated. + jtag430_haltcpu(); + + //FCTL1=0xA540, enabling flash write + jtag430_writemem(0x0128, 0xA540); + //FCTL2=0xA540, selecting MCLK as source, DIV=1 + jtag430_writemem(0x012A, 0xA540); + //FCTL3=0xA500, should be 0xA540 for Info Seg A on 2xx chips. + jtag430_writemem(0x012C, 0xA500); + + //Write the word itself. + jtag430_writeflashword(adr,data); + + //FCTL1=0xA500, disabling flash write + jtag430_writemem(0x0128, 0xA500); + + jtag430_releasecpu(); +} + + + +#define ERASE_GLOB 0xA50E +#define ERASE_ALLMAIN 0xA50C +#define ERASE_MASS 0xA506 +#define ERASE_MAIN 0xA504 +#define ERASE_SGMT 0xA502 + +//! Configure flash, then write a word. +void jtag430_eraseflash(unsigned int mode, unsigned int adr, unsigned int count){ + //FCTL1= erase mode + jtag430_writemem(0x0128, mode); + //FCTL2=0xA540, selecting MCLK as source, DIV=1 + jtag430_writemem(0x012A, 0xA540); + //FCTL3=0xA500, should be 0xA540 for Info Seg A on 2xx chips. + jtag430_writemem(0x012C, 0xA500); + + //Write the erase word. + jtag430_writemem(adr, 0x55AA); + //Return to read mode. + CLRTCLK; + jtag_ir_shift8(IR_CNTRL_SIG_16BIT); + jtag_dr_shift16(0x2409); + + //Send the pulses. + jtag430_tclk_flashpulses(count); + + //FCTL1=0xA500, disabling flash write + jtag430_writemem(0x0128, 0xA500); } @@ -192,10 +288,16 @@ void jtag430handle(unsigned char app, case JTAG430_WRITEMEM: case POKE: jtag430_writemem(cmddataword[0],cmddataword[1]); - txdata(app,verb,0); + cmddataword[0]=jtag430_readmem(cmddataword[0]); + txdata(app,verb,2); break; case JTAG430_WRITEFLASH: jtag430_writeflash(cmddataword[0],cmddataword[1]); + cmddataword[0]=jtag430_readmem(cmddataword[0]); + txdata(app,verb,2); + break; + case JTAG430_ERASEFLASH: + jtag430_eraseflash(ERASE_MASS,0xFFFE,0xFFFF); txdata(app,verb,0); break; case JTAG430_SETPC: @@ -205,5 +307,6 @@ void jtag430handle(unsigned char app, default: jtaghandle(app,verb,len); } + jtag430_resettap(); } diff --git a/firmware/apps/monitor/monitor.c b/firmware/apps/monitor/monitor.c index defa814..d820107 100644 --- a/firmware/apps/monitor/monitor.c +++ b/firmware/apps/monitor/monitor.c @@ -15,5 +15,10 @@ void monitorhandle(unsigned char app, cmddata[0]=memorybyte[cmddataword[0]]; txdata(app,verb,1); break; + case MONITOR_CHANGE_BAUD: + //This command, and ONLY this command, does not reply. + setbaud(cmddata[0]); + //txdata(app,verb,0); + break; } } diff --git a/firmware/include/command.h b/firmware/include/command.h index 0c65462..c1269e6 100644 --- a/firmware/include/command.h +++ b/firmware/include/command.h @@ -4,6 +4,7 @@ extern unsigned char cmddata[256]; #define cmddataword ((unsigned int*) cmddata) #define memorybyte ((unsigned char*) 0) +#define memoryword ((unsigned int*) 0) // Global Commands #define READ 0x00 @@ -16,6 +17,9 @@ extern unsigned char cmddata[256]; #define NOK 0x7E #define OK 0x7F +// Monitor Commands +#define MONITOR_CHANGE_BAUD 0x80 + //CHIPCON commands #define CC_CHIP_ERASE 0x80 #define CC_WR_CONFIG 0x81 @@ -53,7 +57,11 @@ extern unsigned char cmddata[256]; #define JTAG430_WRITEMEM 0xE0 #define JTAG430_WRITEFLASH 0xE1 #define JTAG430_READMEM 0xE2 - +#define JTAG430_ERASEFLASH 0xE3 +#define JTAG430_ERASECHECK 0xE4 +#define JTAG430_VERIFYMEM 0xE5 +#define JTAG430_BLOWFUSE 0xE6 +#define JTAG430_ISFUSEBLOWN 0xE7 //! Handle a command. Defined in goodfet.c void handle(unsigned char app, diff --git a/firmware/lib/command.c b/firmware/lib/command.c index 9a9421d..cc6e687 100644 --- a/firmware/lib/command.c +++ b/firmware/lib/command.c @@ -15,7 +15,6 @@ void txdata(unsigned char app, } } - //! Delay for a count. void delay(unsigned int count){ volatile unsigned int i=count; diff --git a/firmware/lib/msp430f1612.c b/firmware/lib/msp430f1612.c index 08e3dd8..fb6c4c0 100644 --- a/firmware/lib/msp430f1612.c +++ b/firmware/lib/msp430f1612.c @@ -24,6 +24,28 @@ void serial_tx(unsigned char x){ TXBUF0 = x; } +//! Set the baud rate. +void setbaud(unsigned char rate){ + + //http://mspgcc.sourceforge.net/baudrate.html + switch(rate){ + default: + case 0: + case 1://9600 baud + UBR00=0x00; UBR10=0x01; UMCTL0=0x00; + break; + case 2://19200 baud + UBR00=0x00; UBR10=0x02; UMCTL0=0x00; + break; + case 3://38400 baud + UBR00=0x40; UBR10=0x00; UMCTL0=0x00; + break; + //TODO + case 4://57600 baud + case 5://115200 baud + break; + } +} void msp430_init_uart(){ @@ -32,15 +54,10 @@ void msp430_init_uart(){ P3SEL |= BIT4|BIT5; // P3.4,5 = USART0 TXD/RXD P3DIR |= BIT4; - UCTL0 = SWRST | CHAR; /* 8-bit character, UART mode */ - - UTCTL0 = SSEL1; /* UCLK = MCLK */ - - //http://mspgcc.sourceforge.net/baudrate.html - //9600 baud - UBR00=0x00; UBR10=0x01; UMCTL0=0x00; + + setbaud(0); ME1 &= ~USPIE0; /* USART1 SPI module disable */ ME1 |= (UTXE0 | URXE0); /* Enable USART1 TXD/RXD */ @@ -49,7 +66,8 @@ void msp430_init_uart(){ /* XXX Clear pending interrupts before enable!!! */ U0TCTL |= URXSE; - + + //IE1 |= URXIE1; /* Enable USART1 RX interrupt */ }