jtag support.

This commit is contained in:
nvt-se 2007-06-28 13:43:24 +00:00
parent ff3e2b8bd8
commit d7c489f0b2
13 changed files with 1408 additions and 0 deletions

View file

@ -0,0 +1,18 @@
ifndef JTAG
JTAG := $(CONTIKI)/platform/$(TARGET)/buildscripts/jtag/pyjtag/jtag.py
endif
ifndef JTAG_PORT
JTAG_PORT = /dev/ppi0
endif
%.u: %.$(TARGET)
$(JTAG) -l $(JTAG_PORT) -e
$(JTAG) -l $(JTAG_PORT) -D -D -S -R 2048 -p $^
$(JTAG) -l $(JTAG_PORT) -D -r
r:
$(JTAG) -l $(JTAG_PORT) -r
erase:
$(JTAG) -l $(JTAG_PORT) -e

View file

@ -0,0 +1,18 @@
ifndef JTAG
JTAG := $(CONTIKI)/platform/$(TARGET)/buildscripts/jtag/pyjtag/jtag.py
endif
ifndef JTAG_PORT
JTAG_PORT = /dev/parport0
endif
%.u: %.$(TARGET)
$(JTAG) -l $(JTAG_PORT) -e
$(JTAG) -l $(JTAG_PORT) -D -D -S -R 2048 -p $^
$(JTAG) -l $(JTAG_PORT) -D -r
r:
$(JTAG) -l $(JTAG_PORT) -r
erase:
$(JTAG) -l $(JTAG_PORT) -e

View file

@ -0,0 +1,7 @@
%.u: %.ihex
msp430-jtag -eI $^
#CW=cw23
#%.u: %.ihex
# $(CW) -d f430p $^

Binary file not shown.

View file

@ -0,0 +1,318 @@
#!/usr/bin/env python
import struct
# ELF object file reader
# (C) 2003 cliechti@gmx.net
# Python license
# size alignment
# Elf32_Addr 4 4 Unsigned program address
# Elf32_Half 2 2 Unsigned medium integer
# Elf32_Off 4 4 Unsigned file offset
# Elf32_Sword 4 4 Signed large integer
# Elf32_Word 4 4 Unsigned large integer
# unsignedchar 1 1 Unsigned small integer
#define EI_NIDENT 16
#~ typedef struct{
#~ unsigned char e_ident[EI_NIDENT];
#~ Elf32_Half e_type;
#~ Elf32_Half e_machine;
#~ Elf32_Word e_version;
#~ Elf32_Addr e_entry;
#~ Elf32_Off e_phoff;
#~ Elf32_Off e_shoff;
#~ Elf32_Word e_flags;
#~ Elf32_Half e_ehsize;
#~ Elf32_Half e_phentsize;
#~ Elf32_Half e_phnum;
#~ Elf32_Half e_shentsize;
#~ Elf32_Half e_shnum;
#~ Elf32_Half e_shstrndx;
#~ } Elf32_Ehdr;
#Section Header
#~ typedef struct {
#~ Elf32_Word sh_name;
#~ Elf32_Word sh_type;
#~ Elf32_Word sh_flags;
#~ Elf32_Addr sh_addr;
#~ Elf32_Off sh_offset;
#~ Elf32_Word sh_size;
#~ Elf32_Word sh_link;
#~ Elf32_Word sh_info;
#~ Elf32_Word sh_addralign;
#~ Elf32_Word sh_entsize;
#~ } Elf32_Shdr;
#~ typedef struct {
#~ Elf32_Word p_type;
#~ Elf32_Off p_offset;
#~ Elf32_Addr p_vaddr;
#~ Elf32_Addr p_paddr;
#~ Elf32_Word p_filesz;
#~ Elf32_Word p_memsz;
#~ Elf32_Word p_flags;
#~ Elf32_Word p_align;
#~ } Elf32_Phdr;
class ELFException(Exception): pass
class ELFSection:
"""read and store a section"""
Elf32_Shdr = "<IIIIIIIIII" #header format
#section types
SHT_NULL = 0
SHT_PROGBITS = 1
SHT_SYMTAB = 2
SHT_STRTAB = 3
SHT_RELA = 4
SHT_HASH = 5
SHT_DYNAMIC = 6
SHT_NOTE = 7
SHT_NOBITS = 8
SHT_REL = 9
SHT_SHLIB = 10
SHT_DYNSYM = 11
SHT_LOPROC = 0x70000000L
SHT_HIPROC = 0x7fffffffL
SHT_LOUSER = 0x80000000L
SHT_HIUSER = 0xffffffffL
#section attribute flags
SHF_WRITE = 0x1
SHF_ALLOC = 0x2
SHF_EXECINSTR = 0x4
SHF_MASKPROC = 0xf0000000
def __init__(self):
"""creat a new empty section object"""
(self.sh_name, self.sh_type, self.sh_flags, self.sh_addr,
self.sh_offset, self.sh_size, self.sh_link, self.sh_info,
self.sh_addralign, self.sh_entsize) = [0]*10
self.name = None
self.data = None
self.lma = None
def fromString(self, s):
"""get section header from string"""
(self.sh_name, self.sh_type, self.sh_flags, self.sh_addr,
self.sh_offset, self.sh_size, self.sh_link, self.sh_info,
self.sh_addralign, self.sh_entsize) = struct.unpack(self.Elf32_Shdr, s)
def __str__(self):
"""pretty print for debug..."""
return "%s(%s, sh_type=%s, sh_flags=%s, "\
"sh_addr=0x%04x, sh_offset=0x%04x, sh_size=%s, sh_link=%s, "\
"sh_info=%s, sh_addralign=%s, sh_entsize=%s, lma=0x%04x)" % (
self.__class__.__name__,
self.name is not None and "%r" % self.name or "sh_name=%s" % self.sh_name,
self.sh_type, self.sh_flags, self.sh_addr,
self.sh_offset, self.sh_size, self.sh_link, self.sh_info,
self.sh_addralign, self.sh_entsize, self.lma)
class ELFProgramHeader:
"""Store and parse a program header"""
Elf32_Phdr = "<IIIIIIII" #header format
#segmet types
PT_NULL = 0
PT_LOAD = 1
PT_DYNAMIC = 2
PT_INTERP = 3
PT_NOTE = 4
PT_SHLIB = 5
PT_PHDR = 6
PT_LOPROC = 0x70000000L
PT_HIPROC = 0x7fffffffL
#segment flags
PF_R = 0x4 #segment is readable
PF_W = 0x2 #segment is writable
PF_X = 0x1 #segment is executable
def __init__(self):
"""create a new, empty segment/program header"""
(self.p_type, self.p_offset, self.p_vaddr, self.p_paddr,
self.p_filesz, self.p_memsz, self.p_flags, self.p_align) = [0]*8
self.data = None
def fromString(self, s):
"""parse header info from string"""
(self.p_type, self.p_offset, self.p_vaddr, self.p_paddr,
self.p_filesz, self.p_memsz, self.p_flags,
self.p_align) = struct.unpack(self.Elf32_Phdr, s)
def __str__(self):
"""pretty print for debug..."""
return "%s(p_type=%s, p_offset=0x%04x, p_vaddr=0x%04x, p_paddr=0x%04x, "\
"p_filesz=%s, p_memsz=%s, p_flags=%s, "\
"p_align=%s)" % (
self.__class__.__name__,
self.p_type, self.p_offset, self.p_vaddr, self.p_paddr,
self.p_filesz, self.p_memsz, self.p_flags,
self.p_align)
class ELFObject:
"""Object to read and handle an LEF object file"""
#header information
Elf32_Ehdr = "<16sHHIIIIIHHHHHH"
#offsets within e_ident
EI_MAG0 = 0 #File identification
EI_MAG1 = 1 #File identification
EI_MAG2 = 2 #File identification
EI_MAG3 = 3 #File identification
EI_CLASS = 4 #File class
EI_DATA = 5 #Data encoding
EI_VERSION = 6 #File version
EI_PAD = 7 #Start of padding bytes
EI_NIDENT = 16 #Size of e_ident[]
#elf file type flags
ET_NONE = 0 #No file type
ET_REL = 1 #Relocatable file
ET_EXEC = 2 #Executable file
ET_DYN = 3 #Shared object file
ET_CORE = 4 #Core file
ET_LOPROC = 0xff00 #Processor-specific
ET_HIPROC = 0xffff #Processor-specific
#ELF format
ELFCLASSNONE = 0 #Invalid class
ELFCLASS32 = 1 #32-bit objects
ELFCLASS64 = 2 #64-bit objects
#encoding
ELFDATANONE = 0 #Invalid data encoding
ELFDATA2LSB = 1 #See below
ELFDATA2MSB = 2 #See below
def __init__(self):
"""create a new elf object"""
(self.e_ident, self.e_type, self.e_machine, self.e_version,
self.e_entry, self.e_phoff, self.e_shoff,
self.e_flags, self.e_ehsize, self.e_phentsize, self.e_phnum,
self.e_shentsize, self.e_shnum, self.e_shstrndx) = [0]*14
def fromFile(self, fileobj):
"""read all relevant data from fileobj.
the file must be seekable"""
#get file header
(self.e_ident, self.e_type, self.e_machine, self.e_version,
self.e_entry, self.e_phoff, self.e_shoff,
self.e_flags, self.e_ehsize, self.e_phentsize, self.e_phnum,
self.e_shentsize, self.e_shnum, self.e_shstrndx) = struct.unpack(
self.Elf32_Ehdr, fileobj.read(struct.calcsize(self.Elf32_Ehdr)))
#verify if its a known format and realy an ELF file
if self.e_ident[0:4] != '\x7fELF' and\
self.e_ident[self.EI_CLASS] != self.ELFCLASS32 and\
self.e_ident[self.EI_DATA] != self.ELFDATA2LSB and\
self.e_ident[self.EI_VERSION] != 1:
raise ELFException("Not a valid ELF file")
#load programm headers
self.programmheaders = []
if self.e_phnum:
#load program headers
fileobj.seek(self.e_phoff)
for sectionnum in range(self.e_phnum):
shdr = (fileobj.read(self.e_phentsize) + '\0'* struct.calcsize(ELFProgramHeader.Elf32_Phdr))[0:struct.calcsize(ELFProgramHeader.Elf32_Phdr)]
psection = ELFProgramHeader()
psection.fromString(shdr)
if psection.p_offset: #skip if section has invalid offset in file
self.programmheaders.append(psection)
#~ #get the segment data from the file for each prg header
#~ for phdr in self.programmheaders:
#~ fileobj.seek(phdr.p_offset)
#~ phdr.data = fileobj.read(phdr.p_filesz)
#~ #pad if needed
#~ if phdr.p_filesz < phdr.p_memsz:
#~ phdr.data = phdr.data + '\0' * (phdr.p_memsz-phdr.p_filesz)
#load sections
self.sections = []
fileobj.seek(self.e_shoff)
for sectionnum in range(self.e_shnum):
shdr = (fileobj.read(self.e_shentsize) + '\0'* struct.calcsize(ELFSection.Elf32_Shdr))[0:struct.calcsize(ELFSection.Elf32_Shdr)]
elfsection = ELFSection()
elfsection.fromString(shdr)
self.sections.append(elfsection)
#load data for all sections
for section in self.sections:
fileobj.seek(section.sh_offset)
data = fileobj.read(section.sh_size)
section.data = data
if section.sh_type == ELFSection.SHT_STRTAB:
section.values = data.split('\0')
section.lma = self.getLMA(section)
#get section names
for section in self.sections:
start = self.sections[self.e_shstrndx].data[section.sh_name:]
section.name = start.split('\0')[0]
def getSection(self, name):
"""get section by name"""
for section in self.sections:
if section.name == '.text':
return section
def getProgrammableSections(self):
"""get all program headers that are marked as executable and
have suitable attributes to be code"""
res = []
for p in self.programmheaders:
#~ print p
#~ if section.sh_flags & self.SHF_ALLOC and section.name not in ('.data', '.data1', '.bss'):
#~ if p.p_type == ELFProgramHeader.PT_LOAD:# and p.p_paddr == p.p_vaddr and p.p_flags & ELFProgramHeader.PF_X:
if p.p_type == ELFProgramHeader.PT_LOAD:
res.append(p)
return res
def getLMA(self, section):
#magic load memory address calculation ;-)
for p in self.programmheaders:
if (p.p_paddr != 0 and \
p.p_type == ELFProgramHeader.PT_LOAD and \
p.p_vaddr != p.p_paddr and \
p.p_vaddr <= section.sh_addr and \
(p.p_vaddr + p.p_memsz >= section.sh_addr + section.sh_size) \
and (not (section.sh_flags & ELFSection.SHF_ALLOC and section.sh_type != ELFSection.SHT_NOBITS) \
or (p.p_offset <= section.sh_offset \
and (p.p_offset + p.p_filesz >= section.sh_offset + section.sh_size)))):
return section.sh_addr + p.p_paddr - p.p_vaddr
return section.sh_addr
def getSections(self):
"""get sections relevant for the application"""
res = []
for section in self.sections:
if section.sh_flags & ELFSection.SHF_ALLOC and section.sh_type != ELFSection.SHT_NOBITS:
res.append(section)
return res
def __str__(self):
"""pretty print for debug..."""
return "%s(self.e_type=%r, self.e_machine=%r, self.e_version=%r, sections=%r)" % (
self.__class__.__name__,
self.e_type, self.e_machine, self.e_version,
[section.name for section in self.sections])
if __name__ == '__main__':
print "This is only a module test!"
elf = ELFObject()
elf.fromFile(open("test.elf"))
if elf.e_type != ELFObject.ET_EXEC:
raise Exception("No executable")
print elf
#~ print repr(elf.getSection('.text').data)
#~ print [(s.name, hex(s.sh_addr)) for s in elf.getSections()]
print "-"*20
for p in elf.sections: print p
print "-"*20
for p in elf.getSections(): print p
print "-"*20
for p in elf.getProgrammableSections(): print p

Binary file not shown.

View file

@ -0,0 +1,49 @@
#!/usr/bin/env python
"""Test File generator.
This tool generates a hex file, of given size, ending on address
0xffff.
USAGE: hen-ihex.py size_in_kilobyte
The resulting Intel-hex file is output to stdout, use redirection
to save the data to a file.
"""
#return a string with data in intel hex format
def makeihex(address, data):
out = []
start = 0
while start<len(data):
end = start + 16
if end > len(data): end = len(data)
out.append(_ihexline(address, [ord(x) for x in data[start:end]]))
start += 16
address += 16
out.append(_ihexline(address, [], end=1)) #append no data but an end line
return ''.join(out)
def _ihexline(address, buffer, end=0):
out = []
if end:
type = 1
else:
type = 0
out.append( ':%02X%04X%02X' % (len(buffer),address&0xffff,type) )
sum = len(buffer) + ((address>>8)&255) + (address&255)
for b in buffer:
if b == None: b = 0 #substitute nonexistent values with zero
out.append('%02X' % (b&255) )
sum += b&255
out.append('%02X\n' %( (-sum)&255))
return ''.join(out)
if __name__ == '__main__':
import struct, sys
if len(sys.argv) != 2:
print __doc__
sys.exit(1)
size = int(sys.argv[1]) #in kilo
startadr = 0x10000 - 1024*size
data = ''.join([struct.pack(">H", x) for x in range(startadr, startadr+ 1024*size, 2)])
print makeihex(startadr, data)

View file

@ -0,0 +1,108 @@
Name "install-pyjtag"
OutFile "install-pyjtag.exe"
!define SF_SELECTED 1
!define SF_SUBSEC 2
!define SF_SUBSECEND 4
!define SF_BOLD 8
!define SF_RO 16
!define SF_EXPAND 32
!define SECTION_OFF 0xFFFFFFFE
LicenseText License
LicenseData license.txt
SetOverwrite on
SetDateSave on
; The default installation directory
InstallDir $PROGRAMFILES\mspgcc
; Registry key to check for directory (so if you install again, it will
; overwrite the old one automatically)
InstallDirRegKey HKLM SOFTWARE\mspgcc "rootdir"
; The text to prompt the user to enter a directory
DirText "This will install the pyjtag executables. You can choose the same \
directory as for the other mspgcc tools."
; The text to prompt the user to enter a directory
ComponentText "Select which optional things you want installed."
Section "msp430-jtag (required)"
SectionIn RO
SetOutPath $INSTDIR
File /r bin
File /oname=license-pyjtag.txt license.txt
File /oname=readme-pyjtag.txt readme.txt
File /oname=bin\jtag.py jtag.py
; Write the installation path into the registry
WriteRegStr HKLM SOFTWARE\mspgcc "rootdir" "$INSTDIR"
; Write the uninstall keys for Windows
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\mspgcc-pyjtag" "DisplayName" "mspgcc pyjtag (remove only)"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\mspgcc-pyjtag" "UninstallString" '"$INSTDIR\uninstall-pyjtag.exe"'
WriteUninstaller "uninstall-pyjtag.exe"
SectionEnd
Section "giveio (needed on Win NT/2k/XP, but NOT on 9x/ME)"
SetOutPath $INSTDIR\bin
File ..\jtag\hardware_access\giveio\giveio.sys
File ..\jtag\hardware_access\giveio\loaddrv.exe
SetOutPath $INSTDIR
nsExec::ExecToLog '$INSTDIR\bin\loaddrv.exe install giveio $INSTDIR\bin\giveio.sys'
Pop $0 ;return value/error/timeout
IntCmp $0 2 ext_here ;assume its alredy installed
IntCmp $0 0 0 ext_err ext_err ;if not 0 -> error
nsExec::ExecToLog '$INSTDIR\bin\loaddrv.exe start giveio'
Pop $0 ;return value/error/timeout
IntCmp $0 0 0 ext_err ext_err ;if not 0 -> error
nsExec::ExecToLog '$INSTDIR\bin\loaddrv.exe starttype giveio auto'
Pop $0 ;return value/error/timeout
IntCmp $0 0 0 ext_err ext_err ;if not 0 -> error
WriteRegStr HKLM SOFTWARE\mspgcc "giveio" "started"
Goto ext_ok
ext_err:
DetailPrint "Error while installing and starting giveio"
MessageBox MB_OK|MB_ICONSTOP "Error while installing and starting giveio"
Goto ext_ok
ext_here:
DetailPrint "Installing giveio gave an error, assuming its already installed"
ext_ok:
SectionEnd
; special uninstall section.
Section "Uninstall"
; remove registry keys
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\mspgcc-pyjtag"
DeleteRegKey HKLM SOFTWARE\NSIS_Example2
; remove files
Delete $INSTDIR\bin\msp430-jtag.exe
Delete $INSTDIR\bin\_parjtag.pyd
Delete $INSTDIR\bin\jtag.py
Delete $INSTDIR\bin\HIL.dll
Delete $INSTDIR\bin\MSP430mspgcc.dll
;XXX python22.dll is left installed as it is used by pybsl and other tools
Delete $INSTDIR\license-pyjtag.txt
Delete $INSTDIR\readme-pyjtag.txt
; giveio
; if it was started by us, stop it
ReadRegStr $0 HKLM SOFTWARE\mspgcc "giveio"
StrCmp $0 '' no_giveio
nsExec::ExecToLog '$INSTDIR\bin\loaddrv.exe stop giveio'
Pop $0 ;return value/error/timeout
IntCmp $0 0 0 giveio_err giveio_err ;if not 0 -> error
nsExec::ExecToLog '$INSTDIR\bin\loaddrv.exe remove giveio'
Pop $0 ;return value/error/timeout
IntCmp $0 0 0 giveio_err giveio_err ;if not 0 -> error
Goto no_giveio
giveio_err:
DetailPrint "Error while uninstalling giveio service"
MessageBox MB_OK|MB_ICONSTOP "Error while uninstalling giveio service"
no_giveio:
Delete loaddrv.exe
Delete giveio.sys
; MUST REMOVE UNINSTALLER, too
Delete $INSTDIR\uninstall-pyjtag.exe
SectionEnd

View file

@ -0,0 +1,604 @@
#!/usr/bin/env python
#Parallel JTAG programmer for the MSP430 embedded proccessor.
#
#(C) 2002 Chris Liechti <cliechti@gmx.net>
#this is distributed under a free software license, see license.txt
#
#Requires Python 2+ and the binary extension _parjtag.
import sys
import _parjtag
VERSION = "1.3"
DEBUG = 0 #disable debug messages by default
#frame specific consts
ERASE_MASS = 2
ERASE_MAIN = 1
ERASE_SGMT = 0
#states
FREERUNNING = 0
STOPPED = 1
#Configurations of the MSP430 driver
VERIFICATION_MODE = 0 #Verify data downloaded to FLASH memories.
RAMSIZE_OPTION = 1 #Change RAM used to download and program flash blocks
DEBUG_OPTION = 2 #Set debug level. Enables debug outputs.
#enumeration of output formats for uploads
HEX = 0
INTELHEX = 1
BINARY = 2
#exceptions
class JTAGException(Exception): pass
#for the use with memread
def hexdump( (adr, memstr) ):
"""Print a hex dump of data collected with memread
arg1: tuple with adress, memory
return None"""
count = 0
ascii = ''
for value in map(ord, memstr):
if not count: print "%04x: " % adr,
print "%02x" % value,
ascii += (32 <= value < 128) and chr(value) or '.'
count += 1
adr += 1
if count == 16:
count = 0
print " ", ascii
ascii = ''
if count < 16: print " "*(16-count), " ", ascii
def makeihex( (address, data) ):
"""work though the data and output lines in inzel hex format.
and end tag is appended"""
start = 0
while start<len(data):
end = start + 16
if end > len(data): end = len(data)
_ihexline(address, [ord(x) for x in data[start:end]])
start += 16
address += 16
_ihexline(address, [], type=1) #append no data but an end line
def _ihexline(address, buffer, type=0):
"""encode one line, output with checksum"""
sys.stdout.write( ':%02X%04X%02X' % (len(buffer), address & 0xffff, type) )
sum = len(buffer) + ((address >> 8) & 255) + (address & 255)
for b in buffer:
if b == None: b = 0 #substitute nonexistent values with zero
sys.stdout.write('%02X' % (b & 255))
sum += b&255
sys.stdout.write('%02X\n' %( (-sum) & 255))
class Segment:
"""store a string with memory contents along with its startaddress"""
def __init__(self, startaddress = 0, data=None):
if data is None:
self.data = ''
else:
self.data = data
self.startaddress = startaddress
def __getitem__(self, index):
return self.data[index]
def __len__(self):
return len(self.data)
def __repr__(self):
return "Segment(startaddress = 0x%04x, data=%r)" % (self.startaddress, self.data)
class Memory:
"""represent memory contents. with functions to load files"""
def __init__(self, filename=None):
self.segments = []
if filename:
self.filename = filename
self.loadFile(filename)
def append(self, seg):
self.segments.append(seg)
def __getitem__(self, index):
return self.segments[index]
def __len__(self):
return len(self.segments)
def loadIHex(self, file):
"""load data from a (opened) file in Intel-HEX format"""
segmentdata = []
currentAddr = 0
startAddr = 0
lines = file.readlines()
for l in lines:
if not l.strip(): continue #skip empty lines
if l[0] != ':': raise Exception("File Format Error\n")
l = l.strip() #fix CR-LF issues...
length = int(l[1:3],16)
address = int(l[3:7],16)
type = int(l[7:9],16)
check = int(l[-2:],16)
if type == 0x00:
if currentAddr != address:
if segmentdata:
self.segments.append( Segment(startAddr, ''.join(segmentdata)) )
startAddr = currentAddr = address
segmentdata = []
for i in range(length):
segmentdata.append( chr(int(l[9+2*i:11+2*i],16)) )
currentAddr = length + currentAddr
elif type == 0x01:
pass
else:
sys.stderr.write("Ignored unknown field (type 0x%02x) in ihex file.\n" % type)
if segmentdata:
self.segments.append( Segment(startAddr, ''.join(segmentdata)) )
def loadTIText(self, file):
"""load data from a (opened) file in TI-Text format"""
next = 1
currentAddr = 0
startAddr = 0
segmentdata = []
#Convert data for MSP430, TXT-File is parsed line by line
while next >= 1:
#Read one line
l = file.readline()
if not l: break #EOF
l = l.strip()
if l[0] == 'q': break
elif l[0] == '@': #if @ => new address => send frame and set new addr.
#create a new segment
if segmentdata:
self.segments.append( Segment(startAddr, ''.join(segmentdata)) )
startAddr = currentAddr = int(l[1:],16)
segmentdata = []
else:
for i in l.split():
segmentdata.append(chr(int(i,16)))
if segmentdata:
self.segments.append( Segment(startAddr, ''.join(segmentdata)) )
def loadELF(self, file):
"""load data from a (opened) file in ELF object format.
File must be seekable"""
import elf
obj = elf.ELFObject()
obj.fromFile(file)
if obj.e_type != elf.ELFObject.ET_EXEC:
raise Exception("No executable")
for section in obj.getSections():
if DEBUG:
sys.stderr.write("ELF section %s at 0x%04x %d bytes\n" % (section.name, section.lma, len(section.data)))
if len(section.data):
self.segments.append( Segment(section.lma, section.data) )
def loadFile(self, filename):
"""fill memory with the contents of a file. file type is determined from extension"""
#TODO: do a contents based detection
if filename[-4:].lower() == '.txt':
self.loadTIText(open(filename, "rb"))
elif filename[-4:].lower() in ('.a43', '.hex'):
self.loadIHex(open(filename, "rb"))
else:
self.loadELF(open(filename, "rb"))
def getMemrange(self, fromadr, toadr):
"""get a range of bytes from the memory. unavailable values are filled with 0xff."""
res = ''
toadr = toadr + 1 #python indxes are excluding end, so include it
while fromadr < toadr:
for seg in self.segments:
segend = seg.startaddress + len(seg.data)
if seg.startaddress <= fromadr and fromadr < segend:
if toadr > segend: #not all data in segment
catchlength = segend-fromadr
else:
catchlength = toadr-fromadr
res = res + seg.data[fromadr-seg.startaddress : fromadr-seg.startaddress+catchlength]
fromadr = fromadr + catchlength #adjust start
if len(res) >= toadr-fromadr:
break #return res
else: #undefined memory is filled with 0xff
res = res + chr(255)
fromadr = fromadr + 1 #adjust start
return res
class JTAG:
"""wrap the _parjtag extension"""
def __init__(self):
self.showprogess = 0
def connect(self, lpt=None):
"""connect to specified or default port"""
if lpt is None:
_parjtag.connect()
else:
_parjtag.connect(lpt)
def close(self):
"""release JTAG"""
_parjtag.release()
def uploadData(self, startaddress, size):
"""upload a datablock"""
if DEBUG > 1: sys.stderr.write("* uploadData()\n")
return _parjtag.memread(startaddress, size)
def actionMassErase(self):
"""Erase the flash memory completely (with mass erase command)"""
sys.stderr.write("Mass Erase...\n")
_parjtag.memerase(ERASE_MASS)
def actionMainErase(self):
"""Erase the MAIN flash memory, leave the INFO mem"""
sys.stderr.write("Erase Main Flash...\n")
_parjtag.memerase(ERASE_MAIN, 0xfffe)
def makeActionSegmentErase(self, address):
"""Selective segment erase"""
class SegmentEraser:
def __init__(self, segaddr):
self.address = segaddr
def __call__(self):
sys.stderr.write("Erase Segment @ 0x%04x...\n" % self.address)
_parjtag.memerase(ERASE_SGMT, self.address)
return SegmentEraser(address)
def actionEraseCheck(self):
"""check the erasure of required flash cells."""
sys.stderr.write("Erase Check by file ...\n")
if self.data is not None:
for seg in self.data:
data = _parjtag.memread(seg.startaddress, len(seg.data))
if data != '\xff'*len(seg.data): raise JTAGException("Erase check failed")
else:
raise JTAGException("cannot do erase check against data with not knowing the actual data")
def progess_update(self, count, total):
sys.stderr.write("\r%d%%" % (100*count/total))
def actionProgram(self):
"""program data into flash memory."""
if self.data is not None:
sys.stderr.write("Program ...\n")
if self.showprogess:
_parjtag.set_flash_callback(self.progess_update)
bytes = 0
for seg in self.data:
_parjtag.memwrite(seg.startaddress, seg.data)
bytes += len(seg.data)
if self.showprogess:
sys.stderr.write("\r")
sys.stderr.write("%i bytes programmed.\n" % bytes)
else:
raise JTAGException("programming without data not possible")
def actionVerify(self):
"""Verify programmed data"""
if self.data is not None:
sys.stderr.write("Verify ...\n")
for seg in self.data:
data = _parjtag.memread(seg.startaddress, len(seg.data))
if data != seg.data: raise JTAGException("Verify failed")
else:
raise JTAGException("verify without data not possible")
def actionReset(self):
"""perform a reset"""
sys.stderr.write("Reset device ...\n")
_parjtag.reset(0, 0)
def actionRun(self, address):
"""start program at specified address"""
raise NotImplementedError
#sys.stderr.write("Load PC with 0x%04x ...\n" % address)
def funclet(self):
"""download and start funclet"""
sys.stderr.write("Download and execute of funclet...\n")
if len(self.data) > 1:
raise JTAGException("don't know how to handle multiple segments in funclets")
_parjtag.funclet(self.data[0].data)
sys.stderr.write("Funclet OK.\n")
def usage():
"""print some help message"""
sys.stderr.write("""
USAGE: %s [options] [file]
Version: %s
If "-" is specified as file the data is read from the stdinput.
A file ending with ".txt" is considered to be in TIText format all
other filenames are considered IntelHex.
General options:
-h, --help Show this help screen.
-l, --lpt=name Specify an other parallel port.
(defaults to LPT1 (/dev/parport0 on unix)
-D, --debug Increase level of debug messages. This won't be
very useful for the average user...
-I, --intelhex Force fileformat to IntelHex
-T, --titext Force fileformat to be TIText
-f, --funclet The given file is a funclet (a small program to
be run in RAM)
-R, --ramsize Specify the amont of RAM to be used to program
flash (default 256).
Program Flow Specifiers:
-e, --masserase Mass Erase (clear all flash memory)
-m, --mainerase Erase main flash memory only
--eraseinfo Erase info flash memory only (0x1000-0x10ff)
--erase=address Selectively erase segment at the specified address
-E, --erasecheck Erase Check by file
-p, --program Program file
-v, --verify Verify by file
The order of the above options matters! The table is ordered by normal
execution order. For the options "Epv" a file must be specified.
Program flow specifiers default to "p" if a file is given.
Don't forget to specify "e" or "eE" when programming flash!
"p" already verifies the programmed data, "v" adds an additional
verification though uploading the written data for a 1:1 compare.
No default action is taken if "p" and/or "v" is given, say specifying
only "v" does a check by file of a programmed device.
Data retreiving:
-u, --upload=addr Upload a datablock (see also: -s).
-s, --size=num Size of the data block do upload. (Default is 2)
-x, --hex Show a hexadecimal display of the uploaded data.
(Default)
-b, --bin Get binary uploaded data. This can be used
to redirect the output into a file.
-i, --ihex Uploaded data is output in Intel HEX format.
This can be used to clone a device.
Do before exit:
-g, --go=address Start programm execution at specified address.
This implies option "w" (wait)
-r, --reset Reset connected MSP430. Starts application.
This is a normal device reset and will start
the programm that is specified in the reset
interrupt vector. (see also -g)
-w, --wait Wait for <ENTER> before closing parallel port.
""" % (sys.argv[0], VERSION))
def main():
global DEBUG
import getopt
filetype = None
filename = None
reset = 0
wait = 0
goaddr = None
jtag = JTAG()
toinit = []
todo = []
startaddr = None
size = 2
outputformat= HEX
lpt = None
funclet = None
ramsize = None
sys.stderr.write("MSP430 parallel JTAG programmer Version: %s\n" % VERSION)
try:
opts, args = getopt.getopt(sys.argv[1:],
"hl:weEmpvrg:Du:d:s:xbiITfR:S",
["help", "lpt=", "wait"
"masserase", "erasecheck", "mainerase", "program",
"erase=", "eraseinfo",
"verify", "reset", "go=", "debug",
"upload=", "download=", "size=", "hex", "bin", "ihex",
"intelhex", "titext", "funclet", "ramsize=", "progress"]
)
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(2)
for o, a in opts:
if o in ("-h", "--help"):
usage()
sys.exit()
elif o in ("-l", "--lpt"):
lpt = a
elif o in ("-w", "--wait"):
wait = 1
elif o in ("-e", "--masserase"):
toinit.append(jtag.actionMassErase) #Erase Flash
elif o in ("-E", "--erasecheck"):
toinit.append(jtag.actionEraseCheck) #Erase Check (by file)
elif o in ("-m", "--mainerase"):
toinit.append(jtag.actionMainErase) #Erase main Flash
elif o == "--erase":
try:
seg = int(a, 0)
toinit.append(jtag.makeActionSegmentErase(seg))
except ValueError:
sys.stderr.write("segment address must be a valid number in dec, hex or octal\n")
sys.exit(2)
elif o == "--eraseinfo":
toinit.append(jtag.makeActionSegmentErase(0x1000))
toinit.append(jtag.makeActionSegmentErase(0x1080))
elif o in ("-p", "--program"):
todo.append(jtag.actionProgram) #Program file
elif o in ("-v", "--verify"):
todo.append(jtag.actionVerify) #Verify file
elif o in ("-r", "--reset"):
reset = 1
elif o in ("-g", "--go"):
try:
goaddr = int(a, 0) #try to convert decimal
except ValueError:
sys.stderr.write("upload address must be a valid number in dec, hex or octal\n")
sys.exit(2)
elif o in ("-D", "--debug"):
DEBUG = DEBUG + 1
elif o in ("-u", "--upload"):
try:
startaddr = int(a, 0) #try to convert number of any base
except ValueError:
sys.stderr.write("upload address must be a valid number in dec, hex or octal\n")
sys.exit(2)
elif o in ("-s", "--size"):
try:
size = int(a, 0)
except ValueError:
sys.stderr.write("upload address must be a valid number in dec, hex or octal\n")
sys.exit(2)
#outut formats
elif o in ("-x", "--hex"):
outputformat = HEX
elif o in ("-b", "--bin"):
outputformat = BINARY
elif o in ("-i", "--ihex"):
outputformat = INTELHEX
#input formats
elif o in ("-I", "--intelhex"):
filetype = 0
elif o in ("-T", "--titext"):
filetype = 1
#others
elif o in ("-f", "--funclet"):
funclet = 1
elif o in ("-R", "--ramsize"):
try:
ramsize = int(a, 0)
except ValueError:
sys.stderr.write("ramsize must be a valid number in dec, hex or octal\n")
sys.exit(2)
elif o in ("-S", "--progress"):
jtag.showprogess = 1
if len(args) == 0:
sys.stderr.write("Use -h for help\n")
elif len(args) == 1: #a filename is given
if not funclet:
if not todo: #if there are no actions yet
todo.extend([ #add some useful actions...
jtag.actionProgram,
])
filename = args[0]
else: #number of args is wrong
usage()
sys.exit(2)
if DEBUG: #debug infos
sys.stderr.write("debug level set to %d\n" % DEBUG)
_parjtag.configure(DEBUG_OPTION, DEBUG)
sys.stderr.write("python version: %s\n" % sys.version)
#sanity check of options
if goaddr and reset:
sys.stderr.write("Warning: option --reset ignored as --go is specified!\n")
reset = 0
if startaddr and reset:
sys.stderr.write("Warning: option --reset ignored as --upload is specified!\n")
reset = 0
#prepare data to download
jtag.data = Memory() #prepare downloaded data
if filetype is not None: #if the filetype is given...
if filename is None:
raise ValueError("no filename but filetype specified")
if filename == '-': #get data from stdin
file = sys.stdin
else:
file = open(filename,"rb") #or from a file
if filetype == 0: #select load function
jtag.data.loadIHex(file) #intel hex
elif filetype == 1:
jtag.data.loadTIText(file) #TI's format
else:
raise ValueError("illegal filetype specified")
else: #no filetype given...
if filename == '-': #for stdin:
jtag.data.loadIHex(sys.stdin) #assume intel hex
elif filename:
jtag.data.loadFile(filename) #autodetect otherwise
if DEBUG > 5: sys.stderr.write("File: %r\n" % filename)
try:
jtag.connect(lpt) #try to open port
except IOError:
raise #do not handle here
else: #continue if open was successful
if ramsize is not None:
_parjtag.configure(RAMSIZE_OPTION, ramsize)
#initialization list
if toinit: #erase and erase check
if DEBUG: sys.stderr.write("Preparing device ...\n")
for f in toinit: f()
#work list
if todo:
if DEBUG > 0: #debug
#show a nice list of sheduled actions
sys.stderr.write("TODO list:\n")
for f in todo:
try:
sys.stderr.write(" %s\n" % f.func_name)
except AttributeError:
sys.stderr.write(" %r\n" % f)
for f in todo: f() #work through todo list
if reset: #reset device first if desired
jtag.actionReset()
if funclet is not None: #download and start funclet
jtag.funclet()
if goaddr is not None: #start user programm at specified address
jtag.actionRun(goaddr) #load PC and execute
#upload datablock and output
if startaddr is not None:
if goaddr: #if a program was started...
raise NotImplementedError
#TODO:
#sys.stderr.write("Waiting to device for reconnect for upload: ")
data = jtag.uploadData(startaddr, size) #upload data
if outputformat == HEX: #depending on output format
hexdump( (startaddr, data) ) #print a hex display
elif outputformat == INTELHEX:
makeihex( (startaddr, data) ) #ouput a intel-hex file
else:
sys.stdout.write(data) #binary output w/o newline!
wait = 0 #wait makes no sense as after the upload the device is still stopped
if wait: #wait at the end if desired
sys.stderr.write("Press <ENTER> ...\n") #display a prompt
raw_input() #wait for newline
_parjtag.reset(1, 1) #reset and release target
#~ jtag.actionReset()
jtag.close() #Release communication port
if __name__ == '__main__':
try:
main()
except SystemExit:
raise #let pass exit() calls
except KeyboardInterrupt:
if DEBUG: raise #show full trace in debug mode
sys.stderr.write("user abort.\n") #short messy in user mode
sys.exit(1) #set errorlevel for script usage
except Exception, msg: #every Exception is caught and displayed
if DEBUG: raise #show full trace in debug mode
sys.stderr.write("\nAn error occoured:\n%s\n" % msg) #short messy in user mode
sys.exit(1) #set errorlevel for script usage

View file

@ -0,0 +1,62 @@
Copyright (c) 2001-2002 Chris Liechti <cliechti@gmx.net>
All Rights Reserved.
This is the Python license. In short, you can use this product in
commercial and non-commercial applications, modify it, redistribute it.
A notification to the author when you use and/or modify it is welcome.
TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING THIS SOFTWARE
============================================
LICENSE AGREEMENT
-----------------
1. This LICENSE AGREEMENT is between the copyright holder of this
product, and the Individual or Organization ("Licensee") accessing
and otherwise using this product in source or binary form and its
associated documentation.
2. Subject to the terms and conditions of this License Agreement,
the copyright holder hereby grants Licensee a nonexclusive,
royalty-free, world-wide license to reproduce, analyze, test,
perform and/or display publicly, prepare derivative works, distribute,
and otherwise use this product alone or in any derivative version,
provided, however, that copyright holders License Agreement and
copyright holders notice of copyright are retained in this product
alone or in any derivative version prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on
or incorporates this product or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to this product.
4. The copyright holder is making this product available to Licensee
on an "AS IS" basis. THE COPYRIGHT HOLDER MAKES NO REPRESENTATIONS
OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT
LIMITATION, THE COPYRIGHT HOLDER MAKES NO AND DISCLAIMS ANY
REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR
ANY PARTICULAR PURPOSE OR THAT THE USE OF THIS PRODUCT WILL
NOT INFRINGE ANY THIRD PARTY RIGHTS.
5. THE COPYRIGHT HOLDER SHALL NOT BE LIABLE TO LICENSEE OR ANY
OTHER USERS OF THIS PRODUCT FOR ANY INCIDENTAL, SPECIAL, OR
CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING,
DISTRIBUTING, OR OTHERWISE USING THIS PRODUCT, OR ANY
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY
THEREOF.
6. This License Agreement will automatically terminate upon a
material breach of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any
relationship of agency, partnership, or joint venture between the
copyright holder and Licensee. This License Agreement does not grant
permission to use trademarks or trade names from the copyright holder
in a trademark sense to endorse or promote products or services of
Licensee, or any third party.
8. By copying, installing or otherwise using this product, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.

View file

@ -0,0 +1,33 @@
.PHONY: all FORCE clean windist
all: windist
#wrap py to exe and build windows installer
windist:
python setup.py py2exe
rm -r bin
mv dist/jtag/jtag.exe dist/msp430-jtag.exe
mv dist/jtag/* dist/
rmdir dist/jtag
mv dist bin
rm -r build
#generate test files
fill60k.a43:
python gen-ihex.py 60 >$@
fill48k.a43:
python gen-ihex.py 48 >$@
fill32k.a43:
python gen-ihex.py 32 >$@
fill16k.a43:
python gen-ihex.py 16 >$@
fill8k.a43:
python gen-ihex.py 8 >$@
fill4k.a43:
python gen-ihex.py 4 >$@
#clean up the mess...
clean:
rm -r dist build bin

View file

@ -0,0 +1,182 @@
pyJTAG
------
Software to talk to the parallel port JTAG PCB as seen with the FET kits.
It is released under a free software license,
see license.txt for more details.
(C) 2002-2003 Chris Liechti <cliechti@gmx.net>
Features
--------
- understands TI-Text and Intel-hex
- download to Flash and/or RAM, erase, verify
- reset device
- load addres into R0/PC and run
- upload a memory block MSP->PC (output as binary data or hex dump)
- written in Python, runs on Win32, Linux, BSD
- use per command line, or in a Python script
Requirements
------------
- Linux, BSD, Un*x or Windows PC
- Python 2.0 or newer, 2.2 recomeded
- Parallel JTAG hardware with an MSP430 device connected
Installation
------------
Python installations are available from www.python.org. On Windows simply
use the installer. The win32all package has an installer too. These
installations should run fine with the deafults.
On Linux just Python is needed. On some distributions is Python 1.5.2
installed per default. You may meed to change the first line in the script
from "python" to "python2". Maybe Python 2.x is in a separate package that
has to be installed. There are rpm and deb binary packages and a source
tarball available through the Python homepage.
The pyjtag archive can simply be unpacked to a directory, Windows users
can use WinZip or WinRar among others to extract the gzipped tar file.
If you want to run it from everywhere the directory where the file jtag.py
is, should be added to the PATH.
Look at "~/.profile", "/etc/profile" on Linux, "autoexec.bat" on Win9x/ME,
System Properties/Environment in Win2000/NT/XP.
_parjtag.so/dll from the jtag archive must be copied to the same directory as
jtag.py. On Windows also MSP430mspgcc.dll and HIL.dll must be located in the
same dir or somewhere in the PATH.
Short introduction
------------------
This software uses the JTAG hardware that comes with the FET kits. It is
connected to the parallel port.
The program can be started by typing "python jtag.py" in a console. Often
it works also with just "jtag.py" or "./jtag.py".
USAGE: jtag.py [options] [file]
If "-" is specified as file the data is read from the stdinput.
A file ending with ".txt" is considered to be in TIText format all
other filenames are considered IntelHex.
General options:
-h, --help Show this help screen.
-l, --lpt=name Specify an other parallel port.
(defaults to LPT1 (/dev/parport0 on unix)
-D, --debug Increase level of debug messages. This won't be
very useful for the average user...
-I, --intelhex Force fileformat to IntelHex
-T, --titext Force fileformat to be TIText
-f, --funclet The given file is a funclet (a small program to
be run in RAM)
-R, --ramsize Specify the amont of RAM to be used to program
flash (default 256).
Program Flow Specifiers:
-e, --masserase Mass Erase (clear all flash memory)
-m, --mainerase Erase main flash memory only
--eraseinfo Erase info flash memory only (0x1000-0x10ff)
--erase=address Selectively erase segment at the specified address
-E, --erasecheck Erase Check by file
-p, --program Program file
-v, --verify Verify by file
The order of the above options matters! The table is ordered by normal
execution order. For the options "Epv" a file must be specified.
Program flow specifiers default to "p" if a file is given.
Don't forget to specify "e" or "eE" when programming flash!
"p" already verifies the programmed data, "v" adds an additional
verification though uploading the written data for a 1:1 compare.
No default action is taken if "p" and/or "v" is given, say specifying
only "v" does a check by file of a programmed device.
Data retreiving:
-u, --upload=addr Upload a datablock (see also: -s).
-s, --size=num Size of the data block do upload. (Default is 2)
-x, --hex Show a hexadecimal display of the uploaded data.
(Default)
-b, --bin Get binary uploaded data. This can be used
to redirect the output into a file.
-i, --ihex Uploaded data is output in Intel HEX format.
This can be used to clone a device.
Do before exit:
-g, --go=address Start programm execution at specified address.
This implies option "w" (wait)
-r, --reset Reset connected MSP430. Starts application.
This is a normal device reset and will start
the programm that is specified in the reset
interrupt vector. (see also -g)
-w, --wait Wait for <ENTER> before closing parallel port.
Examples
--------
These examples assume that you have added the installation directory to
the PATH. Type the full path to jtag.py otherwise and maybe use
"python jtag.py". Depending on installation it may also appear under the
name "msp430-jtag".
jtag.py -e
Only erase flash.
jtag.py -eErw 6port.a43
Erase flash, erase check, download an executable, run it (reset)
and wait.
jtag.py -mS -R 2048 6port.a43
Use ramsize option on a device with 2k RAM to speed up
download. Of course any value from 128B up to the maximum
a device has is allowed.
The progress and mainerase options are also activated.
Only erasing the main memory is useful to keep calibration
data in the information memory.
jtag.py 6port.a43
Download of an executable to en empty (new or erased) device.
(Note that in new devices some of the first bytes in the
information memory are random data. If data should be
downloaded there, specify -eE.)
jtag.py --go=0x220 ramtest.a43
Download a program into RAM and run it, may not work
with all devices.
jtag.py -f blinking.a43
Download a program into RAM and run it. It must be
a special format with "startadr", "entrypoint",
"exitpoint" as the first three words in the data
and it must end on "jmp $". See MSP430debug sources
for more info.
jtag.py -u 0x0c00 -s 1024
Get a memory dump in HEX, from the bootstrap loader.
or save the binary in a file:
"python jtag.py -u 0x0c00 -s 1024 -b >dump.bin"
or as an intel-hex file:
"python jtag.py -u 0x0c00 -s 1024 -i >dump.a43"
jtag.py -r
Just start the user program (with a reset).
cat 6port.a43|jtag.py -e -
Pipe the data from "cat" to jtag.py to erase and program the
flash. (un*x example, don't forget the dash at the end of the
line)
History
-------
1.0 public release
1.1 fix of verify error
1.2 use the verification during programming
1.3 meinerase, progress options, ihex output
References
----------
- Python: http://www.python.org
- Texas Instruments MSP430 Homepage, links to Datasheets and Application
Notes: http://www.ti.com/sc/msp430

View file

@ -0,0 +1,9 @@
# setup.py
from distutils.core import setup
import glob
import py2exe
setup(
name="msp430-jtag",
scripts=["jtag.py"],
)