--- /dev/null
+#!/usr/bin/env python
+# GoodFET Client Library
+#
+# (C) 2009 Travis Goodspeed <travis at radiantmachines.com>
+#
+# This code is ugly as sin, for bootstrapping the firmware only.
+# Rewrite cleanly as soon as is convenient.
+
+import sys, time, string, cStringIO, struct
+sys.path.append("/usr/lib/tinyos")
+import serial
+
+
+class GoodFET:
+ def __init__(self, *args, **kargs):
+ print "inited\n";
+ self.data=[0];
+ def timeout(self):
+ print "timout\n";
+ def serInit(self, port):
+ """Open the serial port"""
+ self.serialport = serial.Serial(
+ port,
+ 9600,
+ parity = serial.PARITY_NONE
+ )
+ #Drop DTR, which is !RST, low to begin the app.
+ self.serialport.setDTR(0);
+ self.serialport.flushInput()
+ self.serialport.flushOutput()
+
+ #Read and handle the initial command.
+ time.sleep(1);
+ self.readcmd(); #Read the first command.
+ 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));
+ self.serialport.write(chr(verb));
+ self.serialport.write(chr(count));
+ #print "count=%02x, len(data)=%04x" % (count,len(data));
+ if count!=0:
+ for d in data:
+ self.serialport.write(chr(d));
+ self.readcmd(); #Uncomment this later, to ensure a response.
+ def readcmd(self):
+ """Read a reply from the GoodFET."""
+ self.app=ord(self.serialport.read(1));
+ self.verb=ord(self.serialport.read(1));
+ self.count=ord(self.serialport.read(1));
+ if self.count>0:
+ self.data=self.serialport.read(self.count);
+ #print "READ %02x %02x %02x " % (self.app, self.verb, self.count);
+
+ #Monitor stuff
+ def peekbyte(self,address):
+ """Read a byte of memory from the monitor."""
+ self.data=[address&0xff,address>>8];
+ self.writecmd(0,0x02,2,self.data);
+ #self.readcmd();
+ return ord(self.data[0]);
+ def peekword(self,address):
+ """Read a word of memory from the monitor."""
+ return self.peekbyte(address)+(self.peekbyte(address+1)<<8);
+ def pokebyte(self,address,value):
+ """Set a byte of memory by the monitor."""
+ self.data=[address&0xff,address>>8,value];
+ self.writecmd(0,0x03,3,self.data);
+ return ord(self.data[0]);
+
+ def monitortest(self):
+ """Self-test several functions through the monitor."""
+ print "Performing monitor self-test.";
+
+ if self.peekword(0x0c00)!=0x0c04:
+ print "ERROR Fetched wrong value from 0x0c04.";
+ self.pokebyte(0x0021,0); #Drop LED
+ if self.peekbyte(0x0021)!=0:
+ print "ERROR, P1OUT not cleared.";
+ self.pokebyte(0x0021,1); #Light LED
+
+ print "Self-test complete.";
+
+ def spisetup(self):
+ """Moved the FET into the SPI application."""
+ print "Initializing SPI.";
+ self.writecmd(1,0x10,0,self.data); #SPI/SETUP
+ #self.readcmd();
+ def spitrans8(self,byte):
+ """Read and write 8 bits by SPI."""
+ self.data=[byte];
+ self.writecmd(1,0,1,self.data); #SPI exchange
+ #self.readcmd();
+
+ if self.app!=1 or self.verb!=0:
+ print "Error in SPI transaction; app=%02x, verb=%02x" % (self.app, self.verb);
+ return ord(self.data[0]);
+ def MSP430setup(self):
+ """Move the FET into the MSP430 JTAG application."""
+ print "Initializing MSP430.";
+ self.writecmd(0x11,0x10,0,self.data);
+ def MSP430peek(self,adr):
+ """Read the contents of memory at an address."""
+ self.data=[adr&0xff, (adr&0xff00)>>8];
+ self.writecmd(0x11,0x02,2,self.data);
+ return ord(self.data[0])+(ord(self.data[1])<<8);
+ def MSP430poke(self,adr,val):
+ """Read the contents of memory at an address."""
+ self.data=[adr&0xff, (adr&0xff00)>>8, val&0xff, (val&0xff00)>>8];
+ self.writecmd(0x11,0x03,4,self.data);
+ return;# ord(self.data[0])+(ord(self.data[1])<<8);
+
+ def MSP430start(self):
+ """Start debugging."""
+ self.writecmd(0x11,0x20,0,self.data);
+ def MSP430haltcpu(self):
+ """Halt the CPU."""
+ self.writecmd(0x11,0xA0,0,self.data);
+ def MSP430releasecpu(self):
+ """Resume the CPU."""
+ self.writecmd(0x11,0xA1,0,self.data);
+
+ def MSP430shiftir8(self,ins):
+ """Shift the 8-bit Instruction Register."""
+ data=[ins];
+ self.writecmd(0x11,0x80,1,data);
+ return ord(self.data[0]);
+ def MSP430shiftdr16(self,dat):
+ """Shift the 16-bit Data Register."""
+ data=[dat&0xFF,(dat&0xFF00)>>8];
+ self.writecmd(0x11,0x81,2,data);
+ return ord(self.data[0])#+(ord(self.data[1])<<8);
+ def MSP430setinstrfetch(self):
+ """Set the instruction fetch mode."""
+ self.writecmd(0x11,0xC1,0,self.data);
+ return self.data[0];
+ 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:
+ print "Is anything connected?";
+ print "Testing RAM.";
+ temp=self.MSP430peek(0x0200);
+ self.MSP430poke(0x0200,0xdead);
+ if(self.MSP430peek(0x0200)!=0xdead):
+ print "Poke of 0x0200 did not set to 0xDEAD properly.";
+ exit;
+ self.MSP430poke(0x0200,temp); #restore old value.
+ self.MSP430releasecpu();
+
+ def MSP430dumpbsl(self):
+ i=0xC00;
+ while i<0x1000:
+ print "%04x %04x" % (i, self.MSP430peek(i));
+ i+=2;
+
+++ /dev/null
-#!/usr/bin/env python
-# GoodFET Client Application
-#
-# (C) 2009 Travis Goodspeed <travis at radiantmachines.com>
-#
-# This code is ugly as sin, for bootstrapping the firmware only.
-# Rewrite cleanly as soon as is convenient.
-
-import sys, time, string, cStringIO, struct
-sys.path.append("/usr/lib/tinyos")
-import serial
-
-
-class Client:
- def __init__(self, *args, **kargs):
- print "inited\n";
- def timeout(self):
- print "timout\n";
- def serInit(self, port):
- """Open the serial port"""
- self.serialport = serial.Serial(
- port,
- 9600,
- parity = serial.PARITY_NONE
- )
- #Drop DTR, which is !RST, low to begin the app.
- self.serialport.setDTR(0);
- self.serialport.flushInput()
- self.serialport.flushOutput()
-
- #Read and handle the initial command.
- time.sleep(1);
- client.readcmd(); #Read the first command.
- 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));
- self.serialport.write(chr(verb));
- self.serialport.write(chr(count));
- #print "count=%02x, len(data)=%04x" % (count,len(data));
- if count!=0:
- for d in data:
- self.serialport.write(chr(d));
- self.readcmd(); #Uncomment this later, to ensure a response.
- def readcmd(self):
- """Read a reply from the GoodFET."""
- self.app=ord(self.serialport.read(1));
- self.verb=ord(self.serialport.read(1));
- self.count=ord(self.serialport.read(1));
- if self.count>0:
- self.data=self.serialport.read(self.count);
- #print "%02x %02x %02x" % (self.app, self.verb, self.count);
-
- #Monitor stuff
- def peekbyte(self,address):
- """Read a byte of memory from the monitor."""
- self.data=[address&0xff,address>>8];
- self.writecmd(0,0x02,2,self.data);
- #self.readcmd();
- return ord(self.data[0]);
- def peekword(self,address):
- """Read a word of memory from the monitor."""
- return self.peekbyte(address)+(self.peekbyte(address+1)<<8);
- def pokebyte(self,address,value):
- """Set a byte of memory by the monitor."""
- self.data=[address&0xff,address>>8,value];
- self.writecmd(0,0x03,3,self.data);
- return ord(self.data[0]);
-
- def monitortest(self):
- """Self-test several functions through the monitor."""
- print "Performing self-test.";
-
- if self.peekword(0x0c00)!=0x0c04:
- print "ERROR Fetched wrong value from 0x0c04.";
- self.pokebyte(0x0021,0); #Drop LED
- if self.peekbyte(0x0021)!=0:
- print "ERROR, P1OUT not cleared.";
- self.pokebyte(0x0021,1); #Light LED
-
- print "Self-test complete.";
-
- def spisetup(self):
- """Moved the FET into the SPI application."""
- print "Initializing SPI.";
- self.writecmd(1,0x10,0,self.data); #SPI/SETUP
- #self.readcmd();
- def spitrans8(self,byte):
- """Read and write 8 bits by SPI."""
- self.data=[byte];
- self.writecmd(1,0,1,self.data); #SPI exchange
- #self.readcmd();
-
- if self.app!=1 or self.verb!=0:
- print "Error in SPI transaction; app=%02x, verb=%02x" % (self.app, self.verb);
- return ord(self.data[0]);
-
-client=Client();
-client.serInit("/dev/ttyUSB0")
-
-client.monitortest();
-
-client.spisetup();
-while 1:
- print "%02x" % client.spitrans8(5);
- time.sleep(0.1);
--- /dev/null
+#!/usr/bin/env python
+
+from GoodFET import GoodFET;
+
+
+client=GoodFET();
+client.serInit("/dev/ttyUSB0")
+
+client.MSP430test();
+#client.MSP430dumpbsl();
+
+# client.MSP430setup();
+# client.MSP430start();
+# client.MSP430haltcpu();
+# ident=client.MSP430peek(0x0ff0);
+# print "Target identifies as %04x." % ident;
+
PORT=/dev/ttyUSB0
-BSL=tos-bsl --invert-reset --invert-test -c $(PORT)
+BSL=tos-bsl --invert-reset --invert-test -c $(PORT) --speed=38400
#mcu=msp430x1611
mcu=msp430x1612
CC=msp430-gcc -g -mmcu=$(mcu) -DGCC $(GCCINC) -I ../include
-apps= monitor/monitor.c spi/spi.c i2c/i2c.c chipcon/chipcon.c jtag/jtag.c
+apps= monitor/monitor.c spi/spi.c i2c/i2c.c chipcon/chipcon.c jtag/jtag.c jtag/jtag430.c
libs= ../lib/msp430f1612.c ../lib/command.c
app=goodfet
goodfet.hex: goodfet
+run:
+ ../../client/goodfet.msp430
install: $(app)
- $(BSL) -e -p $(app)
- $(BSL) -P $(app) -r
+ $(BSL) -e -p $(app).hex
+ $(BSL) -P $(app).hex -r
$(app): $(app).c $(libs) $(apps)
$(app).hex: $(app)
msp430-objcopy goodfet -O ihex goodfet.hex
case JTAG:\r
jtaghandle(app,verb,len);\r
break;\r
+ case JTAG430:\r
+ jtag430handle(app,verb,len);\r
+ break;\r
default:\r
txdata(app,NOK,0);\r
break;\r
--- /dev/null
+GoodFET JTAG Applications
+by Travis Goodspeed
+
+Most MSP430 macros come from definitions in SLAU265A.
+
--- /dev/null
+
+#include "platform.h"
+#include "command.h"
+#include "jtag.h"
+
+
+//! Set the program counter.
+void jtag430_setpc(unsigned int adr){
+ jtag_ir_shift8(IR_CNTRL_SIG_16BIT);
+ jtag_dr_shift16(0x3401);// release low byte
+ jtag_ir_shift8(IR_DATA_16BIT);
+ jtag_dr_shift16(0x4030);//Instruction to load PC
+ CLRTCLK;
+ SETTCLK;
+ jtag_dr_shift16(adr);// Value for PC
+ CLRTCLK;
+ jtag_ir_shift8(IR_ADDR_CAPTURE);
+ SETTCLK;
+ CLRTCLK ;// Now PC is set to "PC_Value"
+ jtag_ir_shift8(IR_CNTRL_SIG_16BIT);
+ jtag_dr_shift16(0x2401);// low byte controlled by JTAG
+}
+
+//! Halt the CPU
+void jtag430_haltcpu(){
+ //jtag430_setinstrfetch();
+
+ jtag_ir_shift8(IR_DATA_16BIT);
+ jtag_dr_shift16(0x3FFF);//JMP $+0
+
+ CLRTCLK;
+ jtag_ir_shift8(IR_CNTRL_SIG_16BIT);
+ jtag_dr_shift16(0x2409);//set JTAG_HALT bit
+ SETTCLK;
+}
+
+//! Release the CPU
+void jtag430_releasecpu(){
+ CLRTCLK;
+ jtag_ir_shift8(IR_CNTRL_SIG_16BIT);
+ jtag_dr_shift16(0x2401);
+ jtag_ir_shift8(IR_ADDR_CAPTURE);
+ SETTCLK;
+}
+
+//! Read data from address
+unsigned int jtag430_readmem(unsigned int adr){
+ unsigned int toret;
+
+ CLRTCLK;
+ jtag_ir_shift8(IR_CNTRL_SIG_16BIT);
+ if(adr>0xFF)
+ jtag_dr_shift16(0x2409);//word read
+ else
+ jtag_dr_shift16(0x2419);//byte read
+ jtag_ir_shift8(IR_ADDR_16BIT);
+ jtag_dr_shift16(adr);//address
+ jtag_ir_shift8(IR_DATA_TO_ADDR);
+ SETTCLK;
+
+ CLRTCLK;
+ toret=jtag_dr_shift16(0x0000);//16 bit return
+
+ return toret;
+}
+
+//! Write data to address.
+void jtag430_writemem(unsigned int adr, unsigned int data){
+ CLRTCLK;
+ jtag_ir_shift8(IR_CNTRL_SIG_16BIT);
+ if(adr>0xFF)
+ jtag_dr_shift16(0x2408);//word write
+ else
+ jtag_dr_shift16(0x2418);//byte write
+ jtag_ir_shift8(IR_ADDR_16BIT);
+ jtag_dr_shift16(adr);
+ jtag_ir_shift8(IR_DATA_TO_ADDR);
+ jtag_dr_shift16(data);
+ SETTCLK;
+
+}
+
+//! Write data to address.
+void jtag430_writeflash(unsigned int adr, unsigned int data){
+ //TODO; this is complicated.
+}
+
+
+//! Reset the TAP state machine.
+void jtag430_resettap(){
+ int i;
+ // Settle output
+ SETTMS;
+ SETTDI;
+ SETTCK;
+
+ // Navigate to reset state.
+ // Should be at least six.
+ for(i=0;i<4;i++){
+ CLRTCK;
+ SETTCK;
+ }
+
+ // test-logic-reset
+ CLRTCK;
+ CLRTMS;
+ SETTCK;
+ SETTMS;
+ // idle
+
+
+ /* sacred, by spec.
+ Sometimes this isn't necessary. */
+ // fuse check
+ CLRTMS;
+ delay(50);
+ SETTMS;
+ CLRTMS;
+ delay(50);
+ SETTMS;
+ /**/
+
+}
+
+//! Start JTAG, take pins
+void jtag430_start(){
+ jtagsetup();
+
+ //Known-good starting position.
+ //Might be unnecessary.
+ SETTST;
+ SETRST;
+ delay(0xFFFF);
+
+ //Entry sequence from Page 67 of SLAU265A for 4-wire MSP430 JTAG
+ CLRRST;
+ delay(100);
+ CLRTST;
+ delay(50);
+ SETTST;
+ delay(50);
+ SETRST;
+ P5DIR&=~RST;
+ delay(0xFFFF);
+}
+
+//! Set CPU to Instruction Fetch
+void jtag430_setinstrfetch(){
+ jtag_ir_shift8(IR_CNTRL_SIG_CAPTURE);
+
+ // Wait until instruction fetch state.
+ while(1){
+ if (jtag_dr_shift16(0x0000) & 0x0080)
+ return;
+ CLRTCLK;
+ SETTCLK;
+ }
+}
+
+//! Handles unique MSP430 JTAG commands. Forwards others to JTAG.
+void jtag430handle(unsigned char app,
+ unsigned char verb,
+ unsigned char len){
+ unsigned char i;
+ switch(verb){
+ case START:
+ //Enter JTAG mode.
+ jtag430_start();
+ //TAP setup, fuse check
+ jtag430_resettap();
+ txdata(app,verb,0);
+ break;
+ case JTAG430_HALTCPU:
+ jtag430_haltcpu();
+ txdata(app,verb,0);
+ break;
+ case JTAG430_RELEASECPU:
+ jtag430_releasecpu();
+ txdata(app,verb,0);
+ break;
+ case JTAG430_SETINSTRFETCH:
+ jtag430_setinstrfetch();
+ txdata(app,verb,0);
+ break;
+
+
+ case JTAG430_READMEM:
+ case PEEK:
+ cmddataword[0]=jtag430_readmem(cmddataword[0]);
+ txdata(app,verb,2);
+ break;
+ case JTAG430_WRITEMEM:
+ case POKE:
+ jtag430_writemem(cmddataword[0],cmddataword[1]);
+ txdata(app,verb,0);
+ break;
+ case JTAG430_WRITEFLASH:
+ jtag430_writeflash(cmddataword[0],cmddataword[1]);
+ txdata(app,verb,0);
+ break;
+ case JTAG430_SETPC:
+ jtag430_setpc(cmddataword[0]);
+ txdata(app,verb,0);
+ break;
+ default:
+ jtaghandle(app,verb,len);
+ }
+}
+
#define CC_MASS_ERASE_FLASH 0x97
#define CC_PROGRAM_FLASH 0x98
+//JTAG commands
+#define JTAG_IR_SHIFT 0x80
+#define JTAG_DR_SHIFT 0x81
+#define JTAG_DR_SHIFT20 0x91
+
+//JTAG430 commands
+#define JTAG430_HALTCPU 0xA0
+#define JTAG430_RELEASECPU 0xA1
+#define JTAG430_SETINSTRFETCH 0xC1
+#define JTAG430_SETPC 0xC2
+#define JTAG430_WRITEMEM 0xE0
+#define JTAG430_WRITEFLASH 0xE1
+#define JTAG430_READMEM 0xE2
+
+
//! Handle a command. Defined in goodfet.c
void handle(unsigned char app,
unsigned char verb,
+#include <signal.h>
+#include <io.h>
+#include <iomacros.h>
+
+
+// Generic Commands
//! Shift 8 bits of the IR.
unsigned char jtag_ir_shift8(unsigned char);
//! Shift 16 bits of the DR.
-unsigned int jtag_dr_shift16(unsigned int in);
+unsigned int jtag_dr_shift16(unsigned int);
+//! Stop JTAG, release pins
+void jtag_stop();
+
+
+// JTAG430 Commands
+
+//! Start JTAG, unique to the '430.
+void jtag430_start();
+//! Reset the TAP state machine, check the fuse.
+void jtag430_resettap();
+
+//High-level Macros follow
+//! Write data to address.
+void jtag430_writemem(unsigned int adr, unsigned int data);
+//! Read data from address
+unsigned int jtag430_readmem(unsigned int adr);
+//! Halt the CPU
+void jtag430_haltcpu();
+//! Release the CPU
+void jtag430_releasecpu();
+//! Set CPU to Instruction Fetch
+void jtag430_setinstrfetch();
+//! Set the program counter.
+void jtag430_setpc(unsigned int adr);
+//! Write data to address.
+void jtag430_writeflash(unsigned int adr, unsigned int data);
+
+//Pins. Both SPI and JTAG names are acceptable.
+//#define SS BIT0
+#define MOSI BIT1
+#define MISO BIT2
+#define SCK BIT3
+
+#define TMS BIT0
+#define TDI BIT1
+#define TDO BIT2
+#define TCK BIT3
+
+#define TCLK TDI
+
+//These are not on P5
+#define RST BIT6
+#define TST BIT0
+
+//This could be more accurate.
+//Does it ever need to be?
+#define JTAGSPEED 20
+#define JTAGDELAY(x) delay(x)
+
+#define SETMOSI P5OUT|=MOSI
+#define CLRMOSI P5OUT&=~MOSI
+#define SETCLK P5OUT|=SCK
+#define CLRCLK P5OUT&=~SCK
+#define READMISO (P5IN&MISO?1:0)
+#define SETTMS P5OUT|=TMS
+#define CLRTMS P5OUT&=~TMS
+#define SETTCK P5OUT|=TCK
+#define CLRTCK P5OUT&=~TCK
+#define SETTDI P5OUT|=TDI
+#define CLRTDI P5OUT&=~TDI
+
+#define SETTST P4OUT|=TST
+#define CLRTST P4OUT&=~TST
+#define SETRST P2OUT|=RST
+#define CLRRST P2OUT&=~RST
+
+#define SETTCLK SETTDI
+#define CLRTCLK CLRTDI
+
+extern int savedtclk;
+#define SAVETCLK savedtclk=P5OUT&TCLK;
+#define RESTORETCLK if(savedtclk) P5OUT|=TCLK; else P5OUT&=~TCLK
+
+//JTAG commands, bit-swapped
+#define IR_CNTRL_SIG_16BIT 0xC8 // 0x13
+#define IR_CNTRL_SIG_CAPTURE 0x28 // 0x14
+#define IR_CNTRL_SIG_RELEASE 0xA8 // 0x15
+// Instructions for the JTAG Fuse
+#define IR_PREPARE_BLOW 0x44 // 0x22
+#define IR_EX_BLOW 0x24 // 0x24
+// Instructions for the JTAG data register
+#define IR_DATA_16BIT 0x82 // 0x41
+#define IR_DATA_QUICK 0xC2 // 0x43
+// Instructions for the JTAG PSA mode
+#define IR_DATA_PSA 0x22 // 0x44
+#define IR_SHIFT_OUT_PSA 0x62 // 0x46
+// Instructions for the JTAG address register
+#define IR_ADDR_16BIT 0xC1 // 0x83
+#define IR_ADDR_CAPTURE 0x21 // 0x84
+#define IR_DATA_TO_ADDR 0xA1 // 0x85
+// Bypass instruction
+#define IR_BYPASS 0xFF // 0xFF
+
//! Delay for a count.
void delay(unsigned int count){
volatile unsigned int i=count;
- while(i--);
+ while(i--) asm("nop");
}