# HG changeset patch # User Windel Bouwman # Date 1358615764 -3600 # Node ID 654093a9a1e3f3eb2ca1c7d8a9e4c2ccfa76eeae # Parent 9e350a7dde9858ffa29e99f67635185982d37ca7 Added icons, improved device explorer diff -r 9e350a7dde98 -r 654093a9a1e3 python/chip.png Binary file python/chip.png has changed diff -r 9e350a7dde98 -r 654093a9a1e3 python/hardware.png Binary file python/hardware.png has changed diff -r 9e350a7dde98 -r 654093a9a1e3 python/ide.py --- a/python/ide.py Fri Jan 18 12:52:11 2013 +0100 +++ b/python/ide.py Sat Jan 19 18:16:04 2013 +0100 @@ -117,7 +117,7 @@ def __init__(self, parent=None): super(Ide, self).__init__(parent) self.setWindowTitle('LCFOS IDE') - self.compiler = KsCompiler() + self.compiler = None # TODO icon = QPixmap() icon.loadFromData(lcfospng) self.setWindowIcon(QIcon(icon)) diff -r 9e350a7dde98 -r 654093a9a1e3 python/lsusb.py --- a/python/lsusb.py Fri Jan 18 12:52:11 2013 +0100 +++ b/python/lsusb.py Sat Jan 19 18:16:04 2013 +0100 @@ -2,6 +2,29 @@ from usb import UsbContext +# try to read usb.ids: +vids = {} +pids = {} +try: + with open('usb.ids', 'r', errors='ignore') as f: + vid = 0 + for l in f: + if l.startswith('#') or not l.strip(): + continue + if l.startswith('\t\t'): + print('iface:', l) + elif l.startswith('\t'): + print('product', l) + pid = int(l[1:5], 16) + print('product', hex(pid), l) + else: + print('vendor', l) + vid = int(l[0:4], 16) + print('vendor', hex(vid), l) + +except IOError as e: + print("Error loading usb id's: {0}".format(e)) + context = UsbContext() for d in context.DeviceList: print(d) diff -r 9e350a7dde98 -r 654093a9a1e3 python/st-flash.py --- a/python/st-flash.py Fri Jan 18 12:52:11 2013 +0100 +++ b/python/st-flash.py Sat Jan 19 18:16:04 2013 +0100 @@ -30,7 +30,6 @@ eraseparser = subparsers.add_parser('erase', help='erase flash contents') args = parser.parse_args() -print(args) if not args.command: parser.print_usage() sys.exit(1) diff -r 9e350a7dde98 -r 654093a9a1e3 python/st-util.py --- a/python/st-util.py Fri Jan 18 12:52:11 2013 +0100 +++ b/python/st-util.py Sat Jan 19 18:16:04 2013 +0100 @@ -21,7 +21,7 @@ def __init__(self): super().__init__() self.chipPixmap = QPixmap('chip.png').scaled(32, 32) - self.usbPixmap = QPixmap('usb.png').scaled(32, 32) + self.hardwarePixmap = QPixmap('hardware.png').scaled(32, 32) self.refresh() def refresh(self): """ Check all usb interfaces for interfaces """ @@ -34,7 +34,6 @@ return self.devices.append(device) self.modelReset.emit() - def index(self, row, column, parent): if parent.isValid(): ip = parent.internalPointer() @@ -42,7 +41,6 @@ devs = [d for d in self.devices if d.iface is ip] return self.createIndex(row, column, devs[row]) else: - # root level iface = self.interfaces[row] return self.createIndex(row, column, iface) return idx @@ -76,10 +74,54 @@ return str(ip) elif role == Qt.DecorationRole: if isinstance(ip, Interface): - return self.usbPixmap + return self.hardwarePixmap if isinstance(ip, Device): return self.chipPixmap +class DeviceExplorer(QTreeView): + """ Lists all interfaces plugged in and allows selection """ + deviceSelected = pyqtSignal(Device) + def __init__(self): + super().__init__() + self.mdl = DeviceTreeModel() + self.setModel(self.mdl) + self.activated.connect(self.openItem) + self.header().close() + self.customContextMenuRequested.connect(self.openMenu) + self.setContextMenuPolicy(Qt.CustomContextMenu) + def openItem(self, idx): + if idx.isValid(): + ip = idx.internalPointer() + if isinstance(ip, Interface): + if not ip.IsOpen: + ip.open() + # Try to get a device: + self.mdl.addDevice(ip.createDevice()) + if isinstance(ip, Device): + self.deviceSelected.emit(ip) + def openMenu(self, pt): + idx = self.indexAt(pt) + menu = QMenu() + menu.addAction('Refresh', self.mdl.refresh) + if idx.isValid(): + ip = idx.internalPointer() + if isinstance(ip, Interface): + if ip.IsOpen: + def closeInterface(): + self.mdl.closeInterface(ip) + menu.addAction('Close', closeInterface) + else: + def openInterface(): + ip.open() + # Try to get a device: + self.mdl.addDevice(ip.createDevice()) + menu.addAction('Open', openInterface) + elif isinstance(ip, Device): + def selectDevice(): + self.deviceSelected.emit(ip) + menu.addAction('Select', selectDevice) + menu.exec(self.mapToGlobal(pt)) + class StUtil(QMainWindow): connected = pyqtSignal(bool) def __init__(self): @@ -104,23 +146,15 @@ sb = self.statusBar() - tv = QTreeView() - self.setCentralWidget(tv) - self.mdl = DeviceTreeModel() - tv.setModel(self.mdl) - tv.activated.connect(self.openItem) + devexplr = DeviceExplorer() + self.setCentralWidget(devexplr) + devexplr.deviceSelected.connect(self.handleDeviceSelected) self.connected.connect(self.handleConnectedChange) self.connected.emit(False) - def openItem(self, idx): - if idx.isValid(): - ip = idx.internalPointer() - if isinstance(ip, Interface): - ip.open() - # Try to get a device: - self.mdl.addDevice(ip.createDevice()) - if isinstance(ip, Device): - self.device = ip + def handleDeviceSelected(self, dev): + self.dev = dev + self.handleConnectedChange(True) def handleConnectedChange(self, state): self.miscMenu.setEnabled(state) self.connectAction.setEnabled(not state) diff -r 9e350a7dde98 -r 654093a9a1e3 python/stlink.py --- a/python/stlink.py Fri Jan 18 12:52:11 2013 +0100 +++ b/python/stlink.py Sat Jan 19 18:16:04 2013 +0100 @@ -57,13 +57,18 @@ 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.devHandle: + if self.IsOpen: return 'STlink2 device version {0}'.format(self.Version) else: return 'STlink2 device' def open(self): - if self.devHandle: + if self.IsOpen: return self.devHandle = self.stlink2.open() if self.devHandle.Configuration != 1: @@ -77,9 +82,12 @@ self.enterSwdMode() self.reset() def close(self): - # TODO - pass - + if self.IsOpen: + self.devHandle.close() + self.devHandle = None + @property + def IsOpen(self): + return self.devHandle != None # modes: def getCurrentMode(self): cmd = bytearray(16) @@ -159,7 +167,6 @@ cmd[0:2] = DEBUG_COMMAND, DEBUG_RUNCORE self.send_recv(cmd, 2) - # Helper 1 functions: def write_debug32(self, address, value): cmd = bytearray(16) diff -r 9e350a7dde98 -r 654093a9a1e3 python/stm32.py --- a/python/stm32.py Fri Jan 18 12:52:11 2013 +0100 +++ b/python/stm32.py Sat Jan 19 18:16:04 2013 +0100 @@ -5,9 +5,6 @@ STM32_FLASH_BASE = 0x08000000 STM32_SRAM_BASE = 0x20000000 -FLASH_KEY1 = 0x45670123 -FLASH_KEY2 = 0xcdef89ab - # flash registers: FLASH_F4_REGS_ADDR = 0x40023c00 FLASH_F4_KEYR = FLASH_F4_REGS_ADDR + 0x04 @@ -23,48 +20,63 @@ FLASH_F4_CR_SNB_MASK = 0x38 FLASH_F4_SR_BSY = 16 -def calculate_F4_sector(address): - """ - from 0x8000000 to 0x80FFFFF - 4 sectors of 0x4000 (16 kB) - 1 sector of 0x10000 (64 kB) - 7 of 0x20000 (128 kB) - """ - sectorsizes = [0x4000] * 4 + [0x10000] + [0x20000] * 7 - sectorstarts = [] - a = STM32_FLASH_BASE - for sectorsize in sectorsizes: - sectorstarts.append(a) - a += sectorsize - # linear search: - sec = 0 - while sec < len(sectorsizes) and address >= sectorstarts[sec]: - sec += 1 - sec -= 1 # one back. - return sec, sectorsizes[sec] - -def calcSectors(address, size): - off = 0 - sectors = [] - while off < size: - sectornum, sectorsize = calculate_F4_sector(address + off) - sectors.append((sectornum, sectorsize)) - off += sectorsize - return sectors - @registerDevice(0x10016413) class Stm32F4(Device): + """ + Implementation of the specifics of the STM32F4xx device series. + """ def __init__(self, iface): super().__init__(iface) + # Assert the proper size for this device: + assert self.FlashSize == 0x100000 + """ + from 0x8000000 to 0x80FFFFF + 4 sectors of 0x4000 (16 kB) + 1 sector of 0x10000 (64 kB) + 7 of 0x20000 (128 kB) + """ + self.sectorsizes = [0x4000] * 4 + [0x10000] + [0x20000] * 7 def __str__(self): - return 'STM32F4 device' + return 'STM32F4 device size=0x{1:X} id=0x{0:X}'.format(\ + self.UID, self.FlashSize) + def calculate_F4_sector(self, address): + sectorstarts = [] + a = STM32_FLASH_BASE + for sectorsize in self.sectorsizes: + sectorstarts.append(a) + a += sectorsize + # linear search: + sec = 0 + while sec < len(self.sectorsizes) and address >= sectorstarts[sec]: + sec += 1 + sec -= 1 # one back. + return sec, self.sectorsizes[sec] + + def calcSectors(self, address, size): + off = 0 + sectors = [] + while off < size: + sectornum, sectorsize = self.calculate_F4_sector(address + off) + sectors.append((sectornum, sectorsize)) + off += sectorsize + return sectors + # Device registers: + @property + def UID(self): + uid_base = 0x1FFF7A10 + uid1 = self.iface.read_debug32(uid_base) + uid2 = self.iface.read_debug32(uid_base + 0x4) + uid3 = self.iface.read_debug32(uid_base + 0x8) + return (uid3 << 64) | (uid2 << 32) | uid1 + @property + def FlashSize(self): + f_id = self.iface.read_debug32(0x1FFF7A22) + f_id = f_id >> 16 + return f_id * 1024 # flashing commands: def writeFlash(self, address, content): - # TODO: - flashsize = 0x100000 # fixed 1 MB for now.. - print('WARNING: using 1 MB as flash size') - pagesize = 0x4000 # fixed for now! - print('warning: page size hardcoded') + flashsize = self.FlashSize + pagesize = min(self.sectorsizes) # Check address range: if address < STM32_FLASH_BASE: @@ -78,19 +90,16 @@ content += bytes([0]) if address & (pagesize - 1) != 0: raise STLinkException('Address not aligned with pagesize') - # erase required space - sectors = calcSectors(address, len(content)) + sectors = self.calcSectors(address, len(content)) print('erasing {0} sectors'.format(len(sectors))) for sector, secsize in sectors: print('erasing sector {0} of {1} bytes'.format(sector, secsize)) self.eraseFlashSector(sector) - # program pages: self.unlockFlashIf() self.writeFlashCrPsiz(2) # writes are 32 bits aligned self.setFlashCrPg() - print('writing {0} bytes'.format(len(content)), end='') offset = 0 t1 = time.time() @@ -98,23 +107,17 @@ size = len(content) - offset if size > 0x8000: size = 0x8000 - chunk = content[offset:offset + size] while len(chunk) % 4 != 0: - print('padding chunk') chunk = chunk + bytes([0]) - # Use simple mem32 writes: self.iface.write_mem32(address + offset, chunk) - offset += size print('.', end='', flush=True) t2 = time.time() print('Done!') print('Speed: {0} bytes/second'.format(len(content)/(t2-t1))) - self.lockFlash() - # verfify program: self.verifyFlash(address, content) def eraseFlashSector(self, sector): @@ -175,6 +178,7 @@ mask = 1 << FLASH_F4_CR_LOCK return cr & mask == mask def unlockFlashIf(self): + FLASH_KEY1, FLASH_KEY2 = 0x45670123, 0xcdef89ab if self.isFlashLocked(): self.iface.write_debug32(FLASH_F4_KEYR, FLASH_KEY1) self.iface.write_debug32(FLASH_F4_KEYR, FLASH_KEY2) @@ -183,7 +187,6 @@ def lockFlash(self): x = self.readFlashCr() | (1 << FLASH_F4_CR_LOCK) self.writeFlashCr(x) - def readFlashSr(self): return self.iface.read_debug32(FLASH_F4_SR) def readFlashCr(self): diff -r 9e350a7dde98 -r 654093a9a1e3 python/usb.py --- a/python/usb.py Fri Jan 18 12:52:11 2013 +0100 +++ b/python/usb.py Sat Jan 19 18:16:04 2013 +0100 @@ -107,7 +107,6 @@ 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]) @@ -193,6 +192,12 @@ def __init__(self, device, handle_p): self.device = device self.handle_p = handle_p + def __del__(self): + self.close() + def close(self): + if self.handle_p: + libusb_close(self.handle_p) + self.handle_p = None def getConfiguration(self): config = c_int() r = libusb_get_configuration(self.handle_p, byref(config))