Mercurial > lcfOS
diff python/utils/stm32.py @ 292:534b94b40aa8
Fixup reorganize
author | Windel Bouwman |
---|---|
date | Wed, 27 Nov 2013 08:06:42 +0100 |
parents | python/stm32.py@bd2593de3ff8 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/stm32.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,264 @@ +import time +import logging +from devices import Device, registerDevice, STLinkException, Interface +import stlink + +# F4 specifics: +STM32_FLASH_BASE = 0x08000000 +STM32_SRAM_BASE = 0x20000000 + +# flash registers: +FLASH_F4_REGS_ADDR = 0x40023c00 +FLASH_F4_KEYR = FLASH_F4_REGS_ADDR + 0x04 +FLASH_F4_SR = FLASH_F4_REGS_ADDR + 0x0c +FLASH_F4_CR = FLASH_F4_REGS_ADDR + 0x10 + +FLASH_F4_CR_START = 16 +FLASH_F4_CR_LOCK = 31 +FLASH_CR_PG = 0 +FLASH_F4_CR_SER = 1 +FLASH_CR_MER = 2 +FLASH_F4_CR_SNB = 3 +FLASH_F4_CR_SNB_MASK = 0x38 +FLASH_F4_SR_BSY = 16 + +class Stm32F4(Device): + """ + Implementation of the specifics of the STM32F4xx device series. + """ + def __init__(self, iface): + super().__init__(iface) + self.logger = logging.getLogger('stm32') + + def __str__(self): + 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 + + @property + def Running(self): + return self.iface.Status == stlink.CORE_RUNNING + + # flashing commands: + def writeFlash(self, address, content): + flashsize = self.FlashSize + pagesize = min(self.sectorsizes) + + # Check address range: + if address < STM32_FLASH_BASE: + raise STLinkException('Flashing below flash start') + if address + len(content) > STM32_FLASH_BASE + flashsize: + raise STLinkException('Flashing above flash size') + if address & 1 == 1: + raise STLinkException('Unaligned flash') + if len(content) & 1 == 1: + self.logger.warning('unaligned length, padding with zero') + content += bytes([0]) + if address & (pagesize - 1) != 0: + raise STLinkException('Address not aligned with pagesize') + # erase required space + sectors = self.calcSectors(address, len(content)) + self.logger.info('erasing {0} sectors'.format(len(sectors))) + for sector, secsize in sectors: + self.logger.info('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() + self.logger.info('writing {0} bytes'.format(len(content))) + offset = 0 + t1 = time.time() + while offset < len(content): + size = len(content) - offset + if size > 0x8000: + size = 0x8000 + chunk = content[offset:offset + size] + while len(chunk) % 4 != 0: + chunk = chunk + bytes([0]) + # Use simple mem32 writes: + self.iface.write_mem32(address + offset, chunk) + offset += size + self.logger.info('{}%'.format(offset*100/len(content))) + self.logger.info('Done!') + self.lockFlash() + # verfify program: + self.verifyFlash(address, content) + + def eraseFlashSector(self, sector): + self.waitFlashBusy() + self.unlockFlashIf() + self.writeFlashCrSnb(sector) + self.setFlashCrStart() + self.waitFlashBusy() + self.lockFlash() + + def eraseFlash(self): + self.waitFlashBusy() + self.unlockFlashIf() + self.setFlashCrMer() + self.setFlashCrStart() + self.waitFlashBusy() + self.clearFlashCrMer() + self.lockFlash() + + def verifyFlash(self, address, content): + device_content = self.readFlash(address, len(content)) + ok = content == device_content + if ok: + self.logger.info('Verify: OK') + else: + self.logger.warning('Verify: Mismatch') + + def readFlash(self, address, size): + self.logger.info('Reading {1} bytes from 0x{0:X}'.format(address, size)) + offset = 0 + tmp_size = 0x1800 + image = bytes() + while offset < size: + # Correct for last page: + if offset + tmp_size > size: + tmp_size = size - offset + + # align size to 4 bytes: + aligned_size = tmp_size + while aligned_size % 4 != 0: + aligned_size += 1 + + mem = self.iface.read_mem32(address + offset, aligned_size) + image += mem[:tmp_size] + + # indicate progress: + self.logger.info('{}%'.format(100*len(image) / size)) + + # increase for next piece: + offset += tmp_size + assert size == len(image) + self.logger.info('Done!') + return image + + def waitFlashBusy(self): + """ block until flash operation completes. """ + while self.isFlashBusy(): + time.sleep(0.01) + + def isFlashLocked(self): + mask = 1 << FLASH_F4_CR_LOCK + return self.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) + if self.isFlashLocked(): + raise STLinkException('Failed to unlock') + + def lockFlash(self): + self.Cr = self.Cr | (1 << FLASH_F4_CR_LOCK) + + def readFlashSr(self): + return self.iface.read_debug32(FLASH_F4_SR) + + def readFlashCr(self): + return self.iface.read_debug32(FLASH_F4_CR) + + def writeFlashCr(self, x): + self.iface.write_debug32(FLASH_F4_CR, x) + + Cr = property(readFlashCr, writeFlashCr) + + def writeFlashCrSnb(self, sector): + x = self.Cr + x &= ~FLASH_F4_CR_SNB_MASK + x |= sector << FLASH_F4_CR_SNB + x |= 1 << FLASH_F4_CR_SER + self.Cr = x + + def setFlashCrMer(self): + self.Cr = self.Cr | (1 << FLASH_CR_MER) + + def setFlashCrPg(self): + self.Cr = self.Cr | (1 << FLASH_CR_PG) + + def writeFlashCrPsiz(self, n): + x = self.Cr + x &= (0x3 << 8) + x |= n << 8 + self.Cr = x + + def clearFlashCrMer(self): + x = self.Cr + x &= ~(1 << FLASH_CR_MER) + self.Cr = x + + def setFlashCrStart(self): + self.Cr = self.Cr | (1 << FLASH_F4_CR_START) + + def isFlashBusy(self): + mask = 1 << FLASH_F4_SR_BSY + sr = self.readFlashSr() + # Check for error bits: + errorbits = {} + errorbits[7] = 'Programming sequence error' + errorbits[6] = 'Programming parallelism error' + errorbits[5] = 'Programming alignment error' + errorbits[4] = 'Write protection error' + errorbits[1] = 'Operation error' + #errorbits[0] = 'End of operation' + for bit, msg in errorbits.items(): + if sr & (1 << bit) == (1 << bit): + raise STLinkException(msg) + return sr & mask == mask + + +@registerDevice(0x10016413) +class Stm32F40x(Stm32F4): + """ STM32F40x and STM32F41x 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