The GoodFET can program an MSP430's flash memory!
authortravisutk <travisutk@12e2690d-a6be-4b82-a7b7-67c4a43b65c8>
Sat, 20 Jun 2009 18:27:17 +0000 (18:27 +0000)
committertravisutk <travisutk@12e2690d-a6be-4b82-a7b7-67c4a43b65c8>
Sat, 20 Jun 2009 18:27:17 +0000 (18:27 +0000)
git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@45 12e2690d-a6be-4b82-a7b7-67c4a43b65c8

client/GoodFET.py
client/goodfet.msp430
firmware/Makefile
firmware/apps/jtag/jtag430.c
firmware/apps/monitor/monitor.c
firmware/include/command.h
firmware/lib/command.c
firmware/lib/msp430f1612.c

index 054f648..a4d07c2 100755 (executable)
@@ -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):
index c2d70f1..2286695 100755 (executable)
@@ -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<stop:
-        #print "%04x %04x" % (i, client.MSP430peek(i));
         h[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<stop  and i&1==0):
+            client.MSP430writeflash(i,h[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<stop and i&1==0):
+            peek=client.MSP430peek(i)
+            if(h[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();
index 2d831e4..8e7d7ff 100644 (file)
@@ -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)
index 03541c1..cc2ecc2 100644 (file)
@@ -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();
 }
 
index defa814..d820107 100644 (file)
@@ -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;
   }
 }
index 0c65462..c1269e6 100644 (file)
@@ -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,
index 9a9421d..cc6e687 100644 (file)
@@ -15,7 +15,6 @@ void txdata(unsigned char app,
   }
 }
 
-
 //! Delay for a count.
 void delay(unsigned int count){
   volatile unsigned int i=count;
index 08e3dd8..fb6c4c0 100644 (file)
@@ -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  */
 }