Mercurial > lcfOS
changeset 114:f42268da614f
Connected to stm32f4discovery
author | Windel Bouwman |
---|---|
date | Sat, 05 Jan 2013 19:07:14 +0100 |
parents | 1f40be088ee8 |
children | 92b2bf0da1ec |
files | python/stlink.py python/usb.py |
diffstat | 2 files changed, 214 insertions(+), 32 deletions(-) [+] |
line wrap: on
line diff
--- a/python/stlink.py Sat Jan 05 00:06:27 2013 +0100 +++ b/python/stlink.py Sat Jan 05 19:07:14 2013 +0100 @@ -1,3 +1,4 @@ +import struct, time from usb import UsbContext class STLinkException(Exception): @@ -8,11 +9,28 @@ STLINK2_PID=0x3748 return device.VendorId == ST_VID and device.ProductId == STLINK2_PID -XFER_TO_DEV=0 -XFER_FROM_DEV=0x80 +DFU_MODE, MASS_MODE, DEBUG_MODE = range(3) +# Commands: +GET_VERSION = 0xf1 +DEBUG_COMMAND = 0xf2 +DFU_COMMAND = 0xf3 +GET_CURRENT_MODE = 0xf5 + +# dfu commands: +DFU_EXIT = 0x7 -class STLink(object): - DFU_MODE = 222 +# debug commands: +DEBUG_ENTER = 0x20 +DEBUG_EXIT = 0x21 +DEBUG_ENTER_SWD = 0xa3 +DEBUG_GETSTATUS = 0x01 + +JTAG_READDEBUG_32BIT = 0x36 + +# cortex M3 +CM3_REG_CPUID = 0xE000ED00 + +class STLink: def __init__(self): self.context = UsbContext() def open(self): @@ -23,22 +41,129 @@ if len(stlink2s) > 1: print('More then one stlink2 found, picking first one') stlink2 = stlink2s[0] - dev = stlink2.open() - if dev.Configuration != 1: - dev.Configuration = 1 - dev.claimInterface(0) + self.devHandle = stlink2.open() + if self.devHandle.Configuration != 1: + self.devHandle.Configuration = 1 + self.devHandle.claimInterface(0) + def close(self): + pass def getCurrentMode(self): - print('get cur mode') - rep_len = 2 - self.fillCommand(self, XFER_FROM_DEV, rep_len) - size = self.send_recv(1, cmd, data) - return self.q_buf[0] + cmd = bytearray(16) + cmd[0] = GET_CURRENT_MODE + reply = self.send_recv(cmd, 2) # Expect 2 bytes back + return reply[0] CurrentMode = property(getCurrentMode) - def fillCommand(self, di, rl): - bytes(b'USBC') - pass - def reset(self): - pass - def send_recv(self, txbuf, rxbuf): - pass + @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] = DFU_COMMAND + cmd[1] = DFU_EXIT + self.send_recv(cmd) + def enterSwdMode(self): + cmd = bytearray(16) + cmd[0] = DEBUG_COMMAND + cmd[1] = DEBUG_ENTER + cmd[2] = DEBUG_ENTER_SWD + self.send_recv(cmd) + def exitDebugMode(self): + cmd = bytearray(16) + cmd[0] = DEBUG_COMMAND + cmd[1] = 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 status(self): + cmd = bytearray(16) + cmd[0] = DEBUG_COMMAND + cmd[1] = DEBUG_GETSTATUS + reply = self.send_recv(cmd, 2) + return reply[0] + def step(self): + cmd = bytearray(16) + cmd[0] = DEBUG_COMMAND + cmd[1] = DEBUG_STEPCORE + self.send_recv(cmd, 2) + def run(self): + cmd = bytearray(16) + cmd[0] = DEBUG_COMMAND + cmd[1] = DEBUG_RUNCORE + self.send_recv(cmd, 2) + + # Helper 1 functions: + def read_debug32(self, address): + cmd = bytearray(16) + cmd[0] = DEBUG_COMMAND + cmd[1] = 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] + + # Helper 2 functions: + def send_recv(self, tx, rxsize=0): + """ Helper function that transmits and receives data. """ + # TODO: we could use here the non-blocking libusb api. + tx = bytes(tx) + self.devHandle.bulkWrite(2, tx) # write to endpoint 2 + if rxsize > 0: + return self.devHandle.bulkRead(1, rxsize) # read from endpoint 1 + +knownChipIds = {0x1: 'x'} + +if __name__ == '__main__': + # Test program + sl = STLink() + sl.open() + 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 + if i in knownChipIds: + print('chip id: 0x{0:X} -> {1}'.format(i, knownChipIds[i])) + else: + print('chip id: 0x{0:X}'.format(i)) + print('cpu: {0}'.format(sl.CpuId)) + + print('status: {0}'.format(sl.status())) + + time.sleep(2.2) + + sl.exitDebugMode() + print('mode at end:', sl.CurrentModeString) + + sl.close() +
--- a/python/usb.py Sat Jan 05 00:06:27 2013 +0100 +++ b/python/usb.py Sat Jan 05 19:07:14 2013 +0100 @@ -1,12 +1,12 @@ -from ctypes import Structure, POINTER, CDLL -from ctypes import c_uint16, c_uint8, c_int, c_ssize_t -from ctypes import byref +from ctypes import Structure, POINTER, CDLL, CFUNCTYPE +from ctypes import c_uint16, c_uint8, c_int, c_uint, c_ssize_t, c_void_p +from ctypes import byref, create_string_buffer # libusb wrapper: libusb = CDLL('libusb-1.0.so') # helper: -def buildfunc(name, argtypes, restype): +def buildfunc(name, argtypes, restype=c_int): f = getattr(libusb, name) f.argtypes = argtypes f.restype = restype @@ -34,6 +34,7 @@ CANCELLED=3, STALL=4, NO_DEVICE=5, OVERFLOW=6) # types +c_int_p = POINTER(c_int) class libusb_context(Structure): pass libusb_context_p = POINTER(libusb_context) @@ -69,6 +70,27 @@ ] libusb_device_descriptor_p = POINTER(libusb_device_descriptor) +""" +class libusb_transfer(Structure): + pass +libusb_transfer_p = POINTER(libusb_transfer) +libusb_transfer_cb_fn = CFUNCTYPE(None, libusb_transfer_p) +libusb_transfer._fields_ = [ + ('dev_handle', libusb_device_handle_p), + ('flags', c_uint8), + ('endpoint', c_uchar), + ('type', c_uchar), + ('timeout', c_uint), + ('status', c_int), # enum libusb_transfer_status + ('length', c_int), + ('actual_length', c_int), + ('callback', libusb_transfer_cb_fn), + ('userdata', c_void_p), + ('buffer', c_void_p), + ('num_iso_packets', c_int), + ('iso_packet_desc', libusb_iso_packet_descriptor) + ] +""" # functions buildfunc('libusb_init', [libusb_context_p_p], c_int) @@ -77,18 +99,21 @@ buildfunc('libusb_free_device_list', [libusb_device_p_p, c_int], None) buildfunc('libusb_get_bus_number', [libusb_device_p], c_uint8) buildfunc('libusb_get_device_address', [libusb_device_p], c_uint8) -buildfunc('libusb_get_device_speed', [libusb_device_p], c_int) +buildfunc('libusb_get_device_speed', [libusb_device_p]) buildfunc('libusb_unref_device', [libusb_device_p], None) -buildfunc('libusb_open', [libusb_device_p, libusb_device_handle_p_p], c_int) +buildfunc('libusb_open', [libusb_device_p, libusb_device_handle_p_p]) buildfunc('libusb_close', [libusb_device_handle_p], None) -buildfunc('libusb_get_configuration', \ - [libusb_device_handle_p, POINTER(c_int)], c_int) -buildfunc('libusb_set_configuration', [libusb_device_handle_p, c_int], c_int) -buildfunc('libusb_claim_interface', [libusb_device_handle_p, c_int], c_int) +buildfunc('libusb_get_configuration',[libusb_device_handle_p,POINTER(c_int)]) +buildfunc('libusb_set_configuration', [libusb_device_handle_p, c_int]) +buildfunc('libusb_claim_interface', [libusb_device_handle_p, c_int]) buildfunc('libusb_get_device_descriptor',\ - [libusb_device_p, libusb_device_descriptor_p], c_int) + [libusb_device_p, libusb_device_descriptor_p]) + +# synchronous functions: +buildfunc('libusb_bulk_transfer', [libusb_device_handle_p, c_uint8, \ + c_void_p, c_int, c_int_p, c_uint]) # pythonic API: @@ -159,6 +184,10 @@ self.ProductId, self.Speed) return r2 +USB_ENDPOINT_DIR_MASK = 0x80 +USB_ENDPOINT_IN = 0x80 +USB_ENDPOINT_OUT = 0x0 + class UsbDeviceHandle: """ Handle to a detected usb device """ def __init__(self, device, handle_p): @@ -176,7 +205,35 @@ def claimInterface(self, interface_number): r = libusb_claim_interface(self.handle_p, interface_number) if r != 0: raise UsbError('Error claiming interface', r) - + def bulkWrite(self, endpoint, data, timeout=0): + """ Synchronous bulk write """ + assert type(data) is bytes + # assure the endpoint indicates the correct: + endpoint = (endpoint & (~USB_ENDPOINT_DIR_MASK)) | USB_ENDPOINT_OUT + buf = create_string_buffer(data) + transferred = c_int() + r = libusb_bulk_transfer(self.handle_p, endpoint, buf, len(data), \ + byref(transferred), timeout) + if r != 0: + raise UsbError('Bulk write failed', r) + if transferred.value != len(data): + raise UsbError('Not all {0} transferred {1}'.format(len(data), \ + transferred.value)) + def bulkRead(self, endpoint, numbytes, timeout=0): + """ Synchronous bulk read """ + # assure the endpoint indicates the correct: + endpoint = (endpoint & (~USB_ENDPOINT_DIR_MASK)) | USB_ENDPOINT_IN + buf = create_string_buffer(numbytes) + transferred = c_int() + r = libusb_bulk_transfer(self.handle_p, endpoint, buf, numbytes, \ + byref(transferred), timeout) + if r != 0: + raise UsbError('Bulk read failed', r) + if transferred.value != numbytes: + raise UsbError('Not all {0} transferred {1}'.format(numbytes, \ + transferred.value)) + data = buf.raw[0:numbytes] + return data class UsbTransfer: def __init__(self):