Mercurial > lcfOS
diff python/utils/stlink.py @ 292:534b94b40aa8
Fixup reorganize
author | Windel Bouwman |
---|---|
date | Wed, 27 Nov 2013 08:06:42 +0100 |
parents | python/stlink.py@c694ec551f34 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/stlink.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,367 @@ +import struct, time +from usb import UsbContext, UsbDevice +from devices import Interface, STLinkException, registerInterface +import adi + +""" + More or less copied from: + https://github.com/texane/stlink + Tracing from: + https://github.com/obe1line/stlink-trace + +""" +ST_VID, STLINK2_PID = 0x0483, 0x3748 + +def checkDevice(device): + return device.VendorId == ST_VID and device.ProductId == STLINK2_PID + +DFU_MODE, MASS_MODE, DEBUG_MODE = 0, 1, 2 + +CORE_RUNNING = 0x80 +CORE_HALTED = 0x81 + +# Commands: +GET_VERSION = 0xf1 +DEBUG_COMMAND = 0xf2 +DFU_COMMAND = 0xf3 +GET_CURRENT_MODE = 0xf5 + +# dfu commands: +DFU_EXIT = 0x7 + +# debug commands: +DEBUG_ENTER = 0x20 +DEBUG_EXIT = 0x21 +DEBUG_ENTER_SWD = 0xa3 +DEBUG_GETSTATUS = 0x01 +DEBUG_FORCEDEBUG = 0x02 +DEBUG_RESETSYS = 0x03 +DEBUG_READALLREGS = 0x04 +DEBUG_READREG = 0x5 +DEBUG_WRITEREG = 0x6 +DEBUG_READMEM_32BIT = 0x7 +DEBUG_WRITEMEM_32BIT = 0x8 +DEBUG_RUNCORE = 0x9 +DEBUG_STEPCORE = 0xa + +JTAG_WRITEDEBUG_32BIT = 0x35 +JTAG_READDEBUG_32BIT = 0x36 +TRACE_GET_BYTE_COUNT = 0x42 + +# cortex M3 +CM3_REG_CPUID = 0xE000ED00 + +@registerInterface((ST_VID, STLINK2_PID)) +class STLink2(Interface): + """ STlink2 interface implementation. """ + def __init__(self, stlink2=None): + self.devHandle = None + if not stlink2: + context = UsbContext() + stlink2s = list(filter(checkDevice, context.DeviceList)) + if not stlink2s: + raise STLinkException('Could not find an ST link 2 interface') + if len(stlink2s) > 1: + print('More then one stlink2 found, picking first one') + stlink2 = stlink2s[0] + assert isinstance(stlink2, UsbDevice) # Nifty type checking + assert checkDevice(stlink2) + self.stlink2 = stlink2 + def __del__(self): + if self.IsOpen: + if self.CurrentMode == DEBUG_MODE: + self.exitDebugMode() + self.close() + def __str__(self): + if self.IsOpen: + return 'STlink2 device version {0}'.format(self.Version) + else: + return 'STlink2 device' + def open(self): + if self.IsOpen: + return + self.devHandle = self.stlink2.open() + if self.devHandle.Configuration != 1: + self.devHandle.Configuration = 1 + self.devHandle.claimInterface(0) + + # First initialization: + if self.CurrentMode == DFU_MODE: + self.exitDfuMode() + if self.CurrentMode != DEBUG_MODE: + self.enterSwdMode() + #self.reset() + def close(self): + if self.IsOpen: + self.devHandle.close() + self.devHandle = None + @property + def IsOpen(self): + return self.devHandle != None + # modes: + def getCurrentMode(self): + cmd = bytearray(16) + cmd[0] = GET_CURRENT_MODE + reply = self.send_recv(cmd, 2) # Expect 2 bytes back + return reply[0] + CurrentMode = property(getCurrentMode) + @property + def CurrentModeString(self): + modes = {DFU_MODE: 'dfu', MASS_MODE: 'massmode', DEBUG_MODE:'debug'} + return modes[self.CurrentMode] + def exitDfuMode(self): + cmd = bytearray(16) + cmd[0:2] = DFU_COMMAND, DFU_EXIT + self.send_recv(cmd) + def enterSwdMode(self): + cmd = bytearray(16) + cmd[0:3] = DEBUG_COMMAND, DEBUG_ENTER, DEBUG_ENTER_SWD + self.send_recv(cmd) + def exitDebugMode(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_EXIT + self.send_recv(cmd) + + def getVersion(self): + cmd = bytearray(16) + cmd[0] = GET_VERSION + data = self.send_recv(cmd, 6) # Expect 6 bytes back + # Parse 6 bytes into various versions: + b0, b1, b2, b3, b4, b5 = data + stlink_v = b0 >> 4 + jtag_v = ((b0 & 0xf) << 2) | (b1 >> 6) + swim_v = b1 & 0x3f + vid = (b3 << 8) | b2 + pid = (b5 << 8) | b4 + return 'stlink={0} jtag={1} swim={2} vid:pid={3:04X}:{4:04X}'.format(\ + stlink_v, jtag_v, swim_v, vid, pid) + Version = property(getVersion) + + @property + def ChipId(self): + return self.read_debug32(0xE0042000) + @property + def CpuId(self): + u32 = self.read_debug32(CM3_REG_CPUID) + implementer_id = (u32 >> 24) & 0x7f + variant = (u32 >> 20) & 0xf + part = (u32 >> 4) & 0xfff + revision = u32 & 0xf + return implementer_id, variant, part, revision + def getStatus(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_GETSTATUS + reply = self.send_recv(cmd, 2) + return reply[0] + Status = property(getStatus) + @property + def StatusString(self): + s = self.Status + statii = {CORE_RUNNING: 'CORE RUNNING', CORE_HALTED: 'CORE HALTED'} + if s in statii: + return statii[s] + return 'Unknown status' + + def reset(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_RESETSYS + self.send_recv(cmd, 2) + + # debug commands: + def step(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_STEPCORE + self.send_recv(cmd, 2) + def run(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_RUNCORE + self.send_recv(cmd, 2) + def halt(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_FORCEDEBUG + self.send_recv(cmd, 2) + + # Tracing: + def traceEnable(self): + self.write_debug32(0xE000EDF0, 0xA05F0003) + + # Enable TRCENA: + DEMCR = 0xE000EDFC + v = self.read_debug32(DEMCR) + v |= (1 << 24) + self.write_debug32(DEMCR, v) + + # ?? Enable write?? + self.write_debug32(0xE0002000, 0x2) # + + # DBGMCU_CR: + self.write_debug32(0xE0042004, 0x27) # Enable trace in async mode + + # TPIU config: + self.write_debug32(0xE0040004, 0x00000001) # current port size register --> 1 == port size = 1 + self.write_debug32(0xE0040010, 0x23) # random clock divider?? + self.write_debug32(0xE00400F0, 0x2) # selected pin protocol (2 == NRZ) + self.write_debug32(0xE0040304, 0x100) # continuous formatting + + # ITM config: + self.write_debug32(0xE0000FB0, 0xC5ACCE55) # Unlock write access to ITM + self.write_debug32(0xE0000F80, 0x00010005) # ITM Enable, sync enable, ATB=1 + self.write_debug32(0xE0000E00, 0xFFFFFFFF) # Enable all trace ports in ITM + self.write_debug32(0xE0000E40, 0x0000000F) # Set privilege mask for all 32 ports. + def writePort0(self, v32): + self.write_debug32(0xE0000000, v32) + def getTraceByteCount(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, 0x42 + reply = self.send_recv(cmd, 2) + return struct.unpack('<H', reply[0:2])[0] + def readTraceData(self): + bsize = self.getTraceByteCount() + if bsize > 0: + td = self.recv_ep3(bsize) + print(td) + else: + print('no trace data') + + # Helper 1 functions: + def write_debug32(self, address, value): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, JTAG_WRITEDEBUG_32BIT + cmd[2:10] = struct.pack('<II', address, value) + r = self.send_recv(cmd, 2) + def read_debug32(self, address): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, JTAG_READDEBUG_32BIT + cmd[2:6] = struct.pack('<I', address) # pack into u32 little endian + reply = self.send_recv(cmd, 8) + return struct.unpack('<I', reply[4:8])[0] + def write_reg(self, reg, value): + cmd = bytearray(16) + cmd[0:3] = DEBUG_COMMAND, DEBUG_WRITEREG, reg + cmd[3:7] = struct.pack('<I', value) + r = self.send_recv(cmd, 2) + def read_reg(self, reg): + cmd = bytearray(16) + cmd[0:3] = DEBUG_COMMAND, DEBUG_READREG, reg + reply = self.send_recv(cmd, 4) + return struct.unpack('<I', reply)[0] + def read_all_regs(self): + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_READALLREGS + reply = self.send_recv(cmd, 84) + fmt = '<' + 'I' * 21 # unpack 21 register values + return list(struct.unpack(fmt, reply)) + def write_mem32(self, address, content): + assert len(content) % 4 == 0 + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_WRITEMEM_32BIT + cmd[2:8] = struct.pack('<IH', address, len(content)) + self.send_recv(cmd) + self.send_recv(content) + def read_mem32(self, address, length): + assert length % 4 == 0 + cmd = bytearray(16) + cmd[0:2] = DEBUG_COMMAND, DEBUG_READMEM_32BIT + cmd[2:8] = struct.pack('<IH', address, length) + reply = self.send_recv(cmd, length) # expect memory back! + return reply + + # Helper 2 functions: + def send_recv(self, tx, rxsize=0): + """ Helper function that transmits and receives data in bulk mode. """ + # TODO: we could use here the non-blocking libusb api. + tx = bytes(tx) + #assert len(tx) == 16 + self.devHandle.bulkWrite(2, tx) # write to endpoint 2 + if rxsize > 0: + return self.devHandle.bulkRead(1, rxsize) # read from endpoint 1 + def recv_ep3(self, rxsize): + return self.devHandle.bulkRead(3, rxsize) + +if __name__ == '__main__': + # Test program + sl = STLink2() + sl.open() + sl.reset() + print('version:', sl.Version) + print('mode before doing anything:', sl.CurrentModeString) + if sl.CurrentMode == DFU_MODE: + sl.exitDfuMode() + sl.enterSwdMode() + print('mode after entering swd mode:', sl.CurrentModeString) + + i = sl.ChipId + print('chip id: 0x{0:X}'.format(i)) + print('cpu: {0}'.format(sl.CpuId)) + + print('status: {0}'.format(sl.StatusString)) + + # test registers: + sl.write_reg(0, 0xdeadbeef) + sl.write_reg(1, 0xcafebabe) + sl.write_reg(2, 0xc0ffee) + sl.write_reg(3, 0x1337) + sl.write_reg(5, 0x1332) + sl.write_reg(6, 0x12345) + assert sl.read_reg(3) == 0x1337 + assert sl.read_reg(5) == 0x1332 + assert sl.read_reg(6) == 0x12345 + regs = sl.read_all_regs() + for i in range(len(regs)): + print('R{0}=0x{1:X}'.format(i, regs[i])) + + print('tracing') + sl.traceEnable() + sl.run() + sl.writePort0(0x1337) # For test + time.sleep(0.1) + td = sl.readTraceData() + print('trace data:', td) + + # Test CoreSight registers: + idr4 = sl.read_debug32(0xE0041fd0) + print('idr4 =', idr4) + + print('== ADI ==') + a = adi.Adi(sl) + a.parseRomTable(0xE00FF000) # why is rom table at 0xE00FF000? + print('== ADI ==') + + # Detect ROM table: + id4 = sl.read_debug32(0xE00FFFD0) + id5 = sl.read_debug32(0xE00FFFD4) + id6 = sl.read_debug32(0xE00FFFD8) + id7 = sl.read_debug32(0xE00FFFDC) + id0 = sl.read_debug32(0xE00FFFE0) + id1 = sl.read_debug32(0xE00FFFE4) + id2 = sl.read_debug32(0xE00FFFE8) + id3 = sl.read_debug32(0xE00FFFEC) + pIDs = [id0, id1, id2, id3, id4, id5, id6, id7] + print(pIDs) + + print('reading from 0xE00FF000') + scs = sl.read_debug32(0xE00FF000) + print('scs {0:08X}'.format(scs)) + dwt = sl.read_debug32(0xE00FF004) + print('dwt {0:08X}'.format(dwt)) + fpb = sl.read_debug32(0xE00FF008) + print('fpb {0:08X}'.format(fpb)) + itm = sl.read_debug32(0xE00FF00C) + print('itm {0:08X}'.format(itm)) + tpiu = sl.read_debug32(0xE00FF010) + print('tpiu {0:08X}'.format(tpiu)) + etm = sl.read_debug32(0xE00FF014) + print('etm {0:08X}'.format(etm)) + assert sl.read_debug32(0xE00FF018) == 0x0 # end marker + + devid = sl.read_debug32(0xE0040FC8) + print('TPIU_DEVID: {0:X}'.format(devid)) + devtype = sl.read_debug32(0xE0040FCC) + print('TPIU_TYPEID: {0:X}'.format(devtype)) + + sl.exitDebugMode() + print('mode at end:', sl.CurrentModeString) + + sl.close() + print('Test succes!') +