From a653ba1562dc444e4be791e22264a89a3c6b4a19 Mon Sep 17 00:00:00 2001 From: travisutk Date: Thu, 18 Jun 2009 18:33:07 +0000 Subject: [PATCH] MSP430 JTAG works. git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@38 12e2690d-a6be-4b82-a7b7-67c4a43b65c8 --- client/{goodfet => GoodFET.py} | 83 ++++++++++--- client/goodfet.msp430 | 17 +++ firmware/apps/Makefile | 10 +- firmware/apps/goodfet.c | 3 + firmware/apps/jtag/Readme.txt | 5 + firmware/apps/jtag/jtag430.c | 209 +++++++++++++++++++++++++++++++++ firmware/include/command.h | 15 +++ firmware/include/jtag.h | 101 +++++++++++++++- firmware/lib/command.c | 2 +- 9 files changed, 425 insertions(+), 20 deletions(-) rename client/{goodfet => GoodFET.py} (55%) create mode 100755 client/goodfet.msp430 create mode 100644 firmware/apps/jtag/Readme.txt create mode 100644 firmware/apps/jtag/jtag430.c diff --git a/client/goodfet b/client/GoodFET.py similarity index 55% rename from client/goodfet rename to client/GoodFET.py index 78171b7..387eeab 100755 --- a/client/goodfet +++ b/client/GoodFET.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# GoodFET Client Application +# GoodFET Client Library # # (C) 2009 Travis Goodspeed # @@ -11,9 +11,10 @@ sys.path.append("/usr/lib/tinyos") import serial -class Client: +class GoodFET: def __init__(self, *args, **kargs): print "inited\n"; + self.data=[0]; def timeout(self): print "timout\n"; def serInit(self, port): @@ -30,7 +31,7 @@ class Client: #Read and handle the initial command. time.sleep(1); - client.readcmd(); #Read the first command. + self.readcmd(); #Read the first command. if(self.verb!=0x7F): print "Verb is wrong. Incorrect firmware?"; @@ -52,8 +53,8 @@ class Client: 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); - + #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.""" @@ -72,7 +73,7 @@ class Client: def monitortest(self): """Self-test several functions through the monitor.""" - print "Performing self-test."; + print "Performing monitor self-test."; if self.peekword(0x0c00)!=0x0c04: print "ERROR Fetched wrong value from 0x0c04."; @@ -97,13 +98,67 @@ class Client: 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); -client=Client(); -client.serInit("/dev/ttyUSB0") - -client.monitortest(); + 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; -client.spisetup(); -while 1: - print "%02x" % client.spitrans8(5); - time.sleep(0.1); diff --git a/client/goodfet.msp430 b/client/goodfet.msp430 new file mode 100755 index 0000000..8a17a26 --- /dev/null +++ b/client/goodfet.msp430 @@ -0,0 +1,17 @@ +#!/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; + diff --git a/firmware/apps/Makefile b/firmware/apps/Makefile index 1ffeb5a..40114b3 100644 --- a/firmware/apps/Makefile +++ b/firmware/apps/Makefile @@ -1,6 +1,6 @@ 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 @@ -10,7 +10,7 @@ GCCINC=-T ../ldscripts/161x.x 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 @@ -18,10 +18,12 @@ all: $(app) 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 diff --git a/firmware/apps/goodfet.c b/firmware/apps/goodfet.c index 19feb63..a8d5b7a 100644 --- a/firmware/apps/goodfet.c +++ b/firmware/apps/goodfet.c @@ -48,6 +48,9 @@ void handle(unsigned char app, case JTAG: jtaghandle(app,verb,len); break; + case JTAG430: + jtag430handle(app,verb,len); + break; default: txdata(app,NOK,0); break; diff --git a/firmware/apps/jtag/Readme.txt b/firmware/apps/jtag/Readme.txt new file mode 100644 index 0000000..862cb48 --- /dev/null +++ b/firmware/apps/jtag/Readme.txt @@ -0,0 +1,5 @@ +GoodFET JTAG Applications +by Travis Goodspeed + +Most MSP430 macros come from definitions in SLAU265A. + diff --git a/firmware/apps/jtag/jtag430.c b/firmware/apps/jtag/jtag430.c new file mode 100644 index 0000000..03541c1 --- /dev/null +++ b/firmware/apps/jtag/jtag430.c @@ -0,0 +1,209 @@ + +#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); + } +} + diff --git a/firmware/include/command.h b/firmware/include/command.h index 2c722c3..0c65462 100644 --- a/firmware/include/command.h +++ b/firmware/include/command.h @@ -40,6 +40,21 @@ extern unsigned char cmddata[256]; #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, diff --git a/firmware/include/jtag.h b/firmware/include/jtag.h index 6f9b6dc..17833d6 100644 --- a/firmware/include/jtag.h +++ b/firmware/include/jtag.h @@ -1,6 +1,105 @@ +#include +#include +#include + + +// 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 + diff --git a/firmware/lib/command.c b/firmware/lib/command.c index 44a853d..9a9421d 100644 --- a/firmware/lib/command.c +++ b/firmware/lib/command.c @@ -19,5 +19,5 @@ void txdata(unsigned char app, //! Delay for a count. void delay(unsigned int count){ volatile unsigned int i=count; - while(i--); + while(i--) asm("nop"); } -- 2.20.1