├── .gitignore ├── LICENSE ├── README.md ├── lib ├── __init__.py ├── dbg.py ├── srec.py ├── stlinkex.py ├── stlinkusb.py ├── stlinkv2.py ├── stm32.py ├── stm32devices.py ├── stm32fp.py ├── stm32fs.py ├── stm32h7.py ├── stm32l0.py └── stm32l4.py ├── list_new_stm32.py ├── pystlink ├── pystlink.py ├── pystlink_test.py ├── pystlink_test_system.py └── stlinkv2.rules /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Pavel Revak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PYSTLINK 2 | 3 | Python tool for manipulating with STM32 MCUs using **ST-Link** in-system programmer and debugger. 4 | 5 | ## Goal 6 | 7 | Goal of this project is to bring more flexible support for different MCUs, very simple command line interface, easier integration into Makefile for direct flashing or uploading program into SRAM and many more, simplest way to add support for new MCUs. Also any suggestions are welcome. 8 | 9 | ## Features 10 | 11 | - running on **Linux**, **Mac OS/X** and **Windows** 12 | - simple command line interface 13 | - detect MCU 14 | - dump registers and memory 15 | - write registers 16 | - download memory to binary file 17 | - upload binary or SREC file into memory 18 | - FLASH binary or SREC file to all **STM32** 19 | - basic runtime control: reset, halt, step, run 20 | - support **ST-Link/V2**, **ST-Link/V2-1** and **ST-Link/V3** 21 | 22 | ### Planed features 23 | 24 | - FLASH support for other MCU types (STM32L) 25 | - FLASH information block (system memory, option bytes and OTP area) 26 | - connecting under RESET 27 | - stop Watchdog in debug mode to prevent device restart 28 | - allow to control breakpoints or watchpoints 29 | - support for more ST-Link devices connected at once 30 | - other file formats (SREC, HEX, ELF, ...) 31 | - pip installer 32 | - proxy to GDB 33 | - and maybe GUI 34 | - support for ST-Link/V1 is NOT planed, use ST-Link/V2 or V2-1 instead 35 | 36 | ## Install 37 | 38 | ### Requirements 39 | 40 | - **Python v3.7+** (tested with 3.8) 41 | - [**pyusb**](https://github.com/walac/pyusb) 42 | - [**libusb**](https://github.com/libusb/libusb) or any other libusb driver 43 | - for Windows download [latest windows binaries](https://github.com/libusb/libusb) and copy libusb-1.0.dll into Windows/System32 directory 44 | 45 | ### pystlink 46 | 47 | - [Download](https://github.com/pavelrevak/pystlink/archive/master.zip) and unpack or `git clone https://github.com/pavelrevak/pystlink.git` 48 | - Connect ST-LINK 49 | - Run `./pystlink.py --help` (or `python3 pystlink.py ...` - depend on python installation and architecture) 50 | 51 | ## Help 52 | ``` 53 | usage: pystlink [-h] [-q | -i | -v | -d] [-V] [-c CPU] [-r] [-u] 54 | [action [action ...]] 55 | 56 | pystlink v0.0.0 (ST-LinkV2) 57 | (c)2015 by pavel.revak@gmail.com 58 | https://github.com/pavelrevak/pystlink 59 | 60 | optional arguments: 61 | -h, --help show this help message and exit 62 | -V, --version show program's version number and exit 63 | -c CPU, --cpu CPU set expected CPU type [eg: STM32F051, STM32L4] 64 | -r, --no-run do not run core when program end (if core was halted) 65 | -u, --no-unmount do not unmount DISCOVERY from ST-Link/V2-1 on OS/X platform 66 | 67 | set verbosity level: 68 | -q, --quiet 69 | -i, --info default 70 | -v, --verbose 71 | -d, --debug 72 | 73 | actions: 74 | action actions will be processed sequentially 75 | 76 | list of available actions: 77 | dump:core print all core registers (halt core) 78 | dump:{reg} print core register (halt core) 79 | dump:{addr}:{size} print content of memory 80 | dump:sram[:{size}] print content of SRAM memory 81 | dump:flash[:{size}] print content of FLASH memory 82 | dump:{addr} print content of 32 bit memory register 83 | dump16:{addr} print content of 16 bit memory register 84 | dump8:{addr} print content of 8 bit memory register 85 | 86 | set:{reg}:{data} set register (halt core) 87 | set:{addr}:{data} set 32 bit memory register 88 | 89 | read:{addr}:{size}:{file} read memory with size into file 90 | read:sram[:{size}]:{file} read SRAM into file 91 | read:flash[:{size}]:{file} read FLASH into file 92 | 93 | fill:{addr}:{size}:{pattern} fill memory with a pattern 94 | fill:sram[:{size}]:{pattern} fill SRAM memory with a pattern 95 | 96 | write:{file.srec} write SREC file into memory 97 | write:{addr}:{file} write binary file into memory 98 | write:sram:{file} write binary file into SRAM memory 99 | 100 | flash:erase complete erase FLASH memory aka mass erase 101 | flash[:erase][:verify]:{file.srec} erase + flash SREC file + verify 102 | flash[:erase][:verify][:{addr}]:{file} erase + flash binary file + verify 103 | 104 | reset reset core 105 | reset:halt reset and halt core 106 | halt halt core 107 | step step core 108 | run run core 109 | 110 | sleep:{seconds} sleep (float) - insert delay between commands 111 | 112 | (numerical values can be in different formats, like: 42, 0x2a, 0o52, 0b101010) 113 | 114 | examples: 115 | pystlink.py --help 116 | pystlink.py -v --cpu STM32F051R8 117 | pystlink.py -q --cpu STM32F03 dump:flash dump:sram 118 | pystlink.py dump:0x08000000:256 119 | pystlink.py set:0x48000018:0x00000100 dump:0x48000014 120 | pystlink.py read:sram:256:aaa.bin read:flash:bbb.bin 121 | pystlink.py -r reset:halt set:pc:0x20000010 dump:pc core:step dump:all 122 | pystlink.py flash:erase:verify:app.bin 123 | pystlink.py flash:erase flash:verify:0x08010000:boot.bin 124 | ```` 125 | 126 | ## Supported programmers 127 | 128 | From ST exists actually three different SWD programmers: 129 | 130 | Full support: 131 | - **ST-Link/V2** 132 | - **ST-Link/V2-1** 133 | - **ST-Link/V3** 134 | 135 | Not supported: 136 | - ST-Link/V1 137 | 138 | Minimum recommended firmware version of ST-Link is **V2J32xx** or newer. Otherwise is recommended upgrade using [ST-LINK firmware upgrade tool](https://www.st.com/en/development-tools/stsw-link007.html). 139 | 140 | ## Supported MCUs 141 | 142 | Currently almost all **ST32** MCUs. There is script `list_new_stm32.py` which compare supported MCUs with all listed on st.com. 143 | 144 | **Not all MCUs are tested**. Please report any problems to [Issues tracker](https://github.com/pavelrevak/pystlink/issues). 145 | 146 | In WiKi is some basic info about STM32 naming: [STM32 coding matrix](https://github.com/pavelrevak/pystlink/wiki/STM32-coding-matrix) 147 | 148 | ## Legal 149 | 150 | Code is under [MIT license](https://github.com/pavelrevak/pystlink/blob/master/LICENSE). 151 | 152 | In general, this program is allowed to copy, share, change, use in commercial and without any limitations, but if you make some changes or updates then will be nice to share it. 153 | 154 | Support is only by [Issues tracker](https://github.com/pavelrevak/pystlink/issues) 155 | 156 | **PYSTLINK** is inspired by [OpenOCD](http://openocd.org/), [STLINK](https://github.com/texane/stlink) and lot of info is from sniffed USB communication with [original ST-LINK](http://www.st.com/web/en/catalog/tools/PF258168) program. 157 | 158 | ## TAGS 159 | ST-Link/V2, ST-Link/V3, stlink, SWD, Python, ARM, CortexM, STM32, debug, FLASH, USB 160 | -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pavelrevak/pystlink/4921e130801d122d29f1b07140dcbcd643b8d7ee/lib/__init__.py -------------------------------------------------------------------------------- /lib/dbg.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | 5 | class Dbg(): 6 | def __init__(self, verbose, bar_length=40): 7 | self._verbose = verbose 8 | self._bargraph_msg = None 9 | self._bargraph_min = None 10 | self._bargraph_max = None 11 | self._newline = True 12 | self._bar_length = bar_length 13 | self._prev_percent = None 14 | self._start_time = None 15 | 16 | def _msg(self, msg, level): 17 | if self._verbose >= level: 18 | if not self._newline: 19 | sys.stderr.write('\n') 20 | self._newline = True 21 | sys.stderr.write('%s\n' % msg) 22 | sys.stderr.flush() 23 | 24 | def debug(self, msg, level=3): 25 | self._msg(msg, level) 26 | 27 | def verbose(self, msg, level=2): 28 | self._msg(msg, level) 29 | 30 | def info(self, msg, level=1): 31 | self._msg(msg, level) 32 | 33 | def message(self, msg, level=0): 34 | self._msg(msg, level) 35 | 36 | def error(self, msg, level=0): 37 | self._msg('*** %s ***' % msg, level) 38 | 39 | def warning(self, msg, level=0): 40 | self._msg(' * %s' % msg, level) 41 | 42 | def print_bargraph(self, percent): 43 | if percent == self._prev_percent: 44 | return 45 | bar = int(percent * self._bar_length) // 100 46 | sys.stderr.write('\r%s: [%s%s] %3d%%' % ( 47 | self._bargraph_msg, 48 | '=' * bar, 49 | ' ' * (self._bar_length - bar), 50 | percent, 51 | )) 52 | sys.stderr.flush() 53 | self._prev_percent = percent 54 | self._newline = False 55 | 56 | def bargraph_start(self, msg, value_min=0, value_max=100, level=1): 57 | self._start_time = time.time() 58 | if self._verbose < level: 59 | return 60 | self._bargraph_msg = msg 61 | self._bargraph_min = value_min 62 | self._bargraph_max = value_max 63 | if not self._newline: 64 | sys.stderr.write('\n') 65 | self._newline = False 66 | sys.stderr.write('%s' % msg) 67 | self._prev_percent = None 68 | self._newline = False 69 | 70 | def bargraph_update(self, value=0, percent=None): 71 | if not self._bargraph_msg: 72 | return 73 | if percent is None: 74 | if (self._bargraph_max - self._bargraph_min) > 0: 75 | percent = 100 * (value - self._bargraph_min) // (self._bargraph_max - self._bargraph_min) 76 | else: 77 | percent = 0 78 | if percent > 100: 79 | percent = 100 80 | self.print_bargraph(percent) 81 | 82 | def bargraph_done(self): 83 | if not self._bargraph_msg: 84 | return 85 | sys.stderr.write('\r%s: [%s] done in %.2fs\n' % (self._bargraph_msg, '=' * self._bar_length, time.time() - self._start_time)) 86 | sys.stderr.flush() 87 | self._newline = True 88 | self._bargraph_msg = None 89 | 90 | def set_verbose(self, verbose): 91 | self._verbose = verbose 92 | -------------------------------------------------------------------------------- /lib/srec.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | class SrecException(Exception): 5 | def __init__(self, msg): 6 | self.msg = msg 7 | 8 | def __str__(self): 9 | return self.msg 10 | 11 | 12 | class SrecExceptionWrongLength(Exception): 13 | def __init__(self): 14 | self.msg = 'Wrong length of record line' 15 | 16 | def __str__(self): 17 | return self.msg 18 | 19 | 20 | class SrecExceptionWrongType(Exception): 21 | def __init__(self, record_type): 22 | self.msg = 'Wrong record type (%s)' % record_type 23 | 24 | def __str__(self): 25 | return self.msg 26 | 27 | 28 | class SrecExceptionWrongChecksum(Exception): 29 | def __init__(self, checksum): 30 | self.msg = 'Wrong record checksum (expected: 0xff, get: 0x%02x)' % checksum 31 | 32 | def __str__(self): 33 | return self.msg 34 | 35 | 36 | class Srec(): 37 | ADDR_SIZE = { 38 | 'S0': 2, 39 | 'S1': 2, 40 | 'S2': 3, 41 | 'S3': 4, 42 | 'S5': 2, 43 | 'S7': 4, 44 | 'S8': 3, 45 | 'S9': 2, 46 | } 47 | 48 | def __init__(self): 49 | self._buffers = [] 50 | self._buffer_addr = 0 51 | self._buffer_data = None 52 | self.header = None 53 | 54 | def encode_record(self, srec): 55 | srec = srec.strip() 56 | # validate: length of file, start with S, length minimum 6 and even 57 | if len(srec) < 10 or len(srec) % 2: 58 | raise SrecExceptionWrongLength() 59 | record = srec[:2] 60 | if record not in Srec.ADDR_SIZE: 61 | raise SrecExceptionWrongType(record) 62 | data = [] 63 | srec = srec[2:] 64 | while srec: 65 | data.append(int(srec[:2], 16)) 66 | srec = srec[2:] 67 | # validate checksum + remove checksum byte 68 | checksum = 0x00 69 | for i in data: 70 | checksum += i 71 | checksum &= 0xff 72 | if checksum != 0xff: 73 | raise SrecExceptionWrongChecksum(checksum) 74 | data = data[:-1] 75 | # validate length + remove length byte 76 | if data[0] != len(data): 77 | raise SrecExceptionWrongLength() 78 | data = data[1:] 79 | # read address + remove address bytes 80 | addr_size = Srec.ADDR_SIZE[record] 81 | addr = 0 82 | while addr_size: 83 | addr <<= 8 84 | addr |= data[0] 85 | data = data[1:] 86 | addr_size -= 1 87 | return record, addr, data 88 | 89 | def process_record(self, srec): 90 | record, addr, data = self.encode_record(srec) 91 | if record == 'S0': 92 | self.header = data 93 | elif record in ('S1', 'S2', 'S3') and data: 94 | if self._buffer_addr is None: 95 | self._buffer_addr = addr 96 | self._buffer_data = data 97 | elif self._buffer_addr + len(self._buffer_data) == addr: 98 | self._buffer_data += data 99 | elif self._buffer_addr + len(self._buffer_data) != addr: 100 | self._buffers.append((self._buffer_addr, self._buffer_data)) 101 | self._buffer_addr = addr 102 | self._buffer_data = data 103 | 104 | def encode_lines(self, srec_lines): 105 | self._buffers = [] 106 | self._buffer_addr = None 107 | self._buffer_data = None 108 | self.header = None 109 | for srec in srec_lines: 110 | self.process_record(srec) 111 | if self._buffer_addr is not None: 112 | self._buffers.append((self._buffer_addr, self._buffer_data)) 113 | # return self._buffers 114 | 115 | @property 116 | def buffers(self): 117 | return self._buffers 118 | 119 | def encode_file(self, filename): 120 | with open(filename) as srec_file: 121 | self.encode_lines(srec_file) 122 | 123 | 124 | class TestSrec(unittest.TestCase): 125 | 126 | def setUp(self): 127 | self.srec = Srec() 128 | 129 | def testEncodeSrecVeryShortLine1(self): 130 | with self.assertRaises(SrecExceptionWrongLength): 131 | self.srec.encode_record('S') 132 | 133 | def testEncodeSrecVeryShortLine3(self): 134 | with self.assertRaises(SrecExceptionWrongLength): 135 | self.srec.encode_record('S000') 136 | 137 | def testEncodeSrecLinesWrongRecord(self): 138 | with self.assertRaises(SrecExceptionWrongType): 139 | self.srec.encode_record('abcdefghij') 140 | 141 | def testEncodeSrecLinesWrongRecordType(self): 142 | with self.assertRaises(SrecExceptionWrongType): 143 | self.srec.encode_record('S600000000') 144 | 145 | def testEncodeSrecWrongChecksum(self): 146 | with self.assertRaises(SrecExceptionWrongChecksum): 147 | self.srec.encode_record('S000000000') 148 | 149 | def testEncodeSrecWrongChecksum2(self): 150 | with self.assertRaises(SrecExceptionWrongChecksum): 151 | self.srec.encode_record('S012345678901234567890') 152 | 153 | def testEncodeSrecShortLine(self): 154 | with self.assertRaises(SrecExceptionWrongLength): 155 | self.srec.encode_record('S0000000ff') 156 | 157 | def testEncodeSrecShortLine2(self): 158 | with self.assertRaises(SrecExceptionWrongLength): 159 | self.srec.encode_record('S0020000fd') 160 | 161 | def testEncodeSrecLongLine(self): 162 | with self.assertRaises(SrecExceptionWrongLength): 163 | self.srec.encode_record('S0040000fb') 164 | 165 | def testEncodeSrecEmptyHeader(self): 166 | ret = self.srec.encode_record('S0030000FC') 167 | self.assertEqual(ret, ('S0', 0x0000, [])) 168 | 169 | def testEncodeSrecHeader(self): 170 | ret = self.srec.encode_record('S0060000766C6BAC') 171 | self.assertEqual(ret, ('S0', 0x0000, [0x76, 0x6c, 0x6b])) 172 | 173 | def testEncodeSrecDataAddr16(self): 174 | ret = self.srec.encode_record('S1060000766C6BAC') 175 | self.assertEqual(ret, ('S1', 0x0000, [0x76, 0x6c, 0x6b])) 176 | 177 | def testEncodeSrecDataAddr24(self): 178 | ret = self.srec.encode_record('S207000000766C6BAB') 179 | self.assertEqual(ret, ('S2', 0x000000, [0x76, 0x6c, 0x6b])) 180 | 181 | def testEncodeSrecDataAddr32(self): 182 | ret = self.srec.encode_record('S30800000000766C6BAA') 183 | self.assertEqual(ret, ('S3', 0x00000000, [0x76, 0x6c, 0x6b])) 184 | 185 | def testEncodeLines1Buffer(self): 186 | ret = self.srec.encode_lines([ 187 | 'S30900000000112233444c', 188 | 'S309000000045566778838', 189 | 'S309000000089ABCDEF0CA', 190 | ]) 191 | self.assertEqual(ret, [(0x00000000, [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x9a, 0xbc, 0xde, 0xf0])]) 192 | 193 | def testEncodeLines2Buffer(self): 194 | ret = self.srec.encode_lines([ 195 | 'S30900000000112233444c', 196 | 'S309000000045566778838', 197 | 'S309000008009ABCDEF0CA', 198 | ]) 199 | self.assertEqual(ret, [(0x00000000, [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]), (2048, [0x9a, 0xbc, 0xde, 0xf0])]) 200 | 201 | 202 | if __name__ == '__main__': 203 | unittest.main() 204 | -------------------------------------------------------------------------------- /lib/stlinkex.py: -------------------------------------------------------------------------------- 1 | class StlinkException(Exception): 2 | def __init__(self, msg): 3 | self._msg = msg 4 | 5 | def __str__(self): 6 | return self._msg 7 | 8 | 9 | class StlinkExceptionBadParam(StlinkException): 10 | def __init__(self, info=None, cmd=None): 11 | self._info = info 12 | self._cmd = cmd 13 | 14 | def set_cmd(self, cmd): 15 | self._cmd = cmd 16 | return self 17 | 18 | def __str__(self): 19 | msg = 'Bad param: "%s"' % self._cmd 20 | if self._info: 21 | msg += ': %s' % self._info 22 | return msg 23 | 24 | 25 | class StlinkExceptionCpuNotSelected(StlinkException): 26 | def __init__(self): 27 | self._msg = 'CPU is not selected' 28 | -------------------------------------------------------------------------------- /lib/stlinkusb.py: -------------------------------------------------------------------------------- 1 | import usb.core 2 | import usb.util 3 | import lib.stlinkex 4 | import re 5 | 6 | 7 | class StlinkUsbConnector(): 8 | STLINK_CMD_SIZE_V2 = 16 9 | 10 | DEV_TYPES = [ 11 | { 12 | 'version': 'V2', 13 | 'idVendor': 0x0483, 14 | 'idProduct': 0x3748, 15 | 'outPipe': 0x02, 16 | 'inPipe': 0x81, 17 | }, { 18 | 'version': 'V2-1', 19 | 'idVendor': 0x0483, 20 | 'idProduct': 0x374b, 21 | 'outPipe': 0x01, 22 | 'inPipe': 0x81, 23 | }, { 24 | 'version': 'V2-1', # without MASS STORAGE 25 | 'idVendor': 0x0483, 26 | 'idProduct': 0x3752, 27 | 'outPipe': 0x01, 28 | 'inPipe': 0x81, 29 | }, { 30 | 'version': 'V3E', 31 | 'idVendor': 0x0483, 32 | 'idProduct': 0x374e, 33 | 'outPipe': 0x01, 34 | 'inPipe': 0x81, 35 | }, { 36 | 'version': 'V3', 37 | 'idVendor': 0x0483, 38 | 'idProduct': 0x374f, 39 | 'outPipe': 0x01, 40 | 'inPipe': 0x81, 41 | }, { 42 | 'version': 'V3', # without MASS STORAGE 43 | 'idVendor': 0x0483, 44 | 'idProduct': 0x3753, 45 | 'outPipe': 0x01, 46 | 'inPipe': 0x81, 47 | } 48 | ] 49 | 50 | def _get_serial(self): 51 | # The signature for get_string has changed between versions to 1.0.0b1, 52 | # 1.0.0b2 and 1.0.0. Try the old signature first, if that fails try 53 | # the newer one. 54 | try: 55 | serial = usb.util.get_string(self._dev, 255, self._dev.iSerialNumber) 56 | except (usb.core.USBError, ValueError): 57 | serial = usb.util.get_string(self._dev, self._dev.iSerialNumber) 58 | if serial != None: 59 | if re.search("[0-9a-fA-f]+", serial).span()[1] != 24: 60 | serial = ''.join(["%.2x" % ord(c) for c in list(serial)]) 61 | return serial 62 | 63 | def __init__(self, dbg=None, serial = None, index = 0): 64 | self._dbg = dbg 65 | self._dev_type = None 66 | self._xfer_counter = 0 67 | devices = usb.core.find(find_all=True) 68 | multiple_devices = False 69 | self._dev = None 70 | num_stlink = 0 71 | for dev in devices: 72 | for dev_type in StlinkUsbConnector.DEV_TYPES: 73 | if dev.idVendor == dev_type['idVendor'] and dev.idProduct == dev_type['idProduct']: 74 | if not serial and index == 0: 75 | if self._dev: 76 | multiple_devices = True 77 | self._dbg.info("%2d: STLINK %4s, serial %s" % (num_stlink, self._dev_type['version'], self._get_serial())) 78 | self._dev = dev 79 | self._dev_type = dev_type 80 | num_stlink = num_stlink + 1 81 | if self._dev and serial and serial == self._get_serial(): 82 | break 83 | if self._dev and serial == None and index == num_stlink: 84 | break 85 | if multiple_devices: 86 | self._dbg.info("%2d: STLINK %4s, serial %s" % 87 | (num_stlink, self._dev_type['version'], 88 | self._get_serial())) 89 | raise lib.stlinkex.StlinkException( 90 | "Found multiple devices. Select one with -s SERIAL or -n INDEX") 91 | if self._dev: 92 | self._dbg.verbose("Connected to ST-Link/%4s, serial %s" % ( 93 | self._dev_type['version'], self._get_serial())) 94 | return 95 | raise lib.stlinkex.StlinkException('ST-Link/V2 is not connected') 96 | 97 | @property 98 | def version(self): 99 | return self._dev_type['version'] 100 | 101 | @property 102 | def xfer_counter(self): 103 | return self._xfer_counter 104 | 105 | def _write(self, data, tout=200): 106 | self._dbg.debug(" USB > %s" % ' '.join(['%02x' % i for i in data])) 107 | self._xfer_counter += 1 108 | count = self._dev.write(self._dev_type['outPipe'], data, tout) 109 | if count != len(data): 110 | raise lib.stlinkex.StlinkException("Error, only %d Bytes was transmitted to ST-Link instead of expected %d" % (count, len(data))) 111 | 112 | def _read(self, size, tout=200): 113 | read_size = size 114 | if read_size < 64: 115 | read_size = 64 116 | elif read_size % 4: 117 | read_size += 3 118 | read_size &= 0xffc 119 | data = self._dev.read(self._dev_type['inPipe'], read_size, tout).tolist() 120 | self._dbg.debug(" USB < %s" % ' '.join(['%02x' % i for i in data])) 121 | return data[:size] 122 | 123 | def xfer(self, cmd, data=None, rx_len=None, retry=0, tout=200): 124 | while (True): 125 | try: 126 | if len(cmd) > self.STLINK_CMD_SIZE_V2: 127 | raise lib.stlinkex.StlinkException("Error too many Bytes in command: %d, maximum is %d" % (len(cmd), self.STLINK_CMD_SIZE_V2)) 128 | # pad to 16 bytes 129 | cmd += [0] * (self.STLINK_CMD_SIZE_V2 - len(cmd)) 130 | self._write(cmd, tout) 131 | if data: 132 | self._write(data, tout) 133 | if rx_len: 134 | return self._read(rx_len) 135 | except usb.core.USBError as e: 136 | if retry: 137 | retry -= 1 138 | continue 139 | raise lib.stlinkex.StlinkException("USB Error: %s" % e) 140 | return None 141 | 142 | def unmount_discovery(self): 143 | import platform 144 | if platform.system() != 'Darwin' or self.version != 'V2-1': 145 | return 146 | import subprocess 147 | p = subprocess.Popen( 148 | ['diskutil', 'info', 'DISCOVERY'], 149 | stdout=subprocess.PIPE, 150 | stderr=subprocess.PIPE, 151 | ) 152 | p.wait() 153 | out, err = p.communicate() 154 | out = out.decode(encoding='UTF-8').strip() 155 | is_mounted = False 156 | is_mbed = False 157 | for line in out.splitlines(): 158 | param = line.split(':', 1) 159 | if param[0].strip() == 'Mounted' and param[1].strip() == 'Yes': 160 | is_mounted = True 161 | if param[0].strip() == 'Device / Media Name' and param[1].strip().startswith('MBED'): 162 | is_mbed = True 163 | if is_mounted and is_mbed: 164 | print("unmounting DISCOVERY") 165 | p = subprocess.Popen( 166 | ['diskutil', 'unmount', 'DISCOVERY'], 167 | stdout=subprocess.PIPE, 168 | stderr=subprocess.PIPE, 169 | ) 170 | p.wait() 171 | -------------------------------------------------------------------------------- /lib/stlinkv2.py: -------------------------------------------------------------------------------- 1 | import lib.stlinkex 2 | 3 | 4 | class Stlink(): 5 | STLINK_GET_VERSION = 0xf1 6 | STLINK_DEBUG_COMMAND = 0xf2 7 | STLINK_DFU_COMMAND = 0xf3 8 | STLINK_SWIM_COMMAND = 0xf4 9 | STLINK_GET_CURRENT_MODE = 0xf5 10 | STLINK_GET_TARGET_VOLTAGE = 0xf7 11 | STLINK_APIV3_GET_VERSION_EX = 0xFB 12 | 13 | STLINK_MODE_DFU = 0x00 14 | STLINK_MODE_MASS = 0x01 15 | STLINK_MODE_DEBUG = 0x02 16 | STLINK_MODE_SWIM = 0x03 17 | STLINK_MODE_BOOTLOADER = 0x04 18 | 19 | STLINK_DFU_EXIT = 0x07 20 | 21 | STLINK_SWIM_ENTER = 0x00 22 | STLINK_SWIM_EXIT = 0x01 23 | 24 | STLINK_DEBUG_ENTER_JTAG = 0x00 25 | STLINK_DEBUG_STATUS = 0x01 26 | STLINK_DEBUG_FORCEDEBUG = 0x02 27 | STLINK_DEBUG_APIV1_RESETSYS = 0x03 28 | STLINK_DEBUG_APIV1_READALLREGS = 0x04 29 | STLINK_DEBUG_APIV1_READREG = 0x05 30 | STLINK_DEBUG_APIV1_WRITEREG = 0x06 31 | STLINK_DEBUG_READMEM_32BIT = 0x07 32 | STLINK_DEBUG_WRITEMEM_32BIT = 0x08 33 | STLINK_DEBUG_RUNCORE = 0x09 34 | STLINK_DEBUG_STEPCORE = 0x0a 35 | STLINK_DEBUG_APIV1_SETFP = 0x0b 36 | STLINK_DEBUG_READMEM_8BIT = 0x0c 37 | STLINK_DEBUG_WRITEMEM_8BIT = 0x0d 38 | STLINK_DEBUG_APIV1_CLEARFP = 0x0e 39 | STLINK_DEBUG_APIV1_WRITEDEBUGREG = 0x0f 40 | STLINK_DEBUG_APIV1_SETWATCHPOINT = 0x10 41 | STLINK_DEBUG_APIV1_ENTER = 0x20 42 | STLINK_DEBUG_EXIT = 0x21 43 | STLINK_DEBUG_READCOREID = 0x22 44 | STLINK_DEBUG_APIV2_ENTER = 0x30 45 | STLINK_DEBUG_APIV2_READ_IDCODES = 0x31 46 | STLINK_DEBUG_APIV2_RESETSYS = 0x32 47 | STLINK_DEBUG_APIV2_READREG = 0x33 48 | STLINK_DEBUG_APIV2_WRITEREG = 0x34 49 | STLINK_DEBUG_APIV2_WRITEDEBUGREG = 0x35 50 | STLINK_DEBUG_APIV2_READDEBUGREG = 0x36 51 | STLINK_DEBUG_APIV2_READALLREGS = 0x3a 52 | STLINK_DEBUG_APIV2_GETLASTRWSTATUS = 0x3b 53 | STLINK_DEBUG_APIV2_DRIVE_NRST = 0x3c 54 | STLINK_DEBUG_SYNC = 0x3e 55 | STLINK_DEBUG_APIV2_START_TRACE_RX = 0x40 56 | STLINK_DEBUG_APIV2_STOP_TRACE_RX = 0x41 57 | STLINK_DEBUG_APIV2_GET_TRACE_NB = 0x42 58 | STLINK_DEBUG_APIV2_SWD_SET_FREQ = 0x43 59 | STLINK_DEBUG_APIV2_READMEM_16BIT = 0x47 60 | STLINK_DEBUG_APIV2_WRITEMEM_16BIT = 0x48 61 | 62 | STLINK_DEBUG_ENTER_SWD = 0xa3 63 | 64 | STLINK_DEBUG_APIV3_SET_COM_FREQ = 0x61 65 | STLINK_DEBUG_APIV3_GET_COM_FREQ = 0x62 66 | 67 | STLINK_DEBUG_APIV2_DRIVE_NRST_LOW = 0x00 68 | STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH = 0x01 69 | STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE = 0x02 70 | 71 | STLINK_DEBUG_APIV2_SWD_SET_FREQ_MAP = { 72 | 4000000: 0, 73 | 1800000: 1, # default 74 | 1200000: 2, 75 | 950000: 3, 76 | 480000: 7, 77 | 240000: 15, 78 | 125000: 31, 79 | 100000: 40, 80 | 50000: 79, 81 | 25000: 158, 82 | # 15000: 265, 83 | # 5000: 798 84 | } 85 | 86 | STLINK_MAXIMUM_TRANSFER_SIZE = 1024 87 | 88 | def __init__(self, connector, dbg, swd_frequency=4000000): 89 | self._connector = connector 90 | self._dbg = dbg 91 | self.read_version() 92 | self.leave_state() 93 | self.read_target_voltage() 94 | if self._ver_api == 3: 95 | self.set_swd_freq_v3(swd_frequency) 96 | if self._ver_jtag >= 22: 97 | self.set_swd_freq(swd_frequency) 98 | self.enter_debug_swd() 99 | self.read_coreid() 100 | 101 | def clean_exit(self): 102 | # WORKAROUND for OS/X 10.11+ 103 | # ... read from ST-Link, must be performed even times 104 | # call this function after last send command 105 | if self._connector.xfer_counter & 1: 106 | self._connector.xfer([Stlink.STLINK_GET_CURRENT_MODE], rx_len=2) 107 | 108 | def read_version(self): 109 | # WORKAROUNF for OS/X 10.11+ 110 | # ... retry XFER if first is timeout. 111 | # only during this command it is necessary 112 | rx = self._connector.xfer([Stlink.STLINK_GET_VERSION, 0x80], rx_len=6, retry=2, tout=200) 113 | ver = int.from_bytes(rx[:2], byteorder='big') 114 | dev_ver = self._connector.version 115 | self._ver_stlink = (ver >> 12) & 0xf 116 | self._ver_jtag = (ver >> 6) & 0x3f 117 | self._ver_swim = ver & 0x3f if dev_ver == 'V2' else None 118 | self._ver_mass = ver & 0x3f if dev_ver == 'V2-1' else None 119 | self._ver_api = 3 if dev_ver[0:2] == 'V3' else 2 if self._ver_jtag > 11 else 1 120 | if dev_ver[0:2] == 'V3': 121 | rx_v3 = self._connector.xfer([Stlink.STLINK_APIV3_GET_VERSION_EX, 0x80], rx_len=16) 122 | self._ver_swim = int(rx_v3[1]) 123 | self._ver_jtag = int(rx_v3[2]) 124 | self._ver_mass = int(rx_v3[3]) 125 | self._ver_bridge = int(rx_v3[4]) 126 | self._ver_str = "%s V%dJ%d" % (dev_ver, self._ver_stlink, self._ver_jtag) 127 | if dev_ver == 'V3': 128 | self._ver_str += "M%d" % self._ver_mass 129 | self._ver_str += "B%d" % self._ver_bridge 130 | self._ver_str += "S%d" % self._ver_swim 131 | if dev_ver == 'V3E': 132 | self._ver_str += "M%d" % self._ver_mass 133 | if dev_ver == 'V2': 134 | self._ver_str += "S%d" % self._ver_swim 135 | if dev_ver == 'V2-1': 136 | self._ver_str += "M%d" % self._ver_mass 137 | if self.ver_api == 1: 138 | raise self._dbg.warning("ST-Link/%s is not supported, please upgrade firmware." % self._ver_str) 139 | if self.ver_jtag < 32 and self._ver_api == 2: 140 | self._dbg.warning("ST-Link/%s is not recent firmware, please upgrade first - functionality is not guaranteed." % self._ver_str) 141 | if self.ver_jtag < 3 and self._ver_api == 3: 142 | self._dbg.warning("ST-Link/%s is not recent firmware, please upgrade first - functionality is not guaranteed." % self._ver_str) 143 | 144 | @property 145 | def ver_stlink(self): 146 | return self._ver_stlink 147 | 148 | @property 149 | def ver_jtag(self): 150 | return self._ver_jtag 151 | 152 | @property 153 | def ver_mass(self): 154 | return self._ver_mass 155 | 156 | @property 157 | def ver_bridge(self): 158 | return self._ver_bridge 159 | 160 | @property 161 | def ver_swim(self): 162 | return self._ver_swim 163 | 164 | @property 165 | def ver_api(self): 166 | return self._ver_api 167 | 168 | @property 169 | def ver_str(self): 170 | return self._ver_str 171 | 172 | def read_target_voltage(self): 173 | rx = self._connector.xfer([Stlink.STLINK_GET_TARGET_VOLTAGE], rx_len=8) 174 | a0 = int.from_bytes(rx[:4], byteorder='little') 175 | a1 = int.from_bytes(rx[4:8], byteorder='little') 176 | self._target_voltage = 2 * a1 * 1.2 / a0 if a0 != 0 else None 177 | 178 | @property 179 | def target_voltage(self): 180 | return self._target_voltage 181 | 182 | def read_coreid(self): 183 | rx = self._connector.xfer([Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_READCOREID], rx_len=4) 184 | if len(rx) < 4: 185 | self._coreid = 0 186 | else: 187 | self._coreid = int.from_bytes(rx[:4], byteorder='little') 188 | 189 | @property 190 | def coreid(self): 191 | return self._coreid 192 | 193 | def leave_state(self): 194 | rx = self._connector.xfer([Stlink.STLINK_GET_CURRENT_MODE], rx_len=2) 195 | if rx[0] == Stlink.STLINK_MODE_DFU: 196 | self._connector.xfer([Stlink.STLINK_DFU_COMMAND, Stlink.STLINK_DFU_EXIT]) 197 | if rx[0] == Stlink.STLINK_MODE_DEBUG: 198 | self._connector.xfer([Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_EXIT]) 199 | if rx[0] == Stlink.STLINK_MODE_SWIM: 200 | self._connector.xfer([Stlink.STLINK_SWIM_COMMAND, Stlink.STLINK_SWIM_EXIT]) 201 | 202 | def set_swd_freq(self, freq=1800000): 203 | for f, d in Stlink.STLINK_DEBUG_APIV2_SWD_SET_FREQ_MAP.items(): 204 | if freq >= f: 205 | rx = self._connector.xfer([Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_APIV2_SWD_SET_FREQ, d], rx_len=2) 206 | if rx[0] != 0x80: 207 | raise lib.stlinkex.StlinkException("Error switching SWD frequency") 208 | return 209 | raise lib.stlinkex.StlinkException("Selected SWD frequency is too low") 210 | 211 | def set_swd_freq_v3(self, freq=1800000): 212 | rx = self._connector.xfer([Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_APIV3_GET_COM_FREQ, 0], rx_len=52) 213 | i = 0 214 | freq_khz = 0 215 | while i < rx[8] : 216 | freq_khz = int.from_bytes(rx[12 + 4 * i: 15 + 4 * i], byteorder='little') 217 | if freq / 1000 >= freq_khz: 218 | break; 219 | i = i + 1 220 | self._dbg.verbose("Using %d khz for %d kHz requested" % (freq_khz, freq/ 1000)) 221 | if i == rx[8]: 222 | raise lib.stlinkex.StlinkException("Selected SWD frequency is too low") 223 | cmd = [Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_APIV3_SET_COM_FREQ] 224 | cmd.extend([0x0] * 2) 225 | cmd.extend(list(freq_khz.to_bytes(4, byteorder='little'))) 226 | rx = self._connector.xfer(cmd, rx_len=2) 227 | if rx[0] != 0x80: 228 | raise lib.stlinkex.StlinkException("Error switching SWD frequency") 229 | 230 | def enter_debug_swd(self): 231 | self._connector.xfer([Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_APIV2_ENTER, Stlink.STLINK_DEBUG_ENTER_SWD], rx_len=2) 232 | 233 | def debug_resetsys(self): 234 | self._connector.xfer([Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_APIV2_RESETSYS], rx_len=2) 235 | 236 | def set_debugreg32(self, addr, data): 237 | if addr % 4: 238 | raise lib.stlinkex.StlinkException('get_mem address %08x is not in multiples of 4' % addr) 239 | cmd = [Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_APIV2_WRITEDEBUGREG] 240 | cmd.extend(list(addr.to_bytes(4, byteorder='little'))) 241 | cmd.extend(list(data.to_bytes(4, byteorder='little'))) 242 | return self._connector.xfer(cmd, rx_len=2) 243 | 244 | def get_debugreg32(self, addr): 245 | if addr % 4: 246 | raise lib.stlinkex.StlinkException('get_mem address %08xis not in multiples of 4' % addr) 247 | cmd = [Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_APIV2_READDEBUGREG] 248 | cmd.extend(list(addr.to_bytes(4, byteorder='little'))) 249 | rx = self._connector.xfer(cmd, rx_len=8) 250 | return int.from_bytes(rx[4:8], byteorder='little') 251 | 252 | def get_debugreg16(self, addr): 253 | if addr % 2: 254 | raise lib.stlinkex.StlinkException('get_mem_short address is not in even') 255 | val = self.get_debugreg32(addr & 0xfffffffc) 256 | if addr % 4: 257 | val >>= 16 258 | return val & 0xffff 259 | 260 | def get_debugreg8(self, addr): 261 | val = self.get_debugreg32(addr & 0xfffffffc) 262 | val >>= (addr % 4) << 3 263 | return val & 0xff 264 | 265 | def get_reg(self, reg): 266 | cmd = [Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_APIV2_READREG, reg] 267 | rx = self._connector.xfer(cmd, rx_len=8) 268 | return int.from_bytes(rx[4:8], byteorder='little') 269 | 270 | def set_reg(self, reg, data): 271 | cmd = [Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_APIV2_WRITEREG, reg] 272 | cmd.extend(list(data.to_bytes(4, byteorder='little'))) 273 | self._connector.xfer(cmd, rx_len=2) 274 | 275 | def get_mem32(self, addr, size): 276 | if addr % 4: 277 | raise lib.stlinkex.StlinkException('get_mem32: Address must be in multiples of 4') 278 | if size % 4: 279 | raise lib.stlinkex.StlinkException('get_mem32: Size must be in multiples of 4') 280 | if size > Stlink.STLINK_MAXIMUM_TRANSFER_SIZE: 281 | raise lib.stlinkex.StlinkException('get_mem32: Size for reading is %d but maximum can be %d' % (size, Stlink.STLINK_MAXIMUM_TRANSFER_SIZE)) 282 | cmd = [Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_READMEM_32BIT] 283 | cmd.extend(list(addr.to_bytes(4, byteorder='little'))) 284 | cmd.extend(list(size.to_bytes(4, byteorder='little'))) 285 | return self._connector.xfer(cmd, rx_len=size) 286 | 287 | def set_mem32(self, addr, data): 288 | if addr % 4: 289 | raise lib.stlinkex.StlinkException('set_mem32: Address must be in multiples of 4') 290 | if len(data) % 4: 291 | raise lib.stlinkex.StlinkException('set_mem32: Size must be in multiples of 4') 292 | if len(data) > Stlink.STLINK_MAXIMUM_TRANSFER_SIZE: 293 | raise lib.stlinkex.StlinkException('set_mem32: Size for writing is %d but maximum can be %d' % (len(data), Stlink.STLINK_MAXIMUM_TRANSFER_SIZE)) 294 | cmd = [Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_WRITEMEM_32BIT] 295 | cmd.extend(list(addr.to_bytes(4, byteorder='little'))) 296 | cmd.extend(list(len(data).to_bytes(4, byteorder='little'))) 297 | self._connector.xfer(cmd, data=data) 298 | 299 | def get_mem8(self, addr, size): 300 | if size > 64: 301 | raise lib.stlinkex.StlinkException('get_mem8: Size for reading is %d but maximum can be 64' % size) 302 | cmd = [Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_READMEM_8BIT] 303 | cmd.extend(list(addr.to_bytes(4, byteorder='little'))) 304 | cmd.extend(list(size.to_bytes(4, byteorder='little'))) 305 | return self._connector.xfer(cmd, rx_len=size) 306 | 307 | def set_mem8(self, addr, data): 308 | datablock = data 309 | while(datablock): 310 | block = datablock[:64] 311 | datablock = datablock[64:] 312 | cmd = [Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_WRITEMEM_8BIT] 313 | cmd.extend(list(addr.to_bytes(4, byteorder='little'))) 314 | cmd.extend(list(len(block).to_bytes(4, byteorder='little'))) 315 | self._connector.xfer(cmd, block) 316 | addr = addr + 64 317 | 318 | def get_mem16(self, addr, size): 319 | if addr % 2: 320 | raise lib.stlinkex.StlinkException('get_mem16: Address must be in multiples of 2') 321 | if len(data) % 2: 322 | raise lib.stlinkex.StlinkException('get_mem16: Size must be in multiples of 2') 323 | if len(data) > Stlink.STLINK_MAXIMUM_TRANSFER_SIZE: 324 | raise lib.stlinkex.StlinkException('get_mem16: Size for writing is %d but maximum can be %d' % (len(data), Stlink.STLINK_MAXIMUM_TRANSFER_SIZE)) 325 | cmd = [Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_APIV2_READMEM_16BIT] 326 | cmd.extend(list(addr.to_bytes(4, byteorder='little'))) 327 | cmd.extend(list(size.to_bytes(4, byteorder='little'))) 328 | return self._connector.xfer(cmd, rx_len=size) 329 | 330 | def set_mem16(self, addr, data): 331 | if addr % 2: 332 | raise lib.stlinkex.StlinkException('set_mem16: Address must be in multiples of 2') 333 | if len(data) % 2: 334 | raise lib.stlinkex.StlinkException('set_mem16: Size must be in multiples of 2') 335 | if len(data) > Stlink.STLINK_MAXIMUM_TRANSFER_SIZE: 336 | raise lib.stlinkex.StlinkException('set_mem16: Size for writing is %d but maximum can be %d' % (len(data), Stlink.STLINK_MAXIMUM_TRANSFER_SIZE)) 337 | cmd = [Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_APIV2_WRITEMEM_16BIT] 338 | cmd.extend(list(addr.to_bytes(4, byteorder='little'))) 339 | cmd.extend(list(len(data).to_bytes(4, byteorder='little'))) 340 | self._connector.xfer(cmd, data=data) 341 | def set_nrst(self, action): 342 | self._connector.xfer([Stlink.STLINK_DEBUG_COMMAND, Stlink.STLINK_DEBUG_APIV2_DRIVE_NRST, action], rx_len=2) 343 | -------------------------------------------------------------------------------- /lib/stm32.py: -------------------------------------------------------------------------------- 1 | import lib.stm32devices 2 | import lib.stlinkex 3 | 4 | 5 | class Stm32(): 6 | REGISTERS = ['R0', 'R1', 'R2', 'R3', 'R4', 'R5', 'R6', 'R7', 'R8', 'R9', 'R10', 'R11', 'R12', 'SP', 'LR', 'PC', 'PSR', 'MSP', 'PSP'] 7 | 8 | SRAM_START = 0x20000000 9 | FLASH_START = 0x08000000 10 | 11 | AIRCR_REG = 0xe000ed0c 12 | DHCSR_REG = 0xe000edf0 13 | DEMCR_REG = 0xe000edfc 14 | 15 | AIRCR_KEY = 0x05fa0000 16 | AIRCR_SYSRESETREQ_BIT = 0x00000004 17 | AIRCR_SYSRESETREQ = AIRCR_KEY | AIRCR_SYSRESETREQ_BIT 18 | 19 | DHCSR_KEY = 0xa05f0000 20 | DHCSR_DEBUGEN_BIT = 0x00000001 21 | DHCSR_HALT_BIT = 0x00000002 22 | DHCSR_STEP_BIT = 0x00000004 23 | DHCSR_STATUS_ENABLE_BIT = DHCSR_DEBUGEN_BIT << 16 24 | DHCSR_STATUS_HALT_BIT = DHCSR_HALT_BIT << 16 25 | DHCSR_DEBUGDIS = DHCSR_KEY 26 | DHCSR_DEBUGEN = DHCSR_KEY | DHCSR_DEBUGEN_BIT 27 | DHCSR_HALT = DHCSR_KEY | DHCSR_DEBUGEN_BIT | DHCSR_HALT_BIT 28 | DHCSR_STEP = DHCSR_KEY | DHCSR_DEBUGEN_BIT | DHCSR_STEP_BIT 29 | DHCSR_HALTED = DHCSR_HALT_BIT | DHCSR_DEBUGEN_BIT |\ 30 | DHCSR_STATUS_HALT_BIT | DHCSR_STATUS_ENABLE_BIT 31 | 32 | DEMCR_RUN_AFTER_RESET = 0x00000000 33 | DEMCR_HALT_AFTER_RESET = 0x00000001 34 | 35 | def __init__(self, stlink, dbg): 36 | self._stlink = stlink 37 | self._dbg = dbg 38 | 39 | def is_reg(self, reg): 40 | return reg.upper() in Stm32.REGISTERS 41 | 42 | def get_reg_all(self): 43 | # TODO use instead STLINK_DEBUG_APIV2_READALLREGS 44 | return [(reg, self.get_reg(reg)) for reg in Stm32.REGISTERS] 45 | 46 | def get_reg(self, reg): 47 | self._dbg.debug('Stm32.get_reg(%s)' % reg) 48 | reg = reg.upper() 49 | if reg in Stm32.REGISTERS: 50 | index = Stm32.REGISTERS.index(reg) 51 | return self._stlink.get_reg(index) 52 | raise lib.stlinkex.StlinkException('Wrong register name') 53 | 54 | def set_reg(self, reg, value): 55 | self._dbg.debug('Stm32.set_reg(%s, 0x%08x)' % (reg, value)) 56 | reg = reg.upper() 57 | if reg in Stm32.REGISTERS: 58 | index = Stm32.REGISTERS.index(reg) 59 | return self._stlink.set_reg(index, value) 60 | raise lib.stlinkex.StlinkException('Wrong register name') 61 | 62 | def get_mem(self, addr, size): 63 | self._dbg.debug('Stm32.get_mem(0x%08x, %d)' % (addr, size)) 64 | if size == 0: 65 | return [] 66 | if size >= 16384: 67 | self._dbg.bargraph_start('Reading memory', value_max=size) 68 | data = [] 69 | if addr % 4: 70 | read_size = min(4 - (addr % 4), size) 71 | data = self._stlink.get_mem8(addr, read_size) 72 | while True: 73 | self._dbg.bargraph_update(value=len(data)) 74 | # WORKAROUND for OS/X 10.11+ 75 | # ... read from ST-Link more than 64 bytes, must be performed even times 76 | read_size = min((size - len(data) & 0xfffffff8), self._stlink.STLINK_MAXIMUM_TRANSFER_SIZE * 2) 77 | if read_size == 0: 78 | break 79 | if read_size > 64: 80 | read_size //= 2 81 | data.extend(self._stlink.get_mem32(addr + len(data), read_size)) 82 | data.extend(self._stlink.get_mem32(addr + len(data), read_size)) 83 | else: 84 | data.extend(self._stlink.get_mem32(addr + len(data), read_size)) 85 | if len(data) < size: 86 | read_size = size - len(data) 87 | data.extend(self._stlink.get_mem8(addr + len(data), read_size)) 88 | self._dbg.bargraph_done() 89 | return data 90 | 91 | def set_mem(self, addr, data): 92 | self._dbg.debug('Stm32.set_mem(0x%08x, [data:%dBytes])' % (addr, len(data))) 93 | if len(data) == 0: 94 | return 95 | if len(data) >= 16384: 96 | self._dbg.bargraph_start('Writing memory', value_max=len(data)) 97 | written_size = 0 98 | if addr % 4: 99 | write_size = min(4 - (addr % 4), len(data)) 100 | self._stlink.set_mem8(addr, data[:write_size]) 101 | written_size = write_size 102 | while True: 103 | self._dbg.bargraph_update(value=written_size) 104 | # WORKAROUND for OS/X 10.11+ 105 | # ... write to ST-Link more than 64 bytes, must be performed even times 106 | write_size = min((len(data) - written_size) & 0xfffffff8, self._stlink.STLINK_MAXIMUM_TRANSFER_SIZE * 2) 107 | if write_size == 0: 108 | break 109 | if write_size > 64: 110 | write_size //= 2 111 | self._stlink.set_mem32(addr + written_size, data[written_size:written_size + write_size]) 112 | written_size += write_size 113 | self._stlink.set_mem32(addr + written_size, data[written_size:written_size + write_size]) 114 | written_size += write_size 115 | else: 116 | self._stlink.set_mem32(addr + written_size, data[written_size:written_size + write_size]) 117 | written_size += write_size 118 | if written_size < len(data): 119 | self._stlink.set_mem8(addr + written_size, data[written_size:]) 120 | self._dbg.bargraph_done() 121 | return 122 | 123 | def fill_mem(self, addr, size, pattern): 124 | if pattern >= 256: 125 | raise lib.stlinkex.StlinkException('Fill pattern can by 8 bit number') 126 | self._dbg.debug('Stm32.fill_mem(0x%08x, 0x%02d)' % (addr, pattern)) 127 | if size == 0: 128 | return 129 | if size >= 16384: 130 | self._dbg.bargraph_start('Writing memory', value_max=size) 131 | written_size = 0 132 | if addr % 4: 133 | write_size = min(4 - (addr % 4), size) 134 | self._stlink.set_mem8(addr, [pattern] * write_size) 135 | written_size = write_size 136 | while True: 137 | self._dbg.bargraph_update(value=written_size) 138 | # WORKAROUND for OS/X 10.11+ 139 | # ... write to ST-Link more than 64 bytes, must be performed even timesg 140 | write_size = min((size - written_size) & 0xfffffff8, self._stlink.STLINK_MAXIMUM_TRANSFER_SIZE * 2) 141 | if write_size == 0: 142 | break 143 | if write_size > 64: 144 | write_size //= 2 145 | self._stlink.set_mem32(addr + written_size, [pattern] * write_size) 146 | written_size += write_size 147 | self._stlink.set_mem32(addr + written_size, [pattern] * write_size) 148 | written_size += write_size 149 | else: 150 | self._stlink.set_mem32(addr + written_size, [pattern] * write_size) 151 | written_size += write_size 152 | if written_size < size: 153 | self._stlink.set_mem8(addr + written_size, [pattern] * (size - written_size)) 154 | self._dbg.bargraph_done() 155 | return 156 | 157 | def core_reset(self): 158 | self._dbg.debug('Stm32.core_reset()') 159 | self._stlink.set_debugreg32(Stm32.DEMCR_REG, Stm32.DEMCR_RUN_AFTER_RESET) 160 | self._stlink.set_debugreg32(Stm32.AIRCR_REG, Stm32.AIRCR_SYSRESETREQ) 161 | self._stlink.get_debugreg32(Stm32.AIRCR_REG) 162 | 163 | def core_reset_halt(self): 164 | self._dbg.debug('Stm32.core_reset_halt()') 165 | self._stlink.set_debugreg32(Stm32.DEMCR_REG, Stm32.DEMCR_HALT_AFTER_RESET) 166 | self._stlink.set_debugreg32(Stm32.AIRCR_REG, Stm32.AIRCR_SYSRESETREQ) 167 | self.core_halt() 168 | self._stlink.get_debugreg32(Stm32.AIRCR_REG) 169 | self._dbg.debug('Stm32.core_reset_halt(): DHCSR %08x' % 170 | self._stlink.get_debugreg32(Stm32.DHCSR_REG)) 171 | 172 | def core_hard_reset_halt(self): 173 | self._dbg.debug('Stm32.core_hard_reset_halt()') 174 | self._stlink.set_nrst(0) 175 | self._stlink.set_debugreg32(Stm32.DEMCR_REG, Stm32.DEMCR_HALT_AFTER_RESET) 176 | self._stlink.set_nrst(1) 177 | self.core_halt() 178 | self._dbg.debug('Stm32.core_reset_halt(): DHCSR %08x' % 179 | self._stlink.get_debugreg32(Stm32.DHCSR_REG)) 180 | 181 | def core_halt(self): 182 | self._dbg.debug('Stm32.core_halt()') 183 | verbose = self._dbg._verbose 184 | if verbose > 2: 185 | self._dbg.set_verbose(2) 186 | i = 0 187 | while((self._stlink.get_debugreg32(Stm32.DHCSR_REG) & Stm32.DHCSR_HALTED) != Stm32.DHCSR_HALTED) : 188 | while True: 189 | self._stlink.set_debugreg32(Stm32.DHCSR_REG, Stm32.DHCSR_HALT) 190 | i += 1 191 | if i & 0xff == 0: 192 | break 193 | self._dbg.set_verbose(verbose) 194 | self._dbg.debug("Halted after %d transactions" % i) 195 | 196 | def core_step(self): 197 | self._dbg.debug('Stm32.core_step()') 198 | self._stlink.set_debugreg32(Stm32.DHCSR_REG, Stm32.DHCSR_STEP) 199 | 200 | def core_run(self): 201 | self._dbg.debug('Stm32.core_run()') 202 | self._stlink.set_debugreg32(Stm32.DHCSR_REG, Stm32.DHCSR_DEBUGEN) 203 | 204 | def core_nodebug(self): 205 | self._dbg.debug('Stm32.core_nodebug()') 206 | self._stlink.set_debugreg32(Stm32.DHCSR_REG, Stm32.DHCSR_DEBUGDIS) 207 | 208 | def flash_erase_all(self, flash_size): 209 | self._dbg.debug('Stm32.flash_mass_erase()') 210 | raise lib.stlinkex.StlinkException('Erasing FLASH is not implemented for this MCU') 211 | 212 | def flash_write(self, addr, data, erase=False, verify=False, erase_sizes=None): 213 | self._dbg.debug('Stm32.flash_write(%s, [data:%dBytes], erase=%s, verify=%s, erase_sizes=%s)' % (('0x%08x' % addr) if addr is not None else 'None', len(data), erase, verify, erase_sizes)) 214 | raise lib.stlinkex.StlinkException('Programing FLASH is not implemented for this MCU') 215 | 216 | def flash_verify(self, addr, data): 217 | self._dbg.debug('Stm32.flash_verify(%s, [data:%dBytes])' % (('0x%08x' % addr) if addr is not None else 'None', len(data))) 218 | length = len(data) 219 | self._dbg.bargraph_start('Verify FLASH ', value_min=addr, value_max=addr + len(data)) 220 | if (addr & 1): 221 | uneven = addr & 3 222 | block = data[:uneven] 223 | data = data[uneven:] 224 | if block != self._stlink.get_mem8(addr, uneven): 225 | raise lib.stlinkex.StlinkException('Verify error at non-aligned block address: 0x%08x' % addr) 226 | addr += uneven 227 | while(data): 228 | block = data[:1024] 229 | data = data[1024:] 230 | if block != self._stlink.get_mem32(addr, len(block)): 231 | raise lib.stlinkex.StlinkException('Verify error at block address: 0x%08x' % addr) 232 | addr += len(block) 233 | self._dbg.bargraph_update(value=addr) 234 | if (len(data) & 1): 235 | remainder = len(data) & 3 236 | block = data[:remainder] 237 | block = block[remainder:] 238 | if block != self._stlink.get_mem8(addr, remainder): 239 | raise lib.stlinkex.StlinkException('Verify error at block address at non-aligned length: 0x%08x' % addr) 240 | addr += remainder 241 | self._dbg.bargraph_done() 242 | -------------------------------------------------------------------------------- /lib/stm32devices.py: -------------------------------------------------------------------------------- 1 | # : by PART_NO/CORE 2 | # : by DEV_ID 3 | # : by flash_size and or device type 4 | 5 | DEVICES = [ 6 | { 7 | 'part_no': 0xc20, 8 | 'core': 'CortexM0', 9 | 'idcode_reg': 0x40015800, 10 | 'devices': [ 11 | { 12 | 'dev_id': 0x440, 13 | 'flash_size_reg': 0x1ffff7cc, 14 | 'flash_driver': 'STM32FP', 15 | 'erase_sizes': (1024, ), 16 | 'devices': [ 17 | {'type': 'STM32F030x8', 'flash_size': 64, 'sram_size': 8, 'eeprom_size': 0, 'freq': 48}, 18 | {'type': 'STM32F051x4', 'flash_size': 16, 'sram_size': 8, 'eeprom_size': 0, 'freq': 48}, 19 | {'type': 'STM32F051x6', 'flash_size': 32, 'sram_size': 8, 'eeprom_size': 0, 'freq': 48}, 20 | {'type': 'STM32F051x8', 'flash_size': 64, 'sram_size': 8, 'eeprom_size': 0, 'freq': 48}, 21 | {'type': 'STM32F058x8', 'flash_size': 64, 'sram_size': 8, 'eeprom_size': 0, 'freq': 48}, 22 | ], 23 | }, 24 | { 25 | 'dev_id': 0x442, 26 | 'flash_size_reg': 0x1ffff7cc, 27 | 'flash_driver': 'STM32FP', 28 | 'erase_sizes': (2048, ), 29 | 'devices': [ 30 | {'type': 'STM32F030xC', 'flash_size': 256, 'sram_size': 32, 'eeprom_size': 0, 'freq': 48}, 31 | {'type': 'STM32F091xB', 'flash_size': 128, 'sram_size': 32, 'eeprom_size': 0, 'freq': 48}, 32 | {'type': 'STM32F091xC', 'flash_size': 256, 'sram_size': 32, 'eeprom_size': 0, 'freq': 48}, 33 | {'type': 'STM32F098xC', 'flash_size': 256, 'sram_size': 32, 'eeprom_size': 0, 'freq': 48}, 34 | ], 35 | }, 36 | { 37 | 'dev_id': 0x444, 38 | 'flash_size_reg': 0x1ffff7cc, 39 | 'flash_driver': 'STM32FP', 40 | 'erase_sizes': (1024, ), 41 | 'devices': [ 42 | {'type': 'STM32F030x4', 'flash_size': 16, 'sram_size': 4, 'eeprom_size': 0, 'freq': 48}, 43 | {'type': 'STM32F030x6', 'flash_size': 32, 'sram_size': 4, 'eeprom_size': 0, 'freq': 48}, 44 | {'type': 'STM32F031x4', 'flash_size': 16, 'sram_size': 4, 'eeprom_size': 0, 'freq': 48}, 45 | {'type': 'STM32F031x6', 'flash_size': 32, 'sram_size': 4, 'eeprom_size': 0, 'freq': 48}, 46 | {'type': 'STM32F038x6', 'flash_size': 32, 'sram_size': 4, 'eeprom_size': 0, 'freq': 48}, 47 | ], 48 | }, 49 | { 50 | 'dev_id': 0x445, 51 | 'flash_size_reg': 0x1ffff7cc, 52 | 'flash_driver': 'STM32FP', 53 | 'erase_sizes': (1024, ), 54 | 'devices': [ 55 | {'type': 'STM32F042x4', 'flash_size': 16, 'sram_size': 6, 'eeprom_size': 0, 'freq': 48}, 56 | {'type': 'STM32F042x6', 'flash_size': 32, 'sram_size': 6, 'eeprom_size': 0, 'freq': 48}, 57 | {'type': 'STM32F048x6', 'flash_size': 32, 'sram_size': 6, 'eeprom_size': 0, 'freq': 48}, 58 | {'type': 'STM32F070x6', 'flash_size': 32, 'sram_size': 6, 'eeprom_size': 0, 'freq': 48}, 59 | ], 60 | }, 61 | { 62 | 'dev_id': 0x448, 63 | 'flash_size_reg': 0x1ffff7cc, 64 | 'flash_driver': 'STM32FP', 65 | 'erase_sizes': (2048, ), 66 | 'devices': [ 67 | {'type': 'STM32F070xB', 'flash_size': 128, 'sram_size': 16, 'eeprom_size': 0, 'freq': 48}, 68 | {'type': 'STM32F071x8', 'flash_size': 64, 'sram_size': 16, 'eeprom_size': 0, 'freq': 48}, 69 | {'type': 'STM32F071xB', 'flash_size': 128, 'sram_size': 16, 'eeprom_size': 0, 'freq': 48}, 70 | {'type': 'STM32F072x8', 'flash_size': 64, 'sram_size': 16, 'eeprom_size': 0, 'freq': 48}, 71 | {'type': 'STM32F072xB', 'flash_size': 128, 'sram_size': 16, 'eeprom_size': 0, 'freq': 48}, 72 | {'type': 'STM32F078xB', 'flash_size': 128, 'sram_size': 16, 'eeprom_size': 0, 'freq': 48}, 73 | ], 74 | }, 75 | ], 76 | }, 77 | { 78 | 'part_no': 0xc60, 79 | 'core': 'CortexM0+', 80 | 'idcode_reg': 0x40015800, 81 | 'devices': [ 82 | { 83 | 'dev_id': 0x457, # category 1 84 | 'flash_size_reg': 0x1ff8007c, 85 | 'flash_driver': 'STM32L0', 86 | 'erase_sizes': (128, ), 87 | 'devices': [ 88 | {'type': 'STM32L011x3', 'flash_size': 8, 'sram_size': 2, 'eeprom_size': 0.5, 'freq': 32}, 89 | {'type': 'STM32L011x4', 'flash_size': 16, 'sram_size': 2, 'eeprom_size': 0.5, 'freq': 32}, 90 | {'type': 'STM32L021x4', 'flash_size': 16, 'sram_size': 2, 'eeprom_size': 0.5, 'freq': 32}, 91 | ], 92 | }, 93 | { 94 | 'dev_id': 0x425, # category 2 95 | 'flash_size_reg': 0x1ff8007c, 96 | 'flash_driver': 'STM32L0', 97 | 'erase_sizes': (128, ), 98 | 'devices': [ 99 | {'type': 'STM32L031x4', 'flash_size': 16, 'sram_size': 8, 'eeprom_size': 1, 'freq': 32}, 100 | {'type': 'STM32L031x6', 'flash_size': 32, 'sram_size': 8, 'eeprom_size': 1, 'freq': 32}, 101 | {'type': 'STM32L041x6', 'flash_size': 32, 'sram_size': 8, 'eeprom_size': 1, 'freq': 32}, 102 | ], 103 | }, 104 | { 105 | 'dev_id': 0x417, # category 3 106 | 'flash_size_reg': 0x1ff8007c, 107 | 'flash_driver': 'STM32L0', 108 | 'erase_sizes': (128, ), 109 | 'devices': [ 110 | {'type': 'STM32L051x6', 'flash_size': 32, 'sram_size': 8, 'eeprom_size': 2, 'freq': 32}, 111 | {'type': 'STM32L051x8', 'flash_size': 64, 'sram_size': 8, 'eeprom_size': 2, 'freq': 32}, 112 | {'type': 'STM32L052x6', 'flash_size': 32, 'sram_size': 8, 'eeprom_size': 2, 'freq': 32}, 113 | {'type': 'STM32L052x8', 'flash_size': 64, 'sram_size': 8, 'eeprom_size': 2, 'freq': 32}, 114 | {'type': 'STM32L053x6', 'flash_size': 32, 'sram_size': 8, 'eeprom_size': 2, 'freq': 32}, 115 | {'type': 'STM32L053x8', 'flash_size': 64, 'sram_size': 8, 'eeprom_size': 2, 'freq': 32}, 116 | {'type': 'STM32L062x8', 'flash_size': 64, 'sram_size': 8, 'eeprom_size': 2, 'freq': 32}, 117 | {'type': 'STM32L063x8', 'flash_size': 64, 'sram_size': 8, 'eeprom_size': 2, 'freq': 32}, 118 | ], 119 | }, 120 | { 121 | 'dev_id': 0x447, # category 5 122 | 'flash_size_reg': 0x1ff8007c, 123 | 'flash_driver': 'STM32L0', 124 | 'erase_sizes': (128, ), 125 | 'devices': [ 126 | {'type': 'STM32L071x8', 'flash_size': 64, 'sram_size': 20, 'eeprom_size': 3, 'freq': 32}, 127 | {'type': 'STM32L071xB', 'flash_size': 128, 'sram_size': 20, 'eeprom_size': 6, 'freq': 32}, 128 | {'type': 'STM32L071xZ', 'flash_size': 192, 'sram_size': 20, 'eeprom_size': 6, 'freq': 32}, 129 | {'type': 'STM32L072x8', 'flash_size': 64, 'sram_size': 20, 'eeprom_size': 3, 'freq': 32}, 130 | {'type': 'STM32L072xB', 'flash_size': 128, 'sram_size': 20, 'eeprom_size': 6, 'freq': 32}, 131 | {'type': 'STM32L072xZ', 'flash_size': 192, 'sram_size': 20, 'eeprom_size': 6, 'freq': 32}, 132 | {'type': 'STM32L073x8', 'flash_size': 64, 'sram_size': 20, 'eeprom_size': 3, 'freq': 32}, 133 | {'type': 'STM32L073xB', 'flash_size': 128, 'sram_size': 20, 'eeprom_size': 6, 'freq': 32}, 134 | {'type': 'STM32L073xZ', 'flash_size': 192, 'sram_size': 20, 'eeprom_size': 6, 'freq': 32}, 135 | {'type': 'STM32L081xZ', 'flash_size': 192, 'sram_size': 20, 'eeprom_size': 6, 'freq': 32}, 136 | {'type': 'STM32L081xB', 'flash_size': 128, 'sram_size': 20, 'eeprom_size': 6, 'freq': 32}, 137 | {'type': 'STM32L082xZ', 'flash_size': 192, 'sram_size': 20, 'eeprom_size': 6, 'freq': 32}, 138 | {'type': 'STM32L082xB', 'flash_size': 128, 'sram_size': 20, 'eeprom_size': 6, 'freq': 32}, 139 | {'type': 'STM32L083x8', 'flash_size': 64, 'sram_size': 20, 'eeprom_size': 3, 'freq': 32}, 140 | {'type': 'STM32L083xB', 'flash_size': 128, 'sram_size': 20, 'eeprom_size': 6, 'freq': 32}, 141 | {'type': 'STM32L083xZ', 'flash_size': 192, 'sram_size': 20, 'eeprom_size': 6, 'freq': 32}, 142 | ], 143 | }, 144 | { 145 | 'dev_id': 0x460, 146 | 'flash_size_reg': 0x1fff75e0, 147 | 'flash_driver': 'STM32L4', 148 | 'erase_sizes': (2 * 1024, ), 149 | 'devices': [ 150 | {'type': 'STM32G070x8', 'flash_size': 64, 'sram_size': 32, 'eeprom_size': 0, 'freq': 64}, 151 | {'type': 'STM32G070xB', 'flash_size': 128, 'sram_size': 32, 'eeprom_size': 0, 'freq': 64}, 152 | {'type': 'STM32G071x8', 'flash_size': 64, 'sram_size': 32, 'eeprom_size': 0, 'freq': 64}, 153 | {'type': 'STM32G071xB', 'flash_size': 128, 'sram_size': 32, 'eeprom_size': 0, 'freq': 64}, 154 | ], 155 | }, 156 | ], 157 | }, 158 | { 159 | 'part_no': 0xc23, 160 | 'core': 'CortexM3', 161 | 'idcode_reg': 0xE0042000, 162 | 'devices': [ 163 | { 164 | 'dev_id': 0x410, 165 | 'flash_size_reg': 0x1ffff7e0, 166 | 'flash_driver': 'STM32FP', 167 | 'erase_sizes': (1024, ), 168 | 'devices': [ 169 | {'type': 'STM32F101x8', 'flash_size': 64, 'sram_size': 10, 'eeprom_size': 0, 'freq': 36}, 170 | {'type': 'STM32F101xB', 'flash_size': 128, 'sram_size': 16, 'eeprom_size': 0, 'freq': 36}, 171 | {'type': 'STM32F102x8', 'flash_size': 64, 'sram_size': 10, 'eeprom_size': 0, 'freq': 48}, 172 | {'type': 'STM32F102xB', 'flash_size': 128, 'sram_size': 16, 'eeprom_size': 0, 'freq': 48}, 173 | {'type': 'STM32F103x8', 'flash_size': 64, 'sram_size': 20, 'eeprom_size': 0, 'freq': 72}, 174 | {'type': 'STM32F103xB', 'flash_size': 128, 'sram_size': 20, 'eeprom_size': 0, 'freq': 72}, 175 | ], 176 | }, 177 | { 178 | 'dev_id': 0x411, 179 | 'flash_size_reg': 0x1fff7a22, 180 | 'flash_driver': 'STM32FS', 181 | 'erase_sizes': (16*1024, 16*1024, 16*1024, 16*1024, 64*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, ), 182 | 'devices': [ 183 | {'type': 'STM32F205xB', 'flash_size': 128, 'sram_size': 64, 'eeprom_size': 0, 'freq': 120}, 184 | {'type': 'STM32F205xC', 'flash_size': 256, 'sram_size': 96, 'eeprom_size': 0, 'freq': 120}, 185 | {'type': 'STM32F205xE', 'flash_size': 512, 'sram_size': 128, 'eeprom_size': 0, 'freq': 120}, 186 | {'type': 'STM32F205xF', 'flash_size': 768, 'sram_size': 128, 'eeprom_size': 0, 'freq': 120}, 187 | {'type': 'STM32F205xG', 'flash_size': 1024, 'sram_size': 128, 'eeprom_size': 0, 'freq': 120}, 188 | {'type': 'STM32F207xC', 'flash_size': 256, 'sram_size': 128, 'eeprom_size': 0, 'freq': 120}, 189 | {'type': 'STM32F207xE', 'flash_size': 512, 'sram_size': 128, 'eeprom_size': 0, 'freq': 120}, 190 | {'type': 'STM32F207xF', 'flash_size': 768, 'sram_size': 128, 'eeprom_size': 0, 'freq': 120}, 191 | {'type': 'STM32F207xG', 'flash_size': 1024, 'sram_size': 128, 'eeprom_size': 0, 'freq': 120}, 192 | {'type': 'STM32F215xE', 'flash_size': 512, 'sram_size': 128, 'eeprom_size': 0, 'freq': 120}, 193 | {'type': 'STM32F215xG', 'flash_size': 1024, 'sram_size': 128, 'eeprom_size': 0, 'freq': 120}, 194 | {'type': 'STM32F217xE', 'flash_size': 512, 'sram_size': 128, 'eeprom_size': 0, 'freq': 120}, 195 | {'type': 'STM32F217xG', 'flash_size': 1024, 'sram_size': 128, 'eeprom_size': 0, 'freq': 120}, 196 | ], 197 | }, 198 | { 199 | 'dev_id': 0x412, 200 | 'flash_size_reg': 0x1ffff7e0, 201 | 'flash_driver': 'STM32FP', 202 | 'erase_sizes': (1024, ), 203 | 'devices': [ 204 | {'type': 'STM32F101x4', 'flash_size': 16, 'sram_size': 4, 'eeprom_size': 0, 'freq': 36}, 205 | {'type': 'STM32F101x6', 'flash_size': 32, 'sram_size': 6, 'eeprom_size': 0, 'freq': 36}, 206 | {'type': 'STM32F102x4', 'flash_size': 16, 'sram_size': 4, 'eeprom_size': 0, 'freq': 48}, 207 | {'type': 'STM32F102x6', 'flash_size': 32, 'sram_size': 6, 'eeprom_size': 0, 'freq': 48}, 208 | {'type': 'STM32F103x4', 'flash_size': 16, 'sram_size': 6, 'eeprom_size': 0, 'freq': 72}, 209 | {'type': 'STM32F103x6', 'flash_size': 32, 'sram_size': 10, 'eeprom_size': 0, 'freq': 72}, 210 | ], 211 | }, 212 | { 213 | 'dev_id': 0x414, 214 | 'flash_size_reg': 0x1ffff7e0, 215 | 'flash_driver': 'STM32FP', 216 | 'erase_sizes': (2048, ), 217 | 'devices': [ 218 | {'type': 'STM32F101xC', 'flash_size': 256, 'sram_size': 32, 'eeprom_size': 0, 'freq': 36}, 219 | {'type': 'STM32F101xD', 'flash_size': 384, 'sram_size': 48, 'eeprom_size': 0, 'freq': 36}, 220 | {'type': 'STM32F101xE', 'flash_size': 512, 'sram_size': 48, 'eeprom_size': 0, 'freq': 36}, 221 | {'type': 'STM32F103xC', 'flash_size': 256, 'sram_size': 48, 'eeprom_size': 0, 'freq': 72}, 222 | {'type': 'STM32F103xD', 'flash_size': 384, 'sram_size': 64, 'eeprom_size': 0, 'freq': 72}, 223 | {'type': 'STM32F103xE', 'flash_size': 512, 'sram_size': 64, 'eeprom_size': 0, 'freq': 72}, 224 | ], 225 | }, 226 | { 227 | 'dev_id': 0x416, 228 | 'flash_size_reg': 0x1ff8004c, 229 | 'flash_driver': 'STM32L0', 230 | 'erase_sizes': (256, ), 231 | 'devices': [ 232 | {'type': 'STM32L100x6', 'flash_size': 32, 'sram_size': 4, 'eeprom_size': 2, 'freq': 32}, 233 | {'type': 'STM32L100x8', 'flash_size': 64, 'sram_size': 8, 'eeprom_size': 2, 'freq': 32}, 234 | {'type': 'STM32L100xB', 'flash_size': 128, 'sram_size': 10, 'eeprom_size': 2, 'freq': 32}, 235 | {'type': 'STM32L151x6', 'flash_size': 32, 'sram_size': 10, 'eeprom_size': 4, 'freq': 32}, 236 | {'type': 'STM32L151x8', 'flash_size': 64, 'sram_size': 10, 'eeprom_size': 4, 'freq': 32}, 237 | {'type': 'STM32L151xB', 'flash_size': 128, 'sram_size': 16, 'eeprom_size': 4, 'freq': 32}, 238 | {'type': 'STM32L152x6', 'flash_size': 32, 'sram_size': 10, 'eeprom_size': 4, 'freq': 32}, 239 | {'type': 'STM32L152x8', 'flash_size': 64, 'sram_size': 10, 'eeprom_size': 4, 'freq': 32}, 240 | {'type': 'STM32L152xB', 'flash_size': 128, 'sram_size': 16, 'eeprom_size': 4, 'freq': 32}, 241 | ], 242 | }, 243 | { 244 | 'dev_id': 0x418, 245 | 'flash_size_reg': 0x1ffff7e0, 246 | 'flash_driver': 'STM32FP', 247 | 'erase_sizes': (2048, ), 248 | 'devices': [ 249 | {'type': 'STM32F105x8', 'flash_size': 64, 'sram_size': 64, 'eeprom_size': 0, 'freq': 72}, 250 | {'type': 'STM32F105xB', 'flash_size': 128, 'sram_size': 64, 'eeprom_size': 0, 'freq': 72}, 251 | {'type': 'STM32F105xC', 'flash_size': 256, 'sram_size': 64, 'eeprom_size': 0, 'freq': 72}, 252 | {'type': 'STM32F107xB', 'flash_size': 128, 'sram_size': 64, 'eeprom_size': 0, 'freq': 72}, 253 | {'type': 'STM32F107xC', 'flash_size': 256, 'sram_size': 64, 'eeprom_size': 0, 'freq': 72}, 254 | ], 255 | }, 256 | { 257 | 'dev_id': 0x420, 258 | 'flash_size_reg': 0x1ffff7e0, 259 | 'flash_driver': 'STM32FP', 260 | 'erase_sizes': (1024, ), 261 | 'devices': [ 262 | {'type': 'STM32F100x4', 'flash_size': 16, 'sram_size': 4, 'eeprom_size': 0, 'freq': 24}, 263 | {'type': 'STM32F100x6', 'flash_size': 32, 'sram_size': 4, 'eeprom_size': 0, 'freq': 24}, 264 | {'type': 'STM32F100x8', 'flash_size': 64, 'sram_size': 8, 'eeprom_size': 0, 'freq': 24}, 265 | {'type': 'STM32F100xB', 'flash_size': 128, 'sram_size': 8, 'eeprom_size': 0, 'freq': 24}, 266 | ], 267 | }, 268 | { 269 | 'dev_id': 0x427, 270 | 'flash_size_reg': 0x1ff800cc, 271 | 'flash_driver': 'STM32L0', 272 | 'erase_sizes': (256, ), 273 | 'devices': [ 274 | {'type': 'STM32L100xC', 'flash_size': 256, 'sram_size': 16, 'eeprom_size': 4, 'freq': 32}, 275 | ], 276 | }, 277 | { 278 | 'dev_id': 0x428, 279 | 'flash_size_reg': 0x1ffff7e0, 280 | 'flash_driver': 'STM32FP', 281 | 'erase_sizes': (2048, ), 282 | 'devices': [ 283 | {'type': 'STM32F100xC', 'flash_size': 256, 'sram_size': 24, 'eeprom_size': 0, 'freq': 24}, 284 | {'type': 'STM32F100xD', 'flash_size': 384, 'sram_size': 32, 'eeprom_size': 0, 'freq': 24}, 285 | {'type': 'STM32F100xE', 'flash_size': 512, 'sram_size': 32, 'eeprom_size': 0, 'freq': 24}, 286 | ], 287 | }, 288 | { 289 | 'dev_id': 0x429, 290 | 'flash_size_reg': 0x1ff8004c, 291 | 'flash_driver': 'STM32L0', 292 | 'erase_sizes': (256, ), 293 | 'devices': [ 294 | {'type': 'STM32L100x6-A', 'flash_size': 32, 'sram_size': 4, 'eeprom_size': 2, 'freq': 32}, 295 | {'type': 'STM32L100x8-A', 'flash_size': 64, 'sram_size': 8, 'eeprom_size': 2, 'freq': 32}, 296 | {'type': 'STM32L100xB-A', 'flash_size': 128, 'sram_size': 16, 'eeprom_size': 2, 'freq': 32}, 297 | {'type': 'STM32L151x6-A', 'flash_size': 32, 'sram_size': 16, 'eeprom_size': 4, 'freq': 32}, 298 | {'type': 'STM32L151x8-A', 'flash_size': 64, 'sram_size': 32, 'eeprom_size': 4, 'freq': 32}, 299 | {'type': 'STM32L151xB-A', 'flash_size': 128, 'sram_size': 32, 'eeprom_size': 4, 'freq': 32}, 300 | {'type': 'STM32L152x6-A', 'flash_size': 32, 'sram_size': 16, 'eeprom_size': 4, 'freq': 32}, 301 | {'type': 'STM32L152x8-A', 'flash_size': 64, 'sram_size': 32, 'eeprom_size': 4, 'freq': 32}, 302 | {'type': 'STM32L152xB-A', 'flash_size': 128, 'sram_size': 32, 'eeprom_size': 4, 'freq': 32}, 303 | ], 304 | }, 305 | { 306 | 'dev_id': 0x430, 307 | 'flash_size_reg': 0x1ffff7e0, 308 | 'flash_driver': 'STM32FPXL', 309 | 'erase_sizes': (2048, ), 310 | 'devices': [ 311 | {'type': 'STM32F101xF', 'flash_size': 768, 'sram_size': 80, 'eeprom_size': 0, 'freq': 36}, 312 | {'type': 'STM32F101xG', 'flash_size': 1024, 'sram_size': 80, 'eeprom_size': 0, 'freq': 36}, 313 | {'type': 'STM32F103xF', 'flash_size': 768, 'sram_size': 96, 'eeprom_size': 0, 'freq': 72}, 314 | {'type': 'STM32F103xG', 'flash_size': 1024, 'sram_size': 96, 'eeprom_size': 0, 'freq': 72}, 315 | ], 316 | }, 317 | { 318 | 'dev_id': 0x436, 319 | 'flash_size_reg': 0x1ff800cc, 320 | 'flash_driver': 'STM32L0', 321 | 'erase_sizes': (256, ), 322 | 'devices': [ 323 | {'type': 'STM32L151xC', 'flash_size': 256, 'sram_size': 32, 'eeprom_size': 8, 'freq': 32}, 324 | {'type': 'STM32L151xC-A', 'flash_size': 256, 'sram_size': 32, 'eeprom_size': 8, 'freq': 32}, 325 | {'type': 'STM32L151xD', 'flash_size': 384, 'sram_size': 48, 'eeprom_size': 12, 'freq': 32}, 326 | {'type': 'STM32L152xC', 'flash_size': 256, 'sram_size': 32, 'eeprom_size': 8, 'freq': 32}, 327 | {'type': 'STM32L152xC-A', 'flash_size': 256, 'sram_size': 32, 'eeprom_size': 8, 'freq': 32}, 328 | {'type': 'STM32L152xD', 'flash_size': 384, 'sram_size': 48, 'eeprom_size': 12, 'freq': 32}, 329 | {'type': 'STM32L162xC', 'flash_size': 256, 'sram_size': 32, 'eeprom_size': 8, 'freq': 32}, 330 | {'type': 'STM32L162xC-A', 'flash_size': 256, 'sram_size': 32, 'eeprom_size': 8, 'freq': 32}, 331 | {'type': 'STM32L162xD', 'flash_size': 384, 'sram_size': 48, 'eeprom_size': 12, 'freq': 32}, 332 | ], 333 | }, 334 | { 335 | 'dev_id': 0x437, 336 | 'flash_size_reg': 0x1ff800cc, 337 | 'flash_driver': 'STM32L0', 338 | 'erase_sizes': (256, ), 339 | 'devices': [ 340 | {'type': 'STM32L151xD-X', 'flash_size': 384, 'sram_size': 80, 'eeprom_size': 16, 'freq': 32}, 341 | {'type': 'STM32L151xE', 'flash_size': 512, 'sram_size': 80, 'eeprom_size': 16, 'freq': 32}, 342 | {'type': 'STM32L152xD-X', 'flash_size': 384, 'sram_size': 80, 'eeprom_size': 16, 'freq': 32}, 343 | {'type': 'STM32L152xE', 'flash_size': 512, 'sram_size': 80, 'eeprom_size': 16, 'freq': 32}, 344 | {'type': 'STM32L162xD-X', 'flash_size': 384, 'sram_size': 80, 'eeprom_size': 16, 'freq': 32}, 345 | {'type': 'STM32L162xE', 'flash_size': 512, 'sram_size': 80, 'eeprom_size': 16, 'freq': 32}, 346 | ], 347 | }, 348 | ], 349 | }, 350 | { 351 | 'part_no': 0xc24, 352 | 'core': 'CortexM4', 353 | 'idcode_reg': 0xE0042000, 354 | 'devices': [ 355 | { 356 | 'dev_id': 0x422, 357 | 'flash_size_reg': 0x1ffff7cc, 358 | 'flash_driver': 'STM32FP', 359 | 'erase_sizes': (2048, ), 360 | 'devices': [ 361 | {'type': 'STM32F302xB', 'flash_size': 128, 'sram_size': 32, 'eeprom_size': 0, 'freq': 72}, 362 | {'type': 'STM32F302xC', 'flash_size': 256, 'sram_size': 40, 'eeprom_size': 0, 'freq': 72}, 363 | {'type': 'STM32F303xB', 'flash_size': 128, 'sram_size': 40, 'eeprom_size': 0, 'freq': 72}, 364 | {'type': 'STM32F303xC', 'flash_size': 256, 'sram_size': 48, 'eeprom_size': 0, 'freq': 72}, 365 | {'type': 'STM32F358xC', 'flash_size': 256, 'sram_size': 48, 'eeprom_size': 0, 'freq': 72}, 366 | ], 367 | }, 368 | { 369 | 'dev_id': 0x432, 370 | 'flash_size_reg': 0x1ffff7cc, 371 | 'flash_driver': 'STM32FP', 372 | 'erase_sizes': (2048, ), 373 | 'devices': [ 374 | {'type': 'STM32F373x8', 'flash_size': 64, 'sram_size': 16, 'eeprom_size': 0, 'freq': 72}, 375 | {'type': 'STM32F373xB', 'flash_size': 128, 'sram_size': 24, 'eeprom_size': 0, 'freq': 72}, 376 | {'type': 'STM32F373xC', 'flash_size': 256, 'sram_size': 32, 'eeprom_size': 0, 'freq': 72}, 377 | {'type': 'STM32F378xC', 'flash_size': 256, 'sram_size': 32, 'eeprom_size': 0, 'freq': 72}, 378 | ], 379 | }, 380 | { 381 | 'dev_id': 0x438, 382 | 'flash_size_reg': 0x1ffff7cc, 383 | 'flash_driver': 'STM32FP', 384 | 'erase_sizes': (2048, ), 385 | 'devices': [ 386 | {'type': 'STM32F303x6', 'flash_size': 32, 'sram_size': 16, 'eeprom_size': 0, 'freq': 72}, 387 | {'type': 'STM32F303x8', 'flash_size': 64, 'sram_size': 16, 'eeprom_size': 0, 'freq': 72}, 388 | {'type': 'STM32F328x8', 'flash_size': 64, 'sram_size': 16, 'eeprom_size': 0, 'freq': 72}, 389 | {'type': 'STM32F334x4', 'flash_size': 16, 'sram_size': 16, 'eeprom_size': 0, 'freq': 72}, 390 | {'type': 'STM32F334x6', 'flash_size': 32, 'sram_size': 16, 'eeprom_size': 0, 'freq': 72}, 391 | {'type': 'STM32F334x8', 'flash_size': 64, 'sram_size': 16, 'eeprom_size': 0, 'freq': 72}, 392 | ], 393 | }, 394 | { 395 | 'dev_id': 0x439, 396 | 'flash_size_reg': 0x1ffff7cc, 397 | 'flash_driver': 'STM32FP', 398 | 'erase_sizes': (2048, ), 399 | 'devices': [ 400 | {'type': 'STM32F301x6', 'flash_size': 32, 'sram_size': 16, 'eeprom_size': 0, 'freq': 72}, 401 | {'type': 'STM32F301x8', 'flash_size': 64, 'sram_size': 16, 'eeprom_size': 0, 'freq': 72}, 402 | {'type': 'STM32F302x6', 'flash_size': 32, 'sram_size': 16, 'eeprom_size': 0, 'freq': 72}, 403 | {'type': 'STM32F302x8', 'flash_size': 64, 'sram_size': 16, 'eeprom_size': 0, 'freq': 72}, 404 | {'type': 'STM32F318x8', 'flash_size': 64, 'sram_size': 16, 'eeprom_size': 0, 'freq': 72}, 405 | ], 406 | }, 407 | { 408 | 'dev_id': 0x446, 409 | 'flash_size_reg': 0x1ffff7cc, 410 | 'flash_driver': 'STM32FP', 411 | 'erase_sizes': (2048, ), 412 | 'devices': [ 413 | {'type': 'STM32F302xD', 'flash_size': 384, 'sram_size': 64, 'eeprom_size': 0, 'freq': 72}, 414 | {'type': 'STM32F302xE', 'flash_size': 512, 'sram_size': 64, 'eeprom_size': 0, 'freq': 72}, 415 | {'type': 'STM32F303xD', 'flash_size': 384, 'sram_size': 80, 'eeprom_size': 0, 'freq': 72}, 416 | {'type': 'STM32F303xE', 'flash_size': 512, 'sram_size': 80, 'eeprom_size': 0, 'freq': 72}, 417 | {'type': 'STM32F398xE', 'flash_size': 512, 'sram_size': 80, 'eeprom_size': 0, 'freq': 72}, 418 | ], 419 | }, 420 | { 421 | 'dev_id': 0x413, 422 | 'flash_size_reg': 0x1fff7a22, 423 | 'flash_driver': 'STM32FS', 424 | 'erase_sizes': (16*1024, 16*1024, 16*1024, 16*1024, 64*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, ), 425 | 'devices': [ 426 | {'type': 'STM32F405xE', 'flash_size': 512, 'sram_size': 192, 'eeprom_size': 0, 'freq': 168}, 427 | {'type': 'STM32F405xG', 'flash_size': 1024, 'sram_size': 192, 'eeprom_size': 0, 'freq': 168}, 428 | {'type': 'STM32F407xE', 'flash_size': 512, 'sram_size': 192, 'eeprom_size': 0, 'freq': 168}, 429 | {'type': 'STM32F407xG', 'flash_size': 1024, 'sram_size': 192, 'eeprom_size': 0, 'freq': 168}, 430 | {'type': 'STM32F415xG', 'flash_size': 1024, 'sram_size': 192, 'eeprom_size': 0, 'freq': 168}, 431 | {'type': 'STM32F417xE', 'flash_size': 512, 'sram_size': 192, 'eeprom_size': 0, 'freq': 168}, 432 | {'type': 'STM32F417xG', 'flash_size': 1024, 'sram_size': 192, 'eeprom_size': 0, 'freq': 168}, 433 | ], 434 | }, 435 | { 436 | 'dev_id': 0x415, 437 | 'flash_size_reg': 0x1fff75e0, 438 | 'flash_driver': 'STM32L4', 439 | 'erase_sizes': (2 * 1024,), 440 | 'devices': [ 441 | {'type': 'STM32L475xC', 'flash_size': 256, 'sram_size': 128, 'eeprom_size': 0, 'freq': 80}, 442 | {'type': 'STM32L475xE', 'flash_size': 512, 'sram_size': 128, 'eeprom_size': 0, 'freq': 80}, 443 | {'type': 'STM32L475xG', 'flash_size': 1024, 'sram_size': 128, 'eeprom_size': 0, 'freq': 80}, 444 | {'type': 'STM32L476xC', 'flash_size': 256, 'sram_size': 128, 'eeprom_size': 0, 'freq': 80}, 445 | {'type': 'STM32L476xE', 'flash_size': 512, 'sram_size': 128, 'eeprom_size': 0, 'freq': 80}, 446 | {'type': 'STM32L476xG', 'flash_size': 1024, 'sram_size': 128, 'eeprom_size': 0, 'freq': 80}, 447 | {'type': 'STM32L486xG', 'flash_size': 1024, 'sram_size': 128, 'eeprom_size': 0, 'freq': 80}, 448 | {'type': 'STM32L471xE', 'flash_size': 512, 'sram_size': 128, 'eeprom_size': 0, 'freq': 80}, 449 | {'type': 'STM32L471xG', 'flash_size': 1024, 'sram_size': 128, 'eeprom_size': 0, 'freq': 80}, 450 | ], 451 | }, 452 | { 453 | 'dev_id': 0x419, 454 | 'flash_size_reg': 0x1fff7a22, 455 | 'flash_driver': 'STM32FS', 456 | 'erase_sizes': (16*1024, 16*1024, 16*1024, 16*1024, 64*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, ), 457 | 'devices': [ 458 | {'type': 'STM32F427xG', 'flash_size': 1024, 'sram_size': 256, 'eeprom_size': 0, 'freq': 180}, 459 | {'type': 'STM32F427xI', 'flash_size': 2048, 'sram_size': 256, 'eeprom_size': 0, 'freq': 180}, 460 | {'type': 'STM32F429xE', 'flash_size': 512, 'sram_size': 256, 'eeprom_size': 0, 'freq': 180}, 461 | {'type': 'STM32F429xG', 'flash_size': 1024, 'sram_size': 256, 'eeprom_size': 0, 'freq': 180}, 462 | {'type': 'STM32F429xI', 'flash_size': 2048, 'sram_size': 256, 'eeprom_size': 0, 'freq': 180}, 463 | {'type': 'STM32F437xG', 'flash_size': 1024, 'sram_size': 256, 'eeprom_size': 0, 'freq': 180}, 464 | {'type': 'STM32F437xI', 'flash_size': 2048, 'sram_size': 256, 'eeprom_size': 0, 'freq': 180}, 465 | {'type': 'STM32F439xG', 'flash_size': 1024, 'sram_size': 256, 'eeprom_size': 0, 'freq': 180}, 466 | {'type': 'STM32F439xI', 'flash_size': 2048, 'sram_size': 256, 'eeprom_size': 0, 'freq': 180}, 467 | ], 468 | }, 469 | { 470 | 'dev_id': 0x421, 471 | 'flash_size_reg': 0x1fff7a22, 472 | 'flash_driver': 'STM32FS', 473 | 'erase_sizes': (16*1024, 16*1024, 16*1024, 16*1024, 64*1024, 128*1024, 128*1024, 128*1024, ), 474 | 'devices': [ 475 | {'type': 'STM32F446xC', 'flash_size': 256, 'sram_size': 128, 'eeprom_size': 0, 'freq': 180}, 476 | {'type': 'STM32F446xE', 'flash_size': 512, 'sram_size': 128, 'eeprom_size': 0, 'freq': 180}, 477 | ], 478 | }, 479 | { 480 | 'dev_id': 0x423, 481 | 'flash_size_reg': 0x1fff7a22, 482 | 'flash_driver': 'STM32FS', 483 | 'erase_sizes': (16*1024, 16*1024, 16*1024, 16*1024, 64*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, ), 484 | 'devices': [ 485 | {'type': 'STM32F401xB', 'flash_size': 128, 'sram_size': 64, 'eeprom_size': 0, 'freq': 84}, 486 | {'type': 'STM32F401xC', 'flash_size': 256, 'sram_size': 64, 'eeprom_size': 0, 'freq': 84}, 487 | ], 488 | }, 489 | { 490 | 'dev_id': 0x431, 491 | 'flash_size_reg': 0x1fff7a22, 492 | 'flash_driver': 'STM32FS', 493 | 'erase_sizes': (16*1024, 16*1024, 16*1024, 16*1024, 64*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, ), 494 | 'devices': [ 495 | {'type': 'STM32F411xC', 'flash_size': 256, 'sram_size': 128, 'eeprom_size': 0, 'freq': 100}, 496 | {'type': 'STM32F411xE', 'flash_size': 512, 'sram_size': 128, 'eeprom_size': 0, 'freq': 100}, 497 | ], 498 | }, 499 | { 500 | 'dev_id': 0x433, 501 | 'flash_size_reg': 0x1fff7a22, 502 | 'flash_driver': 'STM32FS', 503 | 'erase_sizes': (16*1024, 16*1024, 16*1024, 16*1024, 64*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, ), 504 | 'devices': [ 505 | {'type': 'STM32F401xD', 'flash_size': 384, 'sram_size': 96, 'eeprom_size': 0, 'freq': 84}, 506 | {'type': 'STM32F401xE', 'flash_size': 512, 'sram_size': 96, 'eeprom_size': 0, 'freq': 84}, 507 | ], 508 | }, 509 | { 510 | 'dev_id': 0x434, 511 | 'flash_size_reg': 0x1fff7a22, 512 | 'flash_driver': 'STM32FS', 513 | 'erase_sizes': (16*1024, 16*1024, 16*1024, 16*1024, 64*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, ), 514 | 'devices': [ 515 | {'type': 'STM32F469xE', 'flash_size': 512, 'sram_size': 384, 'eeprom_size': 0, 'freq': 180}, 516 | {'type': 'STM32F469xG', 'flash_size': 1024, 'sram_size': 384, 'eeprom_size': 0, 'freq': 180}, 517 | {'type': 'STM32F469xI', 'flash_size': 2048, 'sram_size': 384, 'eeprom_size': 0, 'freq': 180}, 518 | {'type': 'STM32F479xG', 'flash_size': 1024, 'sram_size': 384, 'eeprom_size': 0, 'freq': 180}, 519 | {'type': 'STM32F479xI', 'flash_size': 2048, 'sram_size': 384, 'eeprom_size': 0, 'freq': 180}, 520 | ], 521 | }, 522 | { 523 | 'dev_id': 0x464, 524 | 'flash_size_reg': 0x1fff75e0, 525 | 'flash_driver': 'STM32L4', 526 | 'erase_sizes': (2 * 1024,), 527 | 'devices': [ 528 | {'type': 'STM32L412x8', 'flash_size': 64, 'sram_size': 40, 'eeprom_size': 0, 'freq': 80}, 529 | {'type': 'STM32L412xB', 'flash_size': 128, 'sram_size': 40, 'eeprom_size': 0, 'freq': 80}, 530 | {'type': 'STM32L422xB', 'flash_size': 128, 'sram_size': 40, 'eeprom_size': 0, 'freq': 80}, 531 | ], 532 | }, 533 | { 534 | 'dev_id': 0x435, 535 | 'flash_size_reg': 0x1fff75e0, 536 | 'flash_driver': 'STM32L4', 537 | 'erase_sizes': (2 * 1024,), 538 | 'devices': [ 539 | {'type': 'STM32L431xB', 'flash_size': 128, 'sram_size': 64, 'eeprom_size': 0, 'freq': 80}, 540 | {'type': 'STM32L431xC', 'flash_size': 256, 'sram_size': 64, 'eeprom_size': 0, 'freq': 80}, 541 | {'type': 'STM32L432xB', 'flash_size': 128, 'sram_size': 64, 'eeprom_size': 0, 'freq': 80}, 542 | {'type': 'STM32L432xC', 'flash_size': 256, 'sram_size': 64, 'eeprom_size': 0, 'freq': 80}, 543 | {'type': 'STM32L433xB', 'flash_size': 128, 'sram_size': 64, 'eeprom_size': 0, 'freq': 80}, 544 | {'type': 'STM32L433xC', 'flash_size': 256, 'sram_size': 64, 'eeprom_size': 0, 'freq': 80}, 545 | {'type': 'STM32L442xC', 'flash_size': 256, 'sram_size': 64, 'eeprom_size': 0, 'freq': 80}, 546 | {'type': 'STM32L443xC', 'flash_size': 256, 'sram_size': 64, 'eeprom_size': 0, 'freq': 80}, 547 | ], 548 | }, 549 | { 550 | 'dev_id': 0x462, 551 | 'flash_size_reg': 0x1fff75e0, 552 | 'flash_driver': 'STM32L4', 553 | 'erase_sizes': (2 * 1024,), 554 | 'devices': [ 555 | {'type': 'STM32L451xC', 'flash_size': 256, 'sram_size': 160, 'eeprom_size': 0, 'freq': 80}, 556 | {'type': 'STM32L451xE', 'flash_size': 512, 'sram_size': 160, 'eeprom_size': 0, 'freq': 80}, 557 | {'type': 'STM32L452xC', 'flash_size': 256, 'sram_size': 160, 'eeprom_size': 0, 'freq': 80}, 558 | {'type': 'STM32L452xE', 'flash_size': 512, 'sram_size': 160, 'eeprom_size': 0, 'freq': 80}, 559 | {'type': 'STM32L462xE', 'flash_size': 512, 'sram_size': 160, 'eeprom_size': 0, 'freq': 80}, 560 | ], 561 | }, 562 | { 563 | 'dev_id': 0x441, 564 | 'flash_size_reg': 0x1fff7a22, 565 | 'flash_driver': 'STM32FS', 566 | 'erase_sizes': (16*1024, 16*1024, 16*1024, 16*1024, 64*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, ), 567 | 'devices': [ 568 | {'type': 'STM32F412xE', 'flash_size': 512, 'sram_size': 256, 'eeprom_size': 0, 'freq': 100}, 569 | {'type': 'STM32F412xG', 'flash_size': 1024, 'sram_size': 256, 'eeprom_size': 0, 'freq': 100}, 570 | ], 571 | }, 572 | { 573 | 'dev_id': 0x458, 574 | 'flash_size_reg': 0x1fff7a22, 575 | 'flash_driver': 'STM32FS', 576 | 'erase_sizes': (16*1024, 16*1024, 16*1024, 16*1024, 64*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, ), 577 | 'devices': [ 578 | {'type': 'STM32F410x8', 'flash_size': 64, 'sram_size': 32, 'eeprom_size': 0, 'freq': 100}, 579 | {'type': 'STM32F410xB', 'flash_size': 128, 'sram_size': 32, 'eeprom_size': 0, 'freq': 100}, 580 | ], 581 | }, 582 | { 583 | 'dev_id': 0x461, 584 | 'flash_size_reg': 0x1fff75e0, 585 | 'flash_driver': 'STM32L4', 586 | 'erase_sizes': (2 * 1024, ), 587 | 'devices': [ 588 | {'type': 'STM32L496xE', 'flash_size': 512, 'sram_size': 320, 'eeprom_size': 0, 'freq': 80}, 589 | {'type': 'STM32L496xG', 'flash_size': 1024, 'sram_size': 320, 'eeprom_size': 0, 'freq': 80}, 590 | {'type': 'STM32L4A6xG', 'flash_size': 1024, 'sram_size': 320, 'eeprom_size': 0, 'freq': 80}, 591 | ], 592 | }, 593 | { 594 | 'dev_id': 0x463, 595 | 'flash_size_reg': 0x1fff7a22, 596 | 'flash_driver': 'STM32FS', 597 | 'erase_sizes': (16*1024, 16*1024, 16*1024, 16*1024, 64*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, 128*1024, ), 598 | 'devices': [ 599 | {'type': 'STM32F413xG', 'flash_size': 1024, 'sram_size': 320, 'eeprom_size': 0, 'freq': 100}, 600 | {'type': 'STM32F413xH', 'flash_size': 1536, 'sram_size': 320, 'eeprom_size': 0, 'freq': 100}, 601 | {'type': 'STM32F423xH', 'flash_size': 1536, 'sram_size': 320, 'eeprom_size': 0, 'freq': 100}, 602 | ], 603 | }, 604 | { 605 | 'dev_id': 0x470, 606 | 'flash_size_reg': 0x1fff75e0, 607 | 'flash_driver': 'STM32L4', 608 | 'erase_sizes': (4*1024, ), 609 | 'devices': [ 610 | {'type': 'STM32L4[R|S]xxG', 'flash_size': 1024, 'sram_size': 640, 'eeprom_size': 0, 'freq': 120}, 611 | {'type': 'STM32L4[R|S]xxI', 'flash_size': 2048, 'sram_size': 640, 'eeprom_size': 0, 'freq': 120}, 612 | ], 613 | }, 614 | { 615 | 'dev_id': 0x495, 616 | 'flash_size_reg': 0x1fff75e0, 617 | 'flash_driver': 'STM32L4', 618 | 'erase_sizes': (4 * 1024, ), 619 | 'devices': [ 620 | {'type': 'STM32WB55xC', 'flash_size': 256, 'sram_size': 128, 'eeprom_size': 0, 'freq': 64}, 621 | {'type': 'STM32WB55xE', 'flash_size': 512, 'sram_size': 256, 'eeprom_size': 0, 'freq': 64}, 622 | {'type': 'STM32WB55xG', 'flash_size': 1024, 'sram_size': 256, 'eeprom_size': 0, 'freq': 64}, 623 | ], 624 | }, 625 | { 626 | 'dev_id': 0x468, 627 | 'flash_size_reg': 0x1fff75e0, 628 | 'flash_driver': 'STM32L4', 629 | 'erase_sizes': (2 * 1024, ), 630 | 'devices': [ 631 | {'type': 'STM32G43xx6', 'flash_size': 32, 'sram_size': 32, 'eeprom_size': 0, 'freq': 170}, 632 | {'type': 'STM32G43xx8', 'flash_size': 64, 'sram_size': 32, 'eeprom_size': 0, 'freq': 170}, 633 | {'type': 'STM32G43xxB', 'flash_size': 128, 'sram_size': 32, 'eeprom_size': 0, 'freq': 170}, 634 | ], 635 | }, 636 | { 637 | 'dev_id': 0x469, 638 | 'flash_size_reg': 0x1fff75e0, 639 | 'flash_driver': 'STM32L4', 640 | 'erase_sizes': (2 * 1024, ), 641 | 'devices': [ 642 | {'type': 'STM32G47xxB', 'flash_size': 128, 'sram_size': 128, 'eeprom_size': 0, 'freq': 170}, 643 | {'type': 'STM32G47xxC', 'flash_size': 256, 'sram_size': 128, 'eeprom_size': 0, 'freq': 170}, 644 | {'type': 'STM32G47xxE', 'flash_size': 512, 'sram_size': 128, 'eeprom_size': 0, 'freq': 170}, 645 | ], 646 | }, 647 | ], 648 | }, 649 | { 650 | 'part_no': 0xc27, 651 | 'core': 'CortexM7', 652 | 'idcode_reg': [0xe0042000, 0x5c001000], 653 | 'devices': [ 654 | { 655 | 'dev_id': 0x449, 656 | 'flash_size_reg': 0x1ff0f442, 657 | 'flash_driver': 'STM32FS', 658 | 'erase_sizes': (32*1024, 32*1024, 32*1024, 32*1024, 128*1024, 256*1024, 256*1024, 256*1024, ), 659 | 'devices': [ 660 | {'type': 'STM32F745xE', 'flash_size': 512, 'sram_size': 320, 'eeprom_size': 0, 'freq': 216}, 661 | {'type': 'STM32F745xG', 'flash_size': 1024, 'sram_size': 320, 'eeprom_size': 0, 'freq': 216}, 662 | {'type': 'STM32F746xE', 'flash_size': 512, 'sram_size': 320, 'eeprom_size': 0, 'freq': 216}, 663 | {'type': 'STM32F746xG', 'flash_size': 1024, 'sram_size': 320, 'eeprom_size': 0, 'freq': 216}, 664 | {'type': 'STM32F756xG', 'flash_size': 1024, 'sram_size': 320, 'eeprom_size': 0, 'freq': 216}, 665 | ] 666 | }, 667 | { 668 | 'dev_id': 0x451, 669 | 'flash_size_reg': 0x1ff0f442, 670 | 'flash_driver': 'STM32FS', 671 | 'erase_sizes': (32*1024, 32*1024, 32*1024, 32*1024, 128*1024, 256*1024, 256*1024, 256*1024, ), 672 | 'devices': [ 673 | {'type': 'STM32F765xG', 'flash_size': 1024, 'sram_size': 512, 'eeprom_size': 0, 'freq': 216}, 674 | {'type': 'STM32F765xI', 'flash_size': 2048, 'sram_size': 512, 'eeprom_size': 0, 'freq': 216}, 675 | {'type': 'STM32F767xG', 'flash_size': 1024, 'sram_size': 512, 'eeprom_size': 0, 'freq': 216}, 676 | {'type': 'STM32F767xI', 'flash_size': 2048, 'sram_size': 512, 'eeprom_size': 0, 'freq': 216}, 677 | {'type': 'STM32F769xG', 'flash_size': 1024, 'sram_size': 512, 'eeprom_size': 0, 'freq': 216}, 678 | {'type': 'STM32F769xI', 'flash_size': 2048, 'sram_size': 512, 'eeprom_size': 0, 'freq': 216}, 679 | {'type': 'STM32F777xI', 'flash_size': 2048, 'sram_size': 512, 'eeprom_size': 0, 'freq': 216}, 680 | {'type': 'STM32F778xI', 'flash_size': 2048, 'sram_size': 512, 'eeprom_size': 0, 'freq': 216}, 681 | {'type': 'STM32F779xI', 'flash_size': 2048, 'sram_size': 512, 'eeprom_size': 0, 'freq': 216}, 682 | ] 683 | }, 684 | { 685 | 'dev_id': 0x452, 686 | 'flash_size_reg': 0x1ff07a22, 687 | 'flash_driver': 'STM32FS', 688 | 'erase_sizes': (16*1024, 16*1024, 16*1024, 16*1024, 64*1024, 128*1024, 128*1024, 128*1024, ), 689 | 'devices': [ 690 | {'type': 'STM32F722xC', 'flash_size': 256, 'sram_size': 256, 'eeprom_size': 0, 'freq': 216}, 691 | {'type': 'STM32F722xE', 'flash_size': 512, 'sram_size': 256, 'eeprom_size': 0, 'freq': 216}, 692 | {'type': 'STM32F723xC', 'flash_size': 256, 'sram_size': 256, 'eeprom_size': 0, 'freq': 216}, 693 | {'type': 'STM32F723xE', 'flash_size': 512, 'sram_size': 256, 'eeprom_size': 0, 'freq': 216}, 694 | {'type': 'STM32F732xE', 'flash_size': 512, 'sram_size': 256, 'eeprom_size': 0, 'freq': 216}, 695 | {'type': 'STM32F733xE', 'flash_size': 512, 'sram_size': 256, 'eeprom_size': 0, 'freq': 216}, 696 | ] 697 | }, 698 | { 699 | 'dev_id': 0x450, 700 | 'flash_size_reg': 0x1ff1e880, 701 | 'flash_driver': 'STM32H7', 702 | 'erase_sizes': (128*1024,), 703 | 'devices': [ 704 | {'type': 'STM32H743xI', 'flash_size': 2048, 'sram_size': 1024, 'eeprom_size': 0, 'freq': 480}, 705 | {'type': 'STM32H753xI', 'flash_size': 2048, 'sram_size': 1024, 'eeprom_size': 0, 'freq': 480}, 706 | {'type': 'STM32H750xI', 'flash_size': 128, 'sram_size': 1024, 'eeprom_size': 0, 'freq': 480}, 707 | {'type': 'STM32H745xI', 'flash_size': 2048, 'sram_size': 1024, 'eeprom_size': 0, 'freq': 480}, 708 | {'type': 'STM32H755xI', 'flash_size': 2048, 'sram_size': 1024, 'eeprom_size': 0, 'freq': 480}, 709 | ] 710 | }, 711 | ] 712 | }, 713 | ] 714 | -------------------------------------------------------------------------------- /lib/stm32fp.py: -------------------------------------------------------------------------------- 1 | import time 2 | import lib.stm32 3 | import lib.stlinkex 4 | 5 | 6 | class Flash(): 7 | FLASH_REG_BASE = 0x40022000 8 | FLASH_REG_BASE_STEP = 0x40 9 | FLASH_KEYR_INDEX = 0x04 10 | FLASH_SR_INDEX = 0x0c 11 | FLASH_CR_INDEX = 0x10 12 | FLASH_AR_INDEX = 0x14 13 | FLASH_KEYR_REG = FLASH_REG_BASE + FLASH_KEYR_INDEX 14 | FLASH_SR_REG = FLASH_REG_BASE + FLASH_SR_INDEX 15 | FLASH_CR_REG = FLASH_REG_BASE + FLASH_CR_INDEX 16 | FLASH_AR_REG = FLASH_REG_BASE + FLASH_AR_INDEX 17 | 18 | FLASH_CR_LOCK_BIT = 0x00000080 19 | FLASH_CR_PG_BIT = 0x00000001 20 | FLASH_CR_PER_BIT = 0x00000002 21 | FLASH_CR_MER_BIT = 0x00000004 22 | FLASH_CR_STRT_BIT = 0x00000040 23 | FLASH_SR_BUSY_BIT = 0x00000001 24 | FLASH_SR_PGERR_BIT = 0x00000004 25 | FLASH_SR_WRPRTERR_BIT = 0x00000010 26 | FLASH_SR_EOP_BIT = 0x00000020 27 | 28 | def __init__(self, driver, stlink, dbg, bank=0): 29 | self._driver = driver 30 | self._stlink = stlink 31 | self._dbg = dbg 32 | self._stlink.read_target_voltage() 33 | reg_bank = Flash.FLASH_REG_BASE + Flash.FLASH_REG_BASE_STEP * bank 34 | Flash.FLASH_KEYR_REG = reg_bank + Flash.FLASH_KEYR_INDEX 35 | Flash.FLASH_SR_REG = reg_bank + Flash.FLASH_SR_INDEX 36 | Flash.FLASH_CR_REG = reg_bank + Flash.FLASH_CR_INDEX 37 | Flash.FLASH_AR_REG = reg_bank + Flash.FLASH_AR_INDEX 38 | if self._stlink.target_voltage < 2.0: 39 | raise lib.stlinkex.StlinkException('Supply voltage is %.2fV, but minimum for FLASH program or erase is 2.0V' % self._stlink.target_voltage) 40 | self.unlock() 41 | 42 | def clear_sr(self): 43 | # clear errors 44 | sr = self._stlink.get_debugreg32(Flash.FLASH_SR_REG) 45 | self._stlink.set_debugreg32(Flash.FLASH_SR_REG, sr) 46 | 47 | def unlock(self): 48 | self._driver.core_reset_halt() 49 | self.clear_sr() 50 | # programing locked 51 | if self._stlink.get_debugreg32(Flash.FLASH_CR_REG) & Flash.FLASH_CR_LOCK_BIT: 52 | # unlock keys 53 | self._stlink.set_debugreg32(Flash.FLASH_KEYR_REG, 0x45670123) 54 | self._stlink.set_debugreg32(Flash.FLASH_KEYR_REG, 0xcdef89ab) 55 | # programing locked 56 | if self._stlink.get_debugreg32(Flash.FLASH_CR_REG) & Flash.FLASH_CR_LOCK_BIT: 57 | raise lib.stlinkex.StlinkException('Error unlocking FLASH') 58 | 59 | def lock(self): 60 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_LOCK_BIT) 61 | self._driver.core_reset_halt() 62 | 63 | def erase_all(self): 64 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_MER_BIT) 65 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_MER_BIT | Flash.FLASH_CR_STRT_BIT) 66 | self.wait_busy(2, 'Erasing FLASH') 67 | 68 | def erase_page(self, page_addr): 69 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_PER_BIT) 70 | self._stlink.set_debugreg32(Flash.FLASH_AR_REG, page_addr) 71 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_PER_BIT | Flash.FLASH_CR_STRT_BIT) 72 | self.wait_busy(0.2) 73 | 74 | def erase_pages(self, flash_start, erase_sizes, addr, size): 75 | page_addr = flash_start 76 | self._dbg.bargraph_start('Erasing FLASH', value_min=addr, value_max=addr + size) 77 | while True: 78 | for page_size in erase_sizes: 79 | if addr < page_addr + page_size: 80 | self._dbg.bargraph_update(value=page_addr) 81 | self.erase_page(page_addr) 82 | page_addr += page_size 83 | if addr + size < page_addr: 84 | self._dbg.bargraph_done() 85 | return 86 | 87 | def wait_busy(self, wait_time, bargraph_msg=None): 88 | end_time = time.time() 89 | if bargraph_msg: 90 | self._dbg.bargraph_start(bargraph_msg, value_min=time.time(), value_max=end_time + wait_time) 91 | # all times are from data sheet, will be more safe to wait 2 time longer 92 | end_time += wait_time * 2 93 | while time.time() < end_time: 94 | if bargraph_msg: 95 | self._dbg.bargraph_update(value=time.time()) 96 | status = self._stlink.get_debugreg32(Flash.FLASH_SR_REG) 97 | if not status & Flash.FLASH_SR_BUSY_BIT: 98 | self.end_of_operation(status) 99 | if bargraph_msg: 100 | self._dbg.bargraph_done() 101 | return 102 | time.sleep(wait_time / 20) 103 | raise lib.stlinkex.StlinkException('Operation timeout') 104 | 105 | def wait_for_breakpoint(self, wait_time): 106 | end_time = time.time() + wait_time 107 | while time.time() < end_time and not self._stlink.get_debugreg32(lib.stm32.Stm32.DHCSR_REG) & lib.stm32.Stm32.DHCSR_STATUS_HALT_BIT: 108 | time.sleep(wait_time / 20) 109 | self.end_of_operation(self._stlink.get_debugreg32(Flash.FLASH_SR_REG)) 110 | 111 | def end_of_operation(self, status): 112 | if status != Flash.FLASH_SR_EOP_BIT: 113 | raise lib.stlinkex.StlinkException('Error writing FLASH with status (FLASH_SR) %08x' % status) 114 | self._stlink.set_debugreg32(Flash.FLASH_SR_REG, status) 115 | 116 | 117 | # support all STM32F MCUs with page access to FLASH 118 | # (STM32F0xx, STM32F1xx and also STM32F3xx) 119 | class Stm32FP(lib.stm32.Stm32): 120 | def _flash_erase_all(self, bank=0): 121 | flash = Flash(self, self._stlink, self._dbg, bank=bank) 122 | flash.erase_all() 123 | flash.lock() 124 | 125 | def flash_erase_all(self, flash_size): 126 | self._dbg.debug('Stm32FP.flash_erase_all()') 127 | self._flash_erase_all() 128 | 129 | def _flash_write(self, addr, data, erase=False, erase_sizes=None, bank=0): 130 | # align data 131 | if len(data) % 2: 132 | data.extend([0xff] * (2 - len(data) % 2)) 133 | flash = Flash(self, self._stlink, self._dbg, bank=bank) 134 | if erase: 135 | if erase_sizes: 136 | flash.erase_pages(self.FLASH_START, erase_sizes, addr, len(data)) 137 | else: 138 | flash.erase_all() 139 | self._dbg.bargraph_start('Writing FLASH', value_min=addr, value_max=addr + len(data)) 140 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_PG_BIT) 141 | while(data): 142 | self._dbg.bargraph_update(value=addr) 143 | block = data[:self._stlink.STLINK_MAXIMUM_TRANSFER_SIZE] 144 | data = data[self._stlink.STLINK_MAXIMUM_TRANSFER_SIZE:] 145 | if min(block) != 0xff: 146 | self._stlink.set_mem16(addr, block) 147 | addr += len(block) 148 | flash.wait_busy(0.001) 149 | flash.lock() 150 | self._dbg.bargraph_done() 151 | 152 | def flash_write(self, addr, data, erase=False, erase_sizes=None): 153 | self._dbg.debug('Stm32FP.flash_write(%s, [data:%dBytes], erase=%s, erase_sizes=%s)' % (('0x%08x' % addr) if addr is not None else 'None', len(data), erase, erase_sizes)) 154 | if addr is None: 155 | addr = self.FLASH_START 156 | elif addr % 2: 157 | raise lib.stlinkex.StlinkException('Start address is not aligned to half-word') 158 | self._flash_write(addr, data, erase=erase, erase_sizes=erase_sizes) 159 | 160 | 161 | # support STM32F MCUs with page access to FLASH and two banks 162 | # (STM32F1xxxF and STM32F1xxxG) (XL devices) 163 | class Stm32FPXL(Stm32FP): 164 | BANK_SIZE = 512 * 1024 165 | 166 | def flash_erase_all(self, flash_size): 167 | self._dbg.debug('Stm32F1.flash_erase_all()') 168 | self._flash_erase_all(bank=0) 169 | self._flash_erase_all(bank=1) 170 | 171 | def flash_write(self, addr, data, erase=False, erase_sizes=None): 172 | self._dbg.debug('Stm32F1.flash_write(%s, [data:%dBytes], erase=%s, erase_sizes=%s)' % (('0x%08x' % addr) if addr is not None else 'None', len(data), erase, erase_sizes)) 173 | if addr is None: 174 | addr = self.FLASH_START 175 | elif addr % 2: 176 | raise lib.stlinkex.StlinkException('Start address is not aligned to half-word') 177 | if (addr - self.FLASH_START) + len(data) <= Stm32FPXL.BANK_SIZE: 178 | self._flash_write(addr, data, erase=erase, erase_sizes=erase_sizes, bank=0) 179 | elif (addr - self.FLASH_START) > Stm32FPXL.BANK_SIZE: 180 | self._flash_write(addr, data, erase=erase, erase_sizes=erase_sizes, bank=1) 181 | else: 182 | addr_bank1 = addr 183 | addr_bank2 = self.FLASH_START + Stm32FPXL.BANK_SIZE 184 | data_bank1 = data[:(Stm32FPXL.BANK_SIZE - (addr - self.FLASH_START))] 185 | data_bank2 = data[(Stm32FPXL.BANK_SIZE - (addr - self.FLASH_START)):] 186 | self._flash_write(addr_bank1, data_bank1, erase=erase, erase_sizes=erase_sizes, bank=0) 187 | self._flash_write(addr_bank2, data_bank2, erase=erase, erase_sizes=erase_sizes, bank=1) 188 | -------------------------------------------------------------------------------- /lib/stm32fs.py: -------------------------------------------------------------------------------- 1 | import time 2 | import lib.stm32 3 | import lib.stlinkex 4 | 5 | 6 | class Flash(): 7 | ITCM_BASE = 0x00200000 8 | FLASH_REG_BASE = 0x40023c00 9 | FLASH_KEYR_REG = FLASH_REG_BASE + 0x04 10 | FLASH_SR_REG = FLASH_REG_BASE + 0x0c 11 | FLASH_CR_REG = FLASH_REG_BASE + 0x10 12 | 13 | FLASH_CR_LOCK_BIT = 0x80000000 14 | FLASH_CR_PG_BIT = 0x00000001 15 | FLASH_CR_SER_BIT = 0x00000002 16 | FLASH_CR_MER_BIT = 0x00000004 17 | FLASH_CR_STRT_BIT = 0x00010000 18 | FLASH_CR_PSIZE_X8 = 0x00000000 19 | FLASH_CR_PSIZE_X16 = 0x00000100 20 | FLASH_CR_PSIZE_X32 = 0x00000200 21 | FLASH_CR_PSIZE_X64 = 0x00000300 22 | FLASH_CR_SNB_BITINDEX = 3 23 | 24 | FLASH_SR_EOP = 1 << 0 25 | FLASH_SR_OPERR = 1 << 1 26 | FLASH_SR_WRPERR = 1 << 4 27 | FLASH_SR_PGAERR = 1 << 5 28 | FLASH_SR_PGPERR = 1 << 6 29 | FLASH_SR_ERSERR = 1 << 7 30 | FLASH_SR_BSY = 1 << 16 31 | FLASH_SR_ERROR_MASK = FLASH_SR_WRPERR | FLASH_SR_PGAERR |\ 32 | FLASH_SR_PGPERR |FLASH_SR_ERSERR 33 | 34 | VOLTAGE_DEPENDEND_PARAMS = [ 35 | { 36 | 'min_voltage': 2.7, 37 | 'max_mass_erase_time': 16, 38 | 'max_erase_time': {16: .5, 32: 1.1, 64: 1.1, 128: 2, 256: 2}, 39 | 'FLASH_CR_PSIZE': FLASH_CR_PSIZE_X32, 40 | 'align': 4, 41 | }, { 42 | 'min_voltage': 2.1, 43 | 'max_mass_erase_time': 22, 44 | 'max_erase_time': {16: .6, 32: 1.4, 64: 1.4, 128: 2.6, 256: 2.6}, 45 | 'FLASH_CR_PSIZE': FLASH_CR_PSIZE_X16, 46 | 'align': 2, 47 | }, { 48 | 'min_voltage': 1.8, 49 | 'max_mass_erase_time': 32, 50 | 'max_erase_time': {16: .8, 32: 2.4, 64: 2.4, 128: 4, 256: 4}, 51 | 'FLASH_CR_PSIZE': FLASH_CR_PSIZE_X8, 52 | 'align': 1, 53 | } 54 | ] 55 | 56 | def __init__(self, driver, stlink, dbg): 57 | self._driver = driver 58 | self._stlink = stlink 59 | self._dbg = dbg 60 | self._params = self.get_voltage_dependend_params() 61 | self.unlock() 62 | 63 | def get_voltage_dependend_params(self): 64 | self._stlink.read_target_voltage() 65 | for params in Flash.VOLTAGE_DEPENDEND_PARAMS: 66 | if self._stlink.target_voltage > params['min_voltage']: 67 | return params 68 | raise lib.stlinkex.StlinkException('Supply voltage is %.2fV, but minimum for FLASH program or erase is 1.8V' % self._stlink.target_voltage) 69 | 70 | def clear_sr(self): 71 | # clear errors 72 | sr = self._stlink.get_debugreg32(Flash.FLASH_SR_REG) 73 | self._stlink.set_debugreg32(Flash.FLASH_SR_REG, sr) 74 | 75 | def unlock(self): 76 | self._driver.core_reset_halt() 77 | self.clear_sr() 78 | # do dummy read of FLASH_CR_REG 79 | self._stlink.get_debugreg32(Flash.FLASH_CR_REG) 80 | self._stlink.get_debugreg32(Flash.FLASH_CR_REG) 81 | # programing locked 82 | if self._stlink.get_debugreg32(Flash.FLASH_CR_REG) & Flash.FLASH_CR_LOCK_BIT: 83 | # unlock keys 84 | self._stlink.set_debugreg32(Flash.FLASH_KEYR_REG, 0x45670123) 85 | self._stlink.set_debugreg32(Flash.FLASH_KEYR_REG, 0xcdef89ab) 86 | # check if programing was unlocked 87 | if self._stlink.get_debugreg32(Flash.FLASH_CR_REG) & Flash.FLASH_CR_LOCK_BIT: 88 | raise lib.stlinkex.StlinkException('Error unlocking FLASH') 89 | 90 | def lock(self): 91 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_LOCK_BIT) 92 | self._driver.core_reset_halt() 93 | 94 | def erase_all(self): 95 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_MER_BIT) 96 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_MER_BIT | Flash.FLASH_CR_STRT_BIT) 97 | self.wait_busy(self._params['max_mass_erase_time'], 'Erasing FLASH') 98 | 99 | def erase_sector(self, sector, erase_size): 100 | flash_cr_value = Flash.FLASH_CR_SER_BIT 101 | flash_cr_value |= self._params['FLASH_CR_PSIZE'] | (sector << Flash.FLASH_CR_SNB_BITINDEX) 102 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, flash_cr_value) 103 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, flash_cr_value | Flash.FLASH_CR_STRT_BIT) 104 | self.wait_busy(self._params['max_erase_time'][erase_size / 1024]) 105 | 106 | def erase_sectors(self, flash_start, erase_sizes, addr, size): 107 | erase_addr = flash_start 108 | self._dbg.bargraph_start('Erasing FLASH', value_min=flash_start, value_max=flash_start + size) 109 | sector = 0 110 | while True: 111 | for erase_size in erase_sizes: 112 | if addr < erase_addr + erase_size: 113 | self._dbg.bargraph_update(value=erase_addr) 114 | self.erase_sector(sector, erase_size) 115 | erase_addr += erase_size 116 | if addr + size < erase_addr: 117 | self._dbg.bargraph_done() 118 | return 119 | sector += 1 120 | 121 | def wait_busy(self, wait_time, bargraph_msg=None): 122 | end_time = time.time() + wait_time * 1.5 123 | if bargraph_msg: 124 | self._dbg.bargraph_start(bargraph_msg, value_min=time.time(), value_max=time.time() + wait_time) 125 | while time.time() < end_time: 126 | if bargraph_msg: 127 | self._dbg.bargraph_update(value=time.time()) 128 | status = self._stlink.get_debugreg32(Flash.FLASH_SR_REG) 129 | if not status & Flash.FLASH_SR_BSY: 130 | self.end_of_operation(status) 131 | if bargraph_msg: 132 | self._dbg.bargraph_done() 133 | return 134 | time.sleep(wait_time / 20) 135 | raise lib.stlinkex.StlinkException('Operation timeout') 136 | 137 | def wait_for_breakpoint(self, wait_time): 138 | end_time = time.time() + wait_time 139 | while time.time() < end_time and not self._stlink.get_debugreg32(lib.stm32.Stm32.DHCSR_REG) & lib.stm32.Stm32.DHCSR_STATUS_HALT_BIT: 140 | time.sleep(wait_time / 20) 141 | self.end_of_operation(self._stlink.get_debugreg32(Flash.FLASH_SR_REG)) 142 | 143 | def end_of_operation(self, status): 144 | if status: 145 | raise lib.stlinkex.StlinkException('Error writing FLASH with status (FLASH_SR) %08x' % status) 146 | 147 | 148 | # support all STM32F MCUs with sector access access to FLASH 149 | # (STM32F2xx, STM32F4xx) 150 | class Stm32FS(lib.stm32.Stm32): 151 | def flash_erase_all(self, flash_size): 152 | self._dbg.debug('Stm32FS.flash_erase_all()') 153 | flash = Flash(self, self._stlink, self._dbg) 154 | flash.erase_all() 155 | flash.lock() 156 | 157 | def flash_write(self, addr, data, erase=False, erase_sizes=None): 158 | self._dbg.debug('Stm32FS.flash_write(%s, [data:%dBytes], erase=%s, erase_sizes=%s)' % (('0x%08x' % addr) if addr is not None else 'None', len(data), erase, erase_sizes)) 159 | if addr is None: 160 | addr = self.FLASH_START 161 | if addr < self.FLASH_START and addr >= Flash.AXIM_BASE: 162 | addr = Flash.AXIM_BASE + addr - self.FLASH_START 163 | flash = Flash(self, self._stlink, self._dbg) 164 | if erase: 165 | if erase_sizes: 166 | flash.erase_sectors(self.FLASH_START, erase_sizes, addr, len(data)) 167 | else: 168 | flash.erase_all() 169 | status = self._stlink.get_debugreg32(Flash.FLASH_SR_REG) 170 | if status & Flash.FLASH_SR_ERROR_MASK: 171 | # Try to clear errors 172 | self._stlink.set_debugreg32(Flash.FLASH_SR_REG, Flash.FLASH_SR_ERROR_MASK) 173 | status = self._stlink.get_debugreg32(Flash.FLASH_SR_REG) 174 | if status & Flash.FLASH_SR_ERROR_MASK: 175 | raise lib.stlinkex.StlinkException( 176 | 'FLASH state error : %08x\n' % status) 177 | params = Flash.get_voltage_dependend_params(self) 178 | print('Align %d' % params['align']) 179 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_PG_BIT | params['FLASH_CR_PSIZE']) 180 | self._dbg.bargraph_start('Writing FLASH', value_min=addr, value_max=addr + len(data)) 181 | # align data 182 | if len(data) % params['align']: 183 | data.extend([0xff] * (params['align'] - len(data) % params['align'])) 184 | datablock = data 185 | data_addr = addr 186 | while datablock: 187 | block = datablock[:1024] 188 | datablock = datablock[1024:] 189 | if min(block) != 0xff: 190 | if params['align'] == 4: 191 | self._stlink.set_mem32(data_addr, block) 192 | elif params['align'] == 2: 193 | self._stlink.set_mem16(data_addr, block) 194 | else : 195 | self._stlink.set_mem8(data_addr, block) 196 | data_addr += len(block) 197 | self._dbg.bargraph_update(value=data_addr) 198 | flash.wait_busy(0.001) 199 | flash.lock() 200 | self._dbg.bargraph_done() 201 | if status & Flash.FLASH_SR_ERROR_MASK: 202 | raise lib.stlinkex.StlinkException( 203 | 'Error writing FLASH with status: %08x\n' % status) 204 | -------------------------------------------------------------------------------- /lib/stm32h7.py: -------------------------------------------------------------------------------- 1 | import time 2 | import lib.stm32 3 | import lib.stlinkex 4 | 5 | # Stm32H7 programming 6 | class Flash(): 7 | FPEC1_BASE = 0x52002000 8 | FPEC2_BASE = 0x52002100 9 | FLASH_ACR = FPEC1_BASE 10 | FLASH_OPTCR = FPEC1_BASE + 0x18 11 | FLASH_KEYR_OFFSET = 0x04 12 | FLASH_OPTKEYR_OFFSET= 0x08 13 | FLASH_CR_OFFSET = 0x0c 14 | FLASH_SR_OFFSET = 0x10 15 | FLASH_CCR1_OFFSET = 0x14 16 | 17 | FLASH_ACR_1WS = 0x11 18 | FLASH_SR_BUSY = 1 << 0 19 | FLASH_SR_WBNE = 1 << 1 20 | FLASH_SR_QW = 1 << 2 21 | FLASH_SR_CRC_BUSY = 1 << 3 22 | FLASH_SR_EOP = 1 << 16 23 | FLASH_SR_WRPERR = 1 << 17 24 | FLASH_SR_PGSERR = 1 << 18 25 | FLASH_SR_STRBERR = 1 << 19 26 | FLASH_SR_INCERR = 1 << 21 27 | FLASH_SR_OPERR = 1 << 22 28 | FLASH_SR_OPERR = 1 << 22 29 | FLASH_SR_RDPERR = 1 << 23 30 | FLASH_SR_RDSERR = 1 << 24 31 | FLASH_SR_SNECCERR = 1 << 25 32 | FLASH_SR_DBERRERR = 1 << 26 33 | FLASH_SR_ERROR_READ = FLASH_SR_RDPERR | FLASH_SR_RDSERR |\ 34 | FLASH_SR_SNECCERR |FLASH_SR_DBERRERR 35 | FLASH_SR_ERROR_MASK = FLASH_SR_WRPERR | FLASH_SR_PGSERR |\ 36 | FLASH_SR_STRBERR | FLASH_SR_INCERR |\ 37 | FLASH_SR_OPERR | FLASH_SR_ERROR_READ 38 | FLASH_CR_REGS = [FPEC1_BASE + FLASH_CR_OFFSET, 39 | FPEC2_BASE + FLASH_CR_OFFSET] 40 | FLASH_SR_REGS = [FPEC1_BASE + FLASH_SR_OFFSET, 41 | FPEC2_BASE + FLASH_SR_OFFSET] 42 | FLASH_CCR1_REGS = [FPEC1_BASE + FLASH_CCR1_OFFSET, 43 | FPEC2_BASE + FLASH_CCR1_OFFSET] 44 | FLASH_KEYR_REGS = [FPEC1_BASE + FLASH_KEYR_OFFSET, 45 | FPEC2_BASE + FLASH_KEYR_OFFSET] 46 | 47 | FLASH_CR_LOCK = 1 << 0 48 | FLASH_CR_PG = 1 << 1 49 | FLASH_CR_SER = 1 << 2 50 | FLASH_CR_BER = 1 << 3 51 | FLASH_CR_PSIZE8 = 0 << 4 52 | FLASH_CR_PSIZE16 = 1 << 4 53 | FLASH_CR_PSIZE32 = 2 << 4 54 | FLASH_CR_PSIZE64 = 3 << 4 55 | FLASH_CR_FW = 1 << 6 56 | FLASH_CR_START = 1 << 7 57 | FLASH_CR_SNB_BITINDEX = 8 58 | FLASH_CR_CRC_EN = 1 << 15 59 | FLASH_CR_EOP = 1 << 16 60 | 61 | FLASH_OPTCR_MER = 1 << 4 62 | 63 | def __init__(self, driver, stlink, dbg): 64 | self._driver = driver 65 | self._stlink = stlink 66 | self._dbg = dbg 67 | self._sector_size = 128 * 1024 68 | self._flash_size = self._stlink.get_debugreg32(0x1ff1e880) & 0xffff 69 | self._flash_size *= 1024 70 | self._driver.core_reset_halt() 71 | # When running from HSI64, 1 WS is good for all VOS 72 | self._stlink.set_debugreg32(Flash.FLASH_ACR, Flash.FLASH_ACR_1WS) 73 | self.unlock(0) 74 | self.unlock(1) 75 | 76 | def clear_sr(self, bank): 77 | # clear errors 78 | sr = self._stlink.get_debugreg32(Flash.FLASH_SR_REGS[bank]) 79 | self._stlink.set_debugreg32(Flash.FLASH_CCR1_REGS[bank], sr) 80 | 81 | def unlock(self, bank): 82 | self._dbg.debug('unlock bank %d start' % bank) 83 | self.clear_sr(bank) 84 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[bank], 85 | Flash.FLASH_CR_LOCK) 86 | # Lock first. Unlock a previous unlocks register will fail until reset! 87 | cr = self._stlink.get_debugreg32(Flash.FLASH_CR_REGS[bank]) 88 | if cr & Flash.FLASH_CR_LOCK: 89 | # unlock keys 90 | self._stlink.set_debugreg32(Flash.FLASH_KEYR_REGS[bank],0x45670123) 91 | self._stlink.set_debugreg32(Flash.FLASH_KEYR_REGS[bank], 0xcdef89ab) 92 | cr = self._stlink.get_debugreg32(Flash.FLASH_CR_REGS[bank]) 93 | else : 94 | raise lib.stlinkex.StlinkException( 95 | 'Unexpected unlock behaviour bank %d! FLASH_CR 0x%08x' 96 | % (bank, cr)) 97 | # check if programing was unlocked 98 | if cr & Flash.FLASH_CR_LOCK: 99 | raise lib.stlinkex.StlinkException( 100 | 'Error unlocking bank %d, FLASH_CR: 0x%08x. Reset!' 101 | % (bank, cr)) 102 | 103 | def lock(self, bank): 104 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[bank], 105 | Flash.FLASH_CR_LOCK) 106 | cr = self._stlink.get_debugreg32(Flash.FLASH_CR_REGS[bank]) 107 | if not cr &Flash.FLASH_CR_LOCK: 108 | self._dbg.info('Bank %d lock faildL cr %08x' % (bank, cr)) 109 | self._driver.core_reset_halt() 110 | 111 | def erase_all(self): 112 | self._dbg.debug('erase_all') 113 | self.clear_sr(0) 114 | self.clear_sr(1) 115 | cr = Flash.FLASH_CR_PSIZE32 116 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[0], cr) 117 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[1], cr) 118 | self._stlink.set_debugreg32(Flash.FLASH_OPTCR, Flash.FLASH_OPTCR_MER ) 119 | self.wait_busy(20, bargraph_msg='Erasing FLASH', bank=2, check_qw=True) 120 | 121 | def erase_bank(self, bank): 122 | self._dbg.debug('erase_bank %d' % bank) 123 | self.clear_sr(bank) 124 | cr = Flash.FLASH_CR_PSIZE32 | Flash.FLASH_CR_BER 125 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[bank], cr) 126 | cr |= Flash.FLASH_CR_START 127 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[bank], cr) 128 | self.wait_busy(12, bank=bank, check_qw=True) 129 | 130 | def erase_sector(self, sector): 131 | cr = Flash.FLASH_CR_SER | Flash.FLASH_CR_PSIZE32 132 | if (sector < 8) : 133 | self.clear_sr(0) 134 | cr |= (sector << Flash.FLASH_CR_SNB_BITINDEX) 135 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[0], cr) 136 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[0], 137 | cr | Flash.FLASH_CR_START) 138 | self.wait_busy(4, bank=0, check_qw=True) 139 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[0], 0) 140 | else: 141 | self.clear_sr(1) 142 | cr |= ((sector - 8) * Flash.FLASH_CR_SNB_BITINDEX) 143 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[1], cr) 144 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[1], 145 | cr | Flash.FLASH_CR_START) 146 | self.wait_busy(4, bank=1, check_qw=True) 147 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[1], 0) 148 | 149 | def erase_sectors(self, addr, size): 150 | if size == 0: 151 | return 152 | self._dbg.debug( 153 | 'erase_sectors page size %d from addr %08x for %d byte' % 154 | (self._sector_size, addr, size)) 155 | self._dbg.bargraph_start('Erasing FLASH', value_min=addr, 156 | value_max=addr + size) 157 | sector = addr - lib.stm32.Stm32.FLASH_START 158 | end_sector = addr + size - lib.stm32.Stm32.FLASH_START 159 | sector //= self._sector_size 160 | end_sector //= self._sector_size 161 | if sector == 0 and end_sector >= 8: 162 | self.erase_bank(0) 163 | addr += 8* self._sector_size 164 | self._dbg.bargraph_update(value=addr) 165 | sector = 8 166 | while sector <= end_sector: 167 | if sector == 8 and end_sector >= 16: 168 | self.erase_bank(1) 169 | addr += 8* self._sector_size 170 | self._dbg.bargraph_update(value=addr) 171 | break 172 | self.erase_sector(sector) 173 | sector += 1 174 | addr += self._sector_size 175 | self._dbg.bargraph_update(value=addr) 176 | self._dbg.bargraph_done() 177 | 178 | def wait_busy(self, wait_time, bargraph_msg=None, bank=0, check_qw=False): 179 | end_time = time.time() + wait_time * 1.5 180 | if bargraph_msg: 181 | self._dbg.bargraph_start(bargraph_msg, value_min=time.time(), value_max=time.time() + wait_time) 182 | while time.time() < end_time: 183 | if bargraph_msg: 184 | self._dbg.bargraph_update(value=time.time()) 185 | status = 0 186 | if bank == 0 or bank == 2: 187 | status |= self._stlink.get_debugreg32(Flash.FLASH_SR_REGS[0]) 188 | if bank & 1: 189 | status |= self._stlink.get_debugreg32(Flash.FLASH_SR_REGS[1]) 190 | if not status & (Flash.FLASH_SR_BUSY | (check_qw & Flash.FLASH_SR_QW)) : 191 | self.end_of_operation(status) 192 | if bargraph_msg: 193 | self._dbg.bargraph_done() 194 | return 195 | time.sleep(wait_time / 20) 196 | raise lib.stlinkex.StlinkException('Operation timeout') 197 | 198 | def end_of_operation(self, status): 199 | if status & Flash.FLASH_SR_ERROR_MASK: 200 | raise lib.stlinkex.StlinkException('Error writing FLASH with status (FLASH_SR) %08x' % status) 201 | 202 | class Stm32H7(lib.stm32.Stm32): 203 | def flash_erase_all(self, flash_size): 204 | self._dbg.debug('Stm32H7.flash_erase_all()') 205 | flash = Flash(self, self._stlink, self._dbg) 206 | flash.erase_all() 207 | flash.lock(0) 208 | flash.lock(1) 209 | 210 | def flash_write(self, addr, data, erase=False, erase_sizes=None): 211 | if addr is None: 212 | addr = self.FLASH_START 213 | self._dbg.debug( 214 | 'Stm32h7.flash_write(%s, [data:%dBytes], erase=%s)' % 215 | (addr, len(data), erase)) 216 | if addr % 8: 217 | raise lib.stlinkex.StlinkException( 218 | 'Start address is not aligned to word') 219 | # pad data 220 | if len(data) % 32: 221 | data.extend([0xff] * (32 - len(data) % 32)) 222 | flash = Flash(self, self._stlink, self._dbg) 223 | if erase: 224 | full_chip = (addr == self.FLASH_START) and \ 225 | (len(data) == flash._flash_size) 226 | if not erase_sizes or full_chip: 227 | flash.erase_all() 228 | else: 229 | flash.erase_sectors(addr, len(data)) 230 | self._dbg.bargraph_start('Writing FLASH', value_min=addr, 231 | value_max=addr + len(data)) 232 | cr = Flash.FLASH_CR_PG | Flash.FLASH_CR_PSIZE32 233 | if addr < 0x08100000: 234 | flash.unlock(0) 235 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[0], cr) 236 | cr = self._stlink.get_debugreg32(Flash.FLASH_CR_REGS[0]) 237 | if not cr & Flash.FLASH_CR_PG: 238 | raise lib.stlinkex.StlinkException( 239 | 'Bank 0 FLASH_CR not ready for programming: %08x\n' % cr) 240 | if addr + len(data) >= 0x08100000: 241 | flash.unlock(1) 242 | self._stlink.set_debugreg32(Flash.FLASH_CR_REGS[1], cr) 243 | cr = self._stlink.get_debugreg32(Flash.FLASH_CR_REGS[1]) 244 | if not cr & Flash.FLASH_CR_PG: 245 | raise lib.stlinkex.StlinkException( 246 | 'Bank 1 FLASH_CR not ready for programming: %08x\n' % cr) 247 | datablock = data 248 | data_addr = addr 249 | while datablock: 250 | block = datablock[:1024] 251 | datablock = datablock[1024:] 252 | if min(block) != 0xff: 253 | self._stlink.set_mem32(data_addr, block) 254 | data_addr += len(block) 255 | self._dbg.bargraph_update(value=data_addr) 256 | flash.wait_busy(0.001) 257 | flash.lock(0) 258 | flash.lock(1) 259 | self._dbg.bargraph_done() 260 | status = self._stlink.get_debugreg32(Flash.FLASH_SR_REGS[0]) 261 | if status & Flash.FLASH_SR_ERROR_MASK: 262 | raise lib.stlinkex.StlinkException( 263 | 'Bank 0, Error writing FLASH with status: %08x\n' % status) 264 | status = self._stlink.get_debugreg32(Flash.FLASH_SR_REGS[1]) 265 | if status & Flash.FLASH_SR_ERROR_MASK: 266 | raise lib.stlinkex.StlinkException( 267 | 'Bank 1, Error writing FLASH with status: %08x\n' % status) 268 | -------------------------------------------------------------------------------- /lib/stm32l0.py: -------------------------------------------------------------------------------- 1 | import time 2 | import lib.stm32 3 | import lib.stlinkex 4 | 5 | # Stm32 L0 and L1 programming 6 | class Flash(): 7 | PECR_OFFSET = 4 8 | PEKEYR_OFFSET = 0x0c 9 | PRGKEYR_OFFSET = 0x10 10 | OPTKEYR_OFFSET = 0x14 11 | SR_OFFSET = 0x18 12 | STM32L0_NVM_PHY = 0x40022000 13 | STM32L1_NVM_PHY = 0x40023c00 14 | STM32_NVM_PEKEY1 = 0x89abcdef 15 | STM32_NVM_PEKEY2 = 0x02030405 16 | STM32_NVM_PRGKEY1 = 0x8c9daebf 17 | STM32_NVM_PRGKEY2 = 0x13141516 18 | 19 | PECR_PELOCK = 1 << 0 20 | PECR_PRGLOCK = 1 << 1 21 | PECR_PRG = 1 << 3 22 | PECR_ERASE = 1 << 9 23 | PECR_FPRG = 1 << 10 24 | 25 | SR_BSY = 1 << 0 26 | SR_EOP = 1 << 1 27 | SR_WRPERR = 1 << 8 28 | SR_PGAERR = 1 << 9 29 | SR_SIZERR = 1 << 10 30 | 31 | SR_ERROR_MASK = SR_WRPERR | SR_PGAERR | SR_SIZERR 32 | 33 | def __init__(self, driver, stlink, dbg): 34 | self._driver = driver 35 | self._stlink = stlink 36 | self._dbg = dbg 37 | self._page_size = 2048 38 | #use core id to find out if L0 or L1 39 | if stlink._coreid == 0xbc11477: 40 | self._nvm = Flash.STM32L0_NVM_PHY 41 | self._page_size = 128 42 | else: 43 | self._nvm = Flash.STM32L1_NVM_PHY 44 | self._page_size = 256 45 | self.unlock() 46 | 47 | def clear_sr(self): 48 | # clear errors 49 | sr = self._stlink.get_debugreg32(self._nvm + Flash.SR_OFFSET) 50 | self._stlink.set_debugreg32(self._nvm + Flash.SR_OFFSET, sr) 51 | 52 | def unlock(self): 53 | self._dbg.debug('unlock') 54 | self._driver.core_reset_halt() 55 | self.wait_busy(0.01) 56 | self.clear_sr() 57 | # Lock first. Double unlock results in error! 58 | self._stlink.set_debugreg32(self._nvm + Flash.PECR_OFFSET, 59 | Flash.PECR_PELOCK) 60 | pecr = self._stlink.get_debugreg32(self._nvm + Flash.PECR_OFFSET) 61 | if pecr & Flash.PECR_PELOCK: 62 | # unlock keys 63 | self._stlink.set_debugreg32(self._nvm + Flash.PEKEYR_OFFSET, 64 | Flash.STM32_NVM_PEKEY1) 65 | self._stlink.set_debugreg32(self._nvm + Flash.PEKEYR_OFFSET, 66 | Flash.STM32_NVM_PEKEY2) 67 | pecr = self._stlink.get_debugreg32(self._nvm + Flash.PECR_OFFSET) 68 | else : 69 | raise lib.stlinkex.StlinkException( 70 | 'Unexpected unlock behaviour! FLASH_CR 0x%08x' % pecr) 71 | # check if programing was unlocked 72 | if pecr & Flash.PECR_PELOCK: 73 | raise lib.stlinkex.StlinkException( 74 | 'Error unlocking FLASH_CR: 0x%08x. Reset!' % prcr) 75 | 76 | def lock(self): 77 | self._stlink.set_debugreg32(self._nvm + Flash.PECR_OFFSET, 78 | Flash.PECR_PELOCK) 79 | self._driver.core_reset_halt() 80 | 81 | def prg_unlock(self): 82 | pecr = self._stlink.get_debugreg32(self._nvm + Flash.PECR_OFFSET) 83 | if not pecr & Flash.PECR_PRGLOCK: 84 | return 85 | if pecr & Flash.PECR_PELOCK: 86 | raise lib.stlinkex.StlinkException('PELOCK still set: %08x' % pecr) 87 | # unlock keys 88 | self._stlink.set_debugreg32(self._nvm + Flash.PRGKEYR_OFFSET, 89 | Flash.STM32_NVM_PRGKEY1) 90 | self._stlink.set_debugreg32(self._nvm + Flash.PRGKEYR_OFFSET, 91 | Flash.STM32_NVM_PRGKEY2) 92 | pecr = self._stlink.get_debugreg32(self._nvm + Flash.PECR_OFFSET) 93 | if pecr & Flash.PECR_PRGLOCK: 94 | raise lib.stlinkex.StlinkException('PRGLOCK still set: %08x' % pecr) 95 | 96 | def erase_pages(self, addr, size): 97 | self._dbg.verbose('erase_pages from addr 0x%08x for %d byte' % 98 | (addr, size)) 99 | erase_addr = addr & ~(self._page_size - 1) 100 | last_addr = (addr + size + self._page_size - 1) &\ 101 | ~(self._page_size - 1) 102 | self._dbg.bargraph_start('Erasing FLASH', value_min=erase_addr, 103 | value_max=last_addr) 104 | self.prg_unlock() 105 | pecr = Flash.PECR_PRG | Flash.PECR_ERASE 106 | self._stlink.set_debugreg32(self._nvm + Flash.PECR_OFFSET, pecr) 107 | while erase_addr < last_addr: 108 | self._stlink.set_debugreg32(erase_addr, 0) 109 | self.wait_busy(0.01) 110 | erase_addr += self._page_size 111 | self._dbg.bargraph_update(value=erase_addr) 112 | self._dbg.bargraph_done() 113 | self._stlink.set_debugreg32(self._nvm + Flash.PECR_OFFSET, 0) 114 | 115 | def wait_busy(self, wait_time, bargraph_msg=None, check_eop=False): 116 | end_time = time.time() + wait_time * 1.5 117 | if bargraph_msg: 118 | self._dbg.bargraph_start(bargraph_msg, value_min=time.time(), 119 | value_max=time.time() + wait_time) 120 | while time.time() < end_time: 121 | if bargraph_msg: 122 | self._dbg.bargraph_update(value=time.time()) 123 | status = self._stlink.get_debugreg32(self._nvm + Flash.SR_OFFSET) 124 | if not status & (Flash.SR_BSY | (check_eop & Flash.SR_EOP)) : 125 | self.end_of_operation(status) 126 | if bargraph_msg: 127 | self._dbg.bargraph_done() 128 | if check_eop: 129 | self._stlink.set_debugreg32(self._nvm + Flash.SR_OFFSET, 130 | Flash.SR_EOP) 131 | return 132 | time.sleep(wait_time / 20) 133 | raise lib.stlinkex.StlinkException('Operation timeout') 134 | 135 | def end_of_operation(self, status): 136 | if status & Flash.SR_ERROR_MASK: 137 | raise lib.stlinkex.StlinkException( 138 | 'Error writing FLASH with status (FLASH_SR) %08x' % status) 139 | 140 | 141 | class Stm32L0(lib.stm32.Stm32): 142 | def flash_erase_all(self, flash_size): 143 | # Mass erase is only possible by setting and removing flash 144 | # write protection. This will also erase EEPROM! 145 | # Use page erase instead 146 | 147 | self._dbg.debug('Stm32L0.flash_erase_all') 148 | flash = Flash(self, self._stlink, self._dbg) 149 | flash.erase_pages(lib.stm32.Stm32.FLASH_START, flash_size); 150 | flash.lock() 151 | 152 | def flash_write(self, addr, data, erase=False, erase_sizes=None): 153 | if addr is None: 154 | addr = self.FLASH_START 155 | self._dbg.debug( 156 | 'Stm32l4.flash_write ' 157 | '(%s, [data:%dBytes], erase=%s, erase_sizes=%s)' 158 | % (addr, len(data), erase, erase_sizes)) 159 | if addr % 4: 160 | raise lib.stlinkex.StlinkException 161 | ('Start address is not aligned to word') 162 | flash = Flash(self, self._stlink, self._dbg) 163 | if erase: 164 | if erase_sizes: 165 | flash.erase_pages(addr, len(data)) 166 | else: 167 | flash.erase_all() 168 | self._dbg.bargraph_start('Writing FLASH', value_min=addr, 169 | value_max=addr + len(data)) 170 | flash.unlock() 171 | flash.prg_unlock() 172 | datablock = data 173 | data_addr = addr 174 | block = datablock 175 | while len(datablock): 176 | size = 0 177 | if data_addr & ((flash._page_size >> 1) -1): 178 | # not half page aligned 179 | size = data_addr & ((flash._page_size >> 1) -1) 180 | size = (flash._page_size >> 1) - size 181 | if len(datablock) < (flash._page_size >> 1): 182 | # remainder not full half page 183 | size = len(datablock) 184 | while size: 185 | block = datablock[:4] 186 | datablock = datablock[4:] 187 | if max(block) != 0: 188 | self._stlink.set_mem32(data_addr, block) 189 | data_addr += 4 190 | size -= 4 191 | self._dbg.bargraph_update(value=data_addr) 192 | flash.wait_busy(0.005, check_eop=True) 193 | pecr = Flash.PECR_FPRG | Flash.PECR_PRG 194 | self._stlink.set_debugreg32(flash._nvm + Flash.PECR_OFFSET, pecr) 195 | while len(datablock) >= (flash._page_size >> 1): 196 | block = datablock[:(flash._page_size >> 1)] 197 | datablock = datablock[(flash._page_size >> 1):] 198 | if max(block) != 0: 199 | self._stlink.set_mem32(data_addr, block) 200 | data_addr += len(block) 201 | self._dbg.bargraph_update(value=data_addr) 202 | flash.wait_busy(0.005, check_eop=True) 203 | self._stlink.set_debugreg32(flash._nvm + Flash.PECR_OFFSET, 0) 204 | flash.lock() 205 | self._dbg.bargraph_done() 206 | -------------------------------------------------------------------------------- /lib/stm32l4.py: -------------------------------------------------------------------------------- 1 | import time 2 | import lib.stm32 3 | import lib.stlinkex 4 | 5 | # Stm32 L4 and G0 programming 6 | class Flash(): 7 | FLASH_REG_BASE = 0x40022000 8 | FLASH_KEYR_REG = FLASH_REG_BASE + 0x08 9 | FLASH_SR_REG = FLASH_REG_BASE + 0x10 10 | FLASH_CR_REG = FLASH_REG_BASE + 0x14 11 | 12 | FLASH_CR_PG_BIT = 1 << 0 13 | FLASH_CR_PER_BIT = 1 << 1 14 | FLASH_CR_MER1_BIT = 1 << 2 15 | FLASH_CR_PNB_BITINDEX = 3 16 | FLASH_CR_BKER_BIT = 1 << 11 17 | FLASH_CR_MER2_BIT = 1 << 15 18 | FLASH_CR_STRT_BIT = 1 << 16 19 | FLASH_CR_FSTPG_BIT = 1 << 18 20 | FLASH_CR_OPTLOCK_BIT = 1 << 30 21 | FLASH_CR_LOCK_BIT = 1 << 31 22 | 23 | FLASH_SR_EOP_BIT = 1 << 0 24 | FLASH_SR_OPERR_BIT = 1 << 1 25 | FLASH_SR_PROGERR_BIT = 1 << 3 26 | FLASH_SR_WPRERR_BIT = 1 << 4 27 | FLASH_SR_PGAERR_BIT = 1 << 5 28 | FLASH_SR_SIZERR_BIT = 1 << 6 29 | FLASH_SR_PGSERR_BIT = 1 << 7 30 | FLASH_SR_FASTERR_BIT = 1 << 8 31 | FLASH_SR_MISSERR_BIT = 1 << 9 32 | FLASH_SR_BUSY_BIT = 1 << 16 33 | FLASH_SR_CFGBSY_BIT = 1 << 18 34 | 35 | FLASH_SR_ERROR_MASK = ( 36 | FLASH_SR_PROGERR_BIT | FLASH_SR_WPRERR_BIT | FLASH_SR_PGAERR_BIT | 37 | FLASH_SR_SIZERR_BIT | FLASH_SR_PGSERR_BIT | FLASH_SR_FASTERR_BIT | 38 | FLASH_SR_MISSERR_BIT) 39 | 40 | FLASH_OPTR_REG = FLASH_REG_BASE + 0x20 41 | FLASH_OPTR_DBANK_BIT = 1 << 22 42 | 43 | def __init__(self, driver, stlink, dbg): 44 | self._driver = driver 45 | self._stlink = stlink 46 | self._dbg = dbg 47 | self._page_size = 2048 48 | dev_id = self._stlink.get_debugreg32(0xE0042000) & 0xfff 49 | if dev_id == 0x470: 50 | optr = self._stlink.get_debugreg32(Flash.FLASH_OPTR_REG) 51 | if not optr & Flash.FLASH_OPTR_DBANK_BIT: 52 | self._dbg.info('STM32L4[R|S] in single bank configuration') 53 | self._page_size *= 4 54 | self._single_bank = True 55 | else: 56 | self._dbg.info('STM32L4[R|S] in dual bank configuration') 57 | self._page_size *= 2 58 | self.unlock() 59 | 60 | def clear_sr(self): 61 | # clear errors 62 | sr = self._stlink.get_debugreg32(Flash.FLASH_SR_REG) 63 | self._stlink.set_debugreg32(Flash.FLASH_SR_REG, sr) 64 | 65 | def unlock(self): 66 | self._dbg.debug('unlock start') 67 | self._driver.core_reset_halt() 68 | self.clear_sr() 69 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_LOCK_BIT) 70 | # Lock first. Double unlock results in error! 71 | cr = self._stlink.get_debugreg32(Flash.FLASH_CR_REG) 72 | if cr & Flash.FLASH_CR_LOCK_BIT: 73 | # unlock keys 74 | self._stlink.set_debugreg32(Flash.FLASH_KEYR_REG, 0x45670123) 75 | self._stlink.set_debugreg32(Flash.FLASH_KEYR_REG, 0xcdef89ab) 76 | cr = self._stlink.get_debugreg32(Flash.FLASH_CR_REG) 77 | else : 78 | raise lib.stlinkex.StlinkException( 79 | 'Unexpected unlock behaviour! FLASH_CR 0x%08x' % cr) 80 | # check if programing was unlocked 81 | if cr & Flash.FLASH_CR_LOCK_BIT: 82 | raise lib.stlinkex.StlinkException( 83 | 'Error unlocking FLASH_CR: 0x%08x. Reset!' % cr) 84 | if not cr & Flash.FLASH_CR_OPTLOCK_BIT: 85 | raise lib.stlinkex.StlinkException( 86 | 'Error unlocking FLASH_CR: 0x%08x. Reset!' % cr) 87 | 88 | def lock(self): 89 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_LOCK_BIT) 90 | cr = self._stlink.get_debugreg32(Flash.FLASH_CR_REG) 91 | self._dbg.debug('lock cr %08x' % cr) 92 | 93 | def erase_all(self): 94 | self._dbg.debug('erase_all') 95 | cr = Flash.FLASH_CR_MER1_BIT | Flash.FLASH_CR_MER2_BIT; 96 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, cr) 97 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, cr| 98 | Flash.FLASH_CR_STRT_BIT) 99 | # max 22.1 sec on STM32L4R (two banks) 100 | self.wait_busy(25, 'Erasing FLASH') 101 | 102 | def erase_page(self, page): 103 | self._dbg.debug('erase_page %d' % page) 104 | self.clear_sr() 105 | flash_cr_value = Flash.FLASH_CR_PER_BIT 106 | flash_cr_value |= (page << Flash.FLASH_CR_PNB_BITINDEX) 107 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, flash_cr_value) 108 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, flash_cr_value | 109 | Flash.FLASH_CR_STRT_BIT) 110 | self.wait_busy(0.05) 111 | 112 | def erase_bank(self, bank): 113 | self._dbg.debug('erase_bank %d' % bank) 114 | self.clear_sr() 115 | cr = Flash.FLASH_CR_MER1_BIT; 116 | if bank == 1: 117 | cr = Flash.FLASH_CR_MER2_BIT 118 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, cr) 119 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, cr| 120 | Flash.FLASH_CR_STRT_BIT) 121 | self.wait_busy(0.05) 122 | 123 | def erase_pages(self, addr, size): 124 | self._dbg.verbose('erase_pages from addr %08x for %d byte' % 125 | (addr, size)) 126 | page = (addr - lib.stm32.Stm32.FLASH_START ) // self._page_size 127 | last_page = (addr - lib.stm32.Stm32.FLASH_START + size + self._page_size - 1) // self._page_size 128 | self._dbg.verbose('erase_pages %d to %d' % (page, last_page)) 129 | self._dbg.bargraph_start('Erasing FLASH', value_min=page, 130 | value_max=last_page) 131 | if page == 0 and last_page >= 256: 132 | self.erase_bank(0); 133 | page = 256 134 | self._dbg.bargraph_update(value=page) 135 | while page < last_page: 136 | if page == 256 and last_page >= 512: 137 | self.erase_bank(1); 138 | page = 512 139 | self._dbg.bargraph_update(value=page) 140 | break 141 | self.erase_page(page) 142 | page += 1 143 | self._dbg.bargraph_update(value=page) 144 | self._dbg.bargraph_done() 145 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, 0) 146 | 147 | def wait_busy(self, wait_time, bargraph_msg=None, check_eop=False): 148 | end_time = time.time() + wait_time * 1.5 149 | if bargraph_msg: 150 | self._dbg.bargraph_start(bargraph_msg, value_min=time.time(), 151 | value_max=time.time() + wait_time) 152 | while time.time() < end_time: 153 | if bargraph_msg: 154 | self._dbg.bargraph_update(value=time.time()) 155 | status = self._stlink.get_debugreg32(Flash.FLASH_SR_REG) 156 | if not status & (Flash.FLASH_SR_BUSY_BIT | 157 | Flash.FLASH_SR_CFGBSY_BIT | 158 | (check_eop & Flash.FLASH_SR_EOP_BIT)) : 159 | self.end_of_operation(status) 160 | if bargraph_msg: 161 | self._dbg.bargraph_done() 162 | return 163 | time.sleep(wait_time / 20) 164 | raise lib.stlinkex.StlinkException('Operation timeout') 165 | 166 | def end_of_operation(self, status): 167 | if status & Flash.FLASH_SR_ERROR_MASK: 168 | raise lib.stlinkex.StlinkException( 169 | 'Error writing FLASH with status (FLASH_SR) %08x' % status) 170 | 171 | 172 | # support all STM32L4 and G0 MCUs with page size access to FLASH 173 | class Stm32L4(lib.stm32.Stm32): 174 | def flash_erase_all(self, flash_size): 175 | self._dbg.debug('Stm32L4.flash_erase_all()') 176 | flash = Flash(self, self._stlink, self._dbg) 177 | flash.erase_all() 178 | flash.lock() 179 | 180 | def flash_write(self, addr, data, erase=False, erase_sizes=None): 181 | if addr is None: 182 | addr = self.FLASH_START 183 | self._dbg.debug( 184 | 'Stm32l4.flash_write(%s, [data:%dBytes], erase=%s, erase_sizes=%s)' 185 | % (addr, len(data), erase, erase_sizes)) 186 | if addr % 8: 187 | raise lib.stlinkex.StlinkException('Start address is not aligned to word') 188 | # pad data 189 | if len(data) % 8: 190 | data.extend([0xff] * (8 - len(data) % 8)) 191 | flash = Flash(self, self._stlink, self._dbg) 192 | flash.unlock() 193 | if erase: 194 | if erase_sizes: 195 | flash.erase_pages(addr, len(data)) 196 | else: 197 | flash.erase_all() 198 | flash.unlock() 199 | self._dbg.bargraph_start('Writing FLASH', value_min=addr, value_max=addr + len(data)) 200 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, 0) 201 | self._stlink.set_debugreg32(Flash.FLASH_CR_REG, Flash.FLASH_CR_PG_BIT) 202 | cr = self._stlink.get_debugreg32(Flash.FLASH_CR_REG) 203 | if not cr & Flash.FLASH_CR_PG_BIT: 204 | raise lib.stlinkex.StlinkException('Flash_Cr not ready for programming: %08x\n' % cr) 205 | while data: 206 | block = data[:256] 207 | data = data[256:] 208 | self._dbg.debug('Stm32l4.flash_write len %s addr %x' % (len(block), addr)) 209 | if min(block) != 0xff: 210 | self._stlink.set_mem32(addr, block) 211 | addr += len(block) 212 | self._dbg.bargraph_update(value=addr) 213 | flash.wait_busy(0.001) 214 | self._dbg.bargraph_done() 215 | flash.lock() 216 | -------------------------------------------------------------------------------- /list_new_stm32.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import json 3 | import lib.stm32devices 4 | 5 | 6 | def fix_cpu_type(cpu_type): 7 | cpu_type = cpu_type.upper() 8 | # now support only STM32 9 | if cpu_type.startswith('STM32'): 10 | # change character on 10 position to 'x' where is package size code 11 | if len(cpu_type) > 9: 12 | cpu_type = list(cpu_type) 13 | cpu_type[9] = 'x' 14 | cpu_type = ''.join(cpu_type) 15 | return cpu_type 16 | raise Exception('"%s" is not STM32 family' % cpu_type) 17 | 18 | print("Downloading list of all STM32 MCUs from ST.com...") 19 | # req = urllib.request.urlopen('http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus.product-grid.html/SC1169.json') 20 | 21 | URLS = [ 22 | 'http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus.product-grid.html/SC2154.json', 23 | 'http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus.product-grid.html/SC2155.json', 24 | 'http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus.product-grid.html/SC2157.json', 25 | ] 26 | 27 | def download_data(url): 28 | req = urllib.request.urlopen(url) 29 | res = req.read() 30 | print("downloaded: %d KBytes" % (len(res) / 1024)) 31 | return json.loads(res.decode('utf-8')) 32 | 33 | # columns has important keys: 34 | # - id 35 | # - name 36 | # raw_json['columns'] 37 | REQUESTED_COLUMNS = { 38 | 'Part Number': 'type', 39 | 'Core': 'core', 40 | 'Operating Frequency': 'freq', 41 | 'FLASH Size': 'flash_size', 42 | 'Data E2PROM': 'eeprom_size', 43 | 'RAM Size': 'sram_size', 44 | } 45 | 46 | raw_jsons = [download_data(url) for url in URLS] 47 | 48 | columns = {} 49 | for raw_json in raw_jsons: 50 | for column in raw_json['columns']: 51 | if column['name'] in REQUESTED_COLUMNS: 52 | columns[column['id']] = REQUESTED_COLUMNS[column['name']] 53 | 54 | mcus = [] 55 | for raw_json in raw_jsons: 56 | for row in raw_json['rows']: 57 | mcu = {} 58 | mcu['url'] = 'http://www.st.com' + row['productFolderUrl'] 59 | for cell in row['cells']: 60 | column_id = cell['columnId'] 61 | if column_id in columns: 62 | column_name = columns[column_id] 63 | mcu[column_name] = cell['value'] 64 | mcus.append(mcu) 65 | print("MCUs on ST.com is: %d" % len(mcus)) 66 | 67 | supported_mcus = {} 68 | for devs in lib.stm32devices.DEVICES: 69 | for dev in devs['devices']: 70 | for d in dev['devices']: 71 | supported_mcus[d['type']] = d 72 | 73 | unsupported_mcus = {} 74 | wrong_param_mcus = {} 75 | 76 | for mcu in mcus: 77 | mcu_type_fixed = fix_cpu_type(mcu['type']) 78 | mcu_type = mcu.get('type') 79 | core = mcu.get('core') 80 | freq = mcu.get('freq') 81 | if freq is None: 82 | mcu['freq'] = '' 83 | freq = '' 84 | if freq.isnumeric(): 85 | freq = int(freq) 86 | flash_size = mcu.get('flash_size') 87 | if flash_size is None: 88 | mcu['flash_size'] = '' 89 | flash_size = '' 90 | if flash_size.isnumeric(): 91 | flash_size = int(flash_size) 92 | sram_size = mcu.get('sram_size') 93 | if sram_size is None: 94 | mcu['sram_size'] = '' 95 | sram_size = '' 96 | if sram_size.isnumeric(): 97 | sram_size = int(sram_size) 98 | eeprom_size = mcu.get('eeprom_size') 99 | eeprom_size = int(eeprom_size) / 1024 if eeprom_size else 0 100 | if eeprom_size % 1 == 0: 101 | eeprom_size = int(eeprom_size) 102 | mcu['eeprom_size'] = eeprom_size 103 | if mcu_type_fixed in supported_mcus: 104 | supported_mcu = supported_mcus[mcu_type_fixed] 105 | ok = True 106 | if supported_mcu['freq'] != freq: 107 | ok = False 108 | if supported_mcu['flash_size'] != flash_size: 109 | ok = False 110 | if supported_mcu['sram_size'] != sram_size: 111 | ok = False 112 | if supported_mcu['eeprom_size'] != eeprom_size: 113 | ok = False 114 | if not ok: 115 | mcu['supported_mcu'] = supported_mcu 116 | mcu['type_fixed'] = mcu_type_fixed 117 | wrong_param_mcus[mcu_type] = mcu 118 | else: 119 | mcu['type_fixed'] = mcu_type_fixed 120 | unsupported_mcus[mcu_type] = mcu 121 | 122 | print("%-15s %-15s %6s %6s %6s %6s" % ('type', 'core', 'flash', 'sram', 'eeprom', 'freq')) 123 | if unsupported_mcus: 124 | print('---- unsupported mcus (%d) ----' % len(unsupported_mcus)) 125 | for k in sorted(unsupported_mcus.keys()): 126 | v = unsupported_mcus[k] 127 | print(v['url']) 128 | print("%-15s %-15s %6s %6s %6s %6s" % ( 129 | k, v.get('core', ''), v['flash_size'], v['sram_size'], v.get('eeprom_size'), v['freq'] 130 | )) 131 | if wrong_param_mcus: 132 | print('---- mcus with wrong params (%d) ----' % len(wrong_param_mcus)) 133 | for k in sorted(wrong_param_mcus.keys()): 134 | v = wrong_param_mcus[k] 135 | s = v['supported_mcu'] 136 | print(v['url']) 137 | print("%-15s %-15s %6s %6s %6s %6s" % ( 138 | k, v.get('core', ''), v['flash_size'], v['sram_size'], v.get('eeprom_size'), v['freq'] 139 | )) 140 | print("%-15s %-15s %6s %6s %6s %6s" % ( 141 | '(pystlink)', v.get('core', ''), s['flash_size'], s['sram_size'], s.get('eeprom_size'), s['freq'] 142 | )) 143 | -------------------------------------------------------------------------------- /pystlink: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec_file=$0 4 | 5 | if [ -L "$exec_file" ] ; then 6 | exec_file=`readlink $exec_file` 7 | fi 8 | 9 | work_dir=`dirname $exec_file` 10 | 11 | python3 $work_dir/pystlink.py $* 12 | -------------------------------------------------------------------------------- /pystlink.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import argparse 3 | import time 4 | import lib.stlinkusb 5 | import lib.stlinkv2 6 | import lib.stm32 7 | import lib.stm32fp 8 | import lib.stm32fs 9 | import lib.stm32l0 10 | import lib.stm32l4 11 | import lib.stm32h7 12 | import lib.stm32devices 13 | import lib.stlinkex 14 | import lib.dbg 15 | import lib.srec 16 | 17 | VERSION_STR = "pystlink v0.0.0 (ST-LinkV2)" 18 | 19 | DESCRIPTION_STR = VERSION_STR + """ 20 | (c)2015 by pavel.revak@gmail.com 21 | https://github.com/pavelrevak/pystlink 22 | """ 23 | 24 | ACTIONS_HELP_STR = """ 25 | list of available actions: 26 | dump:core print all core registers (halt core) 27 | dump:{reg} print core register (halt core) 28 | dump:{addr}:{size} print content of memory 29 | dump:sram[:{size}] print content of SRAM memory 30 | dump:flash[:{size}] print content of FLASH memory 31 | dump:{addr} print content of 32 bit memory register 32 | dump16:{addr} print content of 16 bit memory register 33 | dump8:{addr} print content of 8 bit memory register 34 | 35 | set:{reg}:{data} set register (halt core) 36 | set:{addr}:{data} set 32 bit memory register 37 | 38 | read:{addr}:{size}:{file} read memory with size into file 39 | read:sram[:{size}]:{file} read SRAM into file 40 | read:flash[:{size}]:{file} read FLASH into file 41 | 42 | fill:{addr}:{size}:{pattern} fill memory with a pattern 43 | fill:sram[:{size}]:{pattern} fill SRAM memory with a pattern 44 | 45 | write:{file.srec} write SREC file into memory 46 | write:{addr}:{file} write binary file into memory 47 | write:sram:{file} write binary file into SRAM memory 48 | 49 | flash:erase complete erase FLASH memory aka mass erase 50 | flash[:erase][:verify]:{file.srec} erase + flash SREC file + verify 51 | flash[:erase][:verify][:{addr}]:{file} erase + flash binary file + verify 52 | flash:check:{file.srec} verify flash against SREC file 53 | flash:check[:{addr}]:{file} verify flash {at addr} against binary file 54 | 55 | reset reset core 56 | reset:halt reset and halt core 57 | halt halt core 58 | step step core 59 | run run core 60 | 61 | sleep:{seconds} sleep (float) - insert delay between commands 62 | 63 | (numerical values can be in different formats, like: 42, 0x2a, 0o52, 0b101010) 64 | 65 | examples: 66 | pystlink.py --help 67 | pystlink.py -v --cpu STM32F051R8 68 | pystlink.py -q --cpu STM32F03 dump:flash dump:sram 69 | pystlink.py dump:0x08000000:256 70 | pystlink.py set:0x48000018:0x00000100 dump:0x48000014 71 | pystlink.py read:sram:256:aaa.bin read:flash:bbb.bin 72 | pystlink.py -r reset:halt set:pc:0x20000010 dump:pc core:step dump:all 73 | pystlink.py flash:erase:verify:app.bin 74 | pystlink.py flash:erase flash:verify:0x08010000:boot.bin 75 | pystlink.py -n 2 76 | pystlink.py -s 77 | """ 78 | 79 | 80 | class PyStlink(): 81 | CPUID_REG = 0xe000ed00 82 | 83 | def __init__(self): 84 | self._start_time = time.time() 85 | self._connector = None 86 | self._stlink = None 87 | self._driver = None 88 | 89 | def find_mcus_by_core(self): 90 | if (self._hard): 91 | self._core.core_hard_reset_halt() 92 | else: 93 | self._core.core_halt() 94 | cpuid = self._stlink.get_debugreg32(PyStlink.CPUID_REG) 95 | if cpuid == 0: 96 | raise lib.stlinkex.StlinkException('Not connected to CPU') 97 | self._dbg.verbose("CPUID: %08x" % cpuid) 98 | partno = 0xfff & (cpuid >> 4) 99 | for mcu_core in lib.stm32devices.DEVICES: 100 | if mcu_core['part_no'] == partno: 101 | self._mcus_by_core = mcu_core 102 | return 103 | raise lib.stlinkex.StlinkException('PART_NO: 0x%03x is not supported' % partno) 104 | 105 | def find_mcus_by_devid(self): 106 | # STM32H7 hack: this MCU has ID-CODE on different address than STM32F7 107 | devid = 0x000 108 | idcode_regs = self._mcus_by_core['idcode_reg'] 109 | if isinstance(self._mcus_by_core['idcode_reg'], int): 110 | idcode_regs = [idcode_regs] 111 | for idcode_reg in idcode_regs: 112 | idcode = self._stlink.get_debugreg32(idcode_reg) 113 | self._dbg.verbose("IDCODE: %08x" % idcode) 114 | devid = 0xfff & idcode 115 | for mcu_devid in self._mcus_by_core['devices']: 116 | if mcu_devid['dev_id'] == devid: 117 | self._mcus_by_devid = mcu_devid 118 | return 119 | raise lib.stlinkex.StlinkException('DEV_ID: 0x%03x is not supported' % devid) 120 | 121 | def find_mcus_by_flash_size(self): 122 | self._flash_size = self._stlink.get_debugreg16(self._mcus_by_devid['flash_size_reg']) 123 | self._mcus = [] 124 | for mcu in self._mcus_by_devid['devices']: 125 | if mcu['flash_size'] == self._flash_size: 126 | self._mcus.append(mcu) 127 | if not self._mcus: 128 | raise lib.stlinkex.StlinkException('Connected CPU with DEV_ID: 0x%03x and FLASH size: %dKB is not supported. Check Protection' % ( 129 | self._mcus_by_devid['dev_id'], self._flash_size 130 | )) 131 | 132 | def fix_cpu_type(self, cpu_type): 133 | cpu_type = cpu_type.upper() 134 | # now support only STM32 135 | if cpu_type.startswith('STM32'): 136 | # change character on 10 position to 'x' where is package size code 137 | if len(cpu_type) > 9: 138 | cpu_type = list(cpu_type) 139 | cpu_type[9] = 'x' 140 | cpu_type = ''.join(cpu_type) 141 | return cpu_type 142 | raise lib.stlinkex.StlinkException('"%s" is not STM32 family' % cpu_type) 143 | 144 | def filter_detected_cpu(self, expected_cpus): 145 | cpus = [] 146 | for detected_cpu in self._mcus: 147 | for expected_cpu in expected_cpus: 148 | expected_cpu = self.fix_cpu_type(expected_cpu) 149 | if detected_cpu['type'].startswith(expected_cpu): 150 | cpus.append(detected_cpu) 151 | break 152 | if not cpus: 153 | raise lib.stlinkex.StlinkException('Connected CPU is not %s but detected is %s %s' % ( 154 | ','.join(expected_cpus), 155 | 'one of' if len(self._mcus) > 1 else '', 156 | ','.join([cpu['type'] for cpu in self._mcus]), 157 | )) 158 | self._mcus = cpus 159 | 160 | def find_sram_eeprom_size(self): 161 | # if is found more MCUS, then SRAM and EEPROM size 162 | # will be used the smallest of all (worst case) 163 | self._sram_size = min([mcu['sram_size'] for mcu in self._mcus]) 164 | self._eeprom_size = min([mcu['eeprom_size'] for mcu in self._mcus]) 165 | self._dbg.info("SRAM: %dKB" % self._sram_size) 166 | if self._eeprom_size: 167 | self._dbg.info("EEPROM: %dKB" % self._eeprom_size) 168 | if len(self._mcus) > 1: 169 | diff = False 170 | if self._sram_size != max([mcu['sram_size'] for mcu in self._mcus]): 171 | diff = True 172 | self._dbg.warning("Detected CPUs have different SRAM sizes.") 173 | if self._eeprom_size != max([mcu['eeprom_size'] for mcu in self._mcus]): 174 | diff = True 175 | self._dbg.warning("Detected CPUs have different EEPROM sizes.") 176 | if diff: 177 | self._dbg.warning("Is recommended to select certain CPU with --cpu {cputype}. Now is used the smallest memory size.") 178 | 179 | def load_driver(self): 180 | flash_driver = self._mcus_by_devid['flash_driver'] 181 | if flash_driver == 'STM32FP': 182 | self._driver = lib.stm32fp.Stm32FP(self._stlink, dbg=self._dbg) 183 | elif flash_driver == 'STM32FPXL': 184 | self._driver = lib.stm32fp.Stm32FPXL(self._stlink, dbg=self._dbg) 185 | elif flash_driver == 'STM32FS': 186 | self._driver = lib.stm32fs.Stm32FS(self._stlink, dbg=self._dbg) 187 | elif flash_driver == 'STM32L0': 188 | self._driver = lib.stm32l0.Stm32L0(self._stlink, dbg=self._dbg) 189 | elif flash_driver == 'STM32L4': 190 | self._driver = lib.stm32l4.Stm32L4(self._stlink, dbg=self._dbg) 191 | elif flash_driver == 'STM32H7': 192 | self._driver = lib.stm32h7.Stm32H7(self._stlink, dbg=self._dbg) 193 | else: 194 | self._driver = self._core 195 | 196 | def detect_cpu(self, expected_cpus, unmount=False): 197 | self._connector = lib.stlinkusb.StlinkUsbConnector(dbg=self._dbg, serial=self._serial, index = self._index) 198 | if unmount: 199 | self._connector.unmount_discovery() 200 | self._stlink = lib.stlinkv2.Stlink(self._connector, dbg=self._dbg) 201 | self._dbg.info("DEVICE: ST-Link/%s" % self._stlink.ver_str) 202 | self._dbg.info("SUPPLY: %.2fV" % self._stlink.target_voltage) 203 | self._dbg.verbose("COREID: %08x" % self._stlink.coreid) 204 | if self._stlink.coreid == 0: 205 | raise lib.stlinkex.StlinkException('Not connected to CPU') 206 | self._core = lib.stm32.Stm32(self._stlink, dbg=self._dbg) 207 | self.find_mcus_by_core() 208 | self._dbg.info("CORE: %s" % self._mcus_by_core['core']) 209 | self.find_mcus_by_devid() 210 | self.find_mcus_by_flash_size() 211 | if expected_cpus: 212 | # filter detected MCUs by selected MCU type 213 | self.filter_detected_cpu(expected_cpus) 214 | self._dbg.info("MCU: %s" % '/'.join([mcu['type'] for mcu in self._mcus])) 215 | self._dbg.info("FLASH: %dKB" % self._flash_size) 216 | self.find_sram_eeprom_size() 217 | self.load_driver() 218 | 219 | def print_buffer(self, addr, data, bytes_per_line=16): 220 | prev_chunk = [] 221 | same_chunk = False 222 | for i in range(0, len(data), bytes_per_line): 223 | chunk = data[i:i + bytes_per_line] 224 | if prev_chunk != chunk: 225 | print('%08x %s%s %s' % ( 226 | addr, 227 | ' '.join(['%02x' % d for d in chunk]), 228 | ' ' * (16 - len(chunk)), 229 | ''.join([chr(d) if d >= 32 and d < 127 else '.' for d in chunk]), 230 | )) 231 | prev_chunk = chunk 232 | same_chunk = False 233 | elif not same_chunk: 234 | print('*') 235 | same_chunk = True 236 | addr += len(chunk) 237 | print('%08x' % addr) 238 | 239 | def store_file(self, addr, data, filename): 240 | with open(filename, 'wb') as f: 241 | f.write(bytes(data)) 242 | self._dbg.info("Saved %d Bytes into %s file" % (len(data), filename)) 243 | 244 | def read_file(self, filename): 245 | if filename.endswith('.srec'): 246 | srec = lib.srec.Srec() 247 | srec.encode_file(filename) 248 | size = sum([len(i[1]) for i in srec.buffers]) 249 | self._dbg.info("Loaded %d Bytes from %s file" % (size, filename)) 250 | return srec.buffers 251 | with open(filename, 'rb') as f: 252 | data = list(f.read()) 253 | self._dbg.info("Loaded %d Bytes from %s file" % (len(data), filename)) 254 | return [(None, data)] 255 | raise lib.stlinkex.StlinkException("Error reading file") 256 | 257 | def dump_mem(self, addr, size): 258 | print("08x %d" % addr, size) 259 | data = self._driver.get_mem(addr, size) 260 | self.print_buffer(addr, data) 261 | 262 | def cmd_dump(self, params): 263 | cmd = params[0] 264 | params = params[1:] 265 | if cmd == 'core': 266 | # dump all core registers 267 | self._driver.core_halt() 268 | for reg, val in self._driver.get_reg_all(): 269 | print(" %3s: %08x" % (reg, val)) 270 | elif self._driver.is_reg(cmd): 271 | # dump core register 272 | self._driver.core_halt() 273 | reg = cmd.upper() 274 | val = self._driver.get_reg(reg) 275 | print(" %3s: %08x" % (reg, val)) 276 | elif cmd == 'flash': 277 | size = int(params[0], 0) if params else self._flash_size * 1024 278 | data = self._driver.get_mem(self._driver.FLASH_START, size) 279 | self.print_buffer(self._driver.FLASH_START, data) 280 | elif cmd == 'sram': 281 | size = int(params[0], 0) if params else self._sram_size * 1024 282 | data = self._driver.get_mem(self._driver.SRAM_START, size) 283 | self.print_buffer(self._driver.SRAM_START, data) 284 | elif params: 285 | # dump memory from address with size 286 | addr = int(cmd, 0) 287 | data = self._driver.get_mem(addr, int(params[0], 0)) 288 | self.print_buffer(addr, data) 289 | else: 290 | # dump 32 bit register at address 291 | addr = int(cmd, 0) 292 | val = self._stlink.get_debugreg32(addr) 293 | print(' %08x: %08x' % (addr, val)) 294 | 295 | def cmd_read(self, params): 296 | cmd = params[0] 297 | file_name = params[-1] 298 | params = params[1:-1] 299 | if cmd == 'flash': 300 | addr = self._driver.FLASH_START 301 | size = int(params[0], 0) if params else self._flash_size * 1024 302 | elif cmd == 'sram': 303 | addr = self._driver.SRAM_START 304 | size = int(params[0], 0) if params else self._sram_size * 1024 305 | elif params: 306 | addr = int(cmd, 0) 307 | size = int(params[0], 0) 308 | else: 309 | raise lib.stlinkex.StlinkExceptionBadParam() 310 | data = self._driver.get_mem(addr, size) 311 | self.store_file(addr, data, file_name) 312 | 313 | def cmd_set(self, params): 314 | cmd = params[0] 315 | params = params[1:] 316 | if not params: 317 | raise lib.stlinkex.StlinkExceptionBadParam('Missing argument') 318 | data = int(params[0], 0) 319 | if self._driver.is_reg(cmd): 320 | self._driver.core_halt() 321 | reg = cmd.upper() 322 | self._driver.set_reg(reg, data) 323 | else: 324 | addr = int(cmd, 0) 325 | self._stlink.set_debugreg32(addr, data) 326 | 327 | def cmd_fill(self, params): 328 | cmd = params[0] 329 | value = int(params[-1], 0) 330 | params = params[1:-1] 331 | if cmd == 'sram': 332 | size = int(params[0], 0) if params else self._sram_size * 1024 333 | self._driver.fill_mem(self._driver.SRAM_START, size, value) 334 | elif params: 335 | self._driver.fill_mem(int(cmd, 0), int(params[0], 0), value) 336 | else: 337 | raise lib.stlinkex.StlinkExceptionBadParam() 338 | 339 | def cmd_write(self, params): 340 | mem = self.read_file(params[-1]) 341 | params = params[:-1] 342 | if len(mem) == 1 and mem[0][0] is None: 343 | data = mem[0][1] 344 | if len(params) != 1: 345 | raise lib.stlinkex.StlinkExceptionBadParam('Address is not set') 346 | if params[0] == 'sram': 347 | addr = self._driver.SRAM_START 348 | if len(data) > self._sram_size * 1024: 349 | raise lib.stlinkex.StlinkExceptionBadParam('Data are bigger than SRAM') 350 | else: 351 | addr = int(params[0], 0) 352 | self._driver.set_mem(addr, data) 353 | return 354 | if params: 355 | raise lib.stlinkex.StlinkException('Address for write is set by file') 356 | for addr, data in mem: 357 | self._driver.set_mem(addr, data) 358 | 359 | def cmd_flash(self, params): 360 | erase = False 361 | verify = False 362 | write = True 363 | if params[0] == 'erase': 364 | params = params[1:] 365 | if not params: 366 | self._flash_size = self._stlink.get_debugreg16(self._mcus_by_devid['flash_size_reg']) 367 | self._driver.flash_erase_all(self._flash_size) 368 | return 369 | erase = True 370 | elif params[0] == 'check': 371 | write = False 372 | verify = True 373 | params = params[1:] 374 | mem = self.read_file(params[-1]) 375 | params = params[:-1] 376 | if params and params[0] == 'verify': 377 | verify = True 378 | params = params[1:] 379 | start_addr = lib.stm32.Stm32.FLASH_START 380 | if len(mem) == 1 and mem[0][0] is None: 381 | if params: 382 | start_addr = int(params[0], 0) 383 | params = params[1:] 384 | if params: 385 | raise lib.stlinkex.StlinkExceptionBadParam('Address for write is set by file') 386 | for addr, data in mem: 387 | if addr is None: 388 | addr = start_addr 389 | if write: 390 | self._driver.flash_write(addr, data, erase=erase, erase_sizes=self._mcus_by_devid['erase_sizes']) 391 | self._driver.core_reset_halt() 392 | time.sleep(0.1) 393 | if verify: 394 | self._driver.core_halt() 395 | self._driver.flash_verify(addr, data) 396 | self._driver.core_run() 397 | def cmd(self, param): 398 | cmd = param[0] 399 | params = param[1:] 400 | if cmd == 'dump' and params: 401 | self.cmd_dump(params) 402 | elif cmd == 'dump16' and params: 403 | addr = int(params[0], 0) 404 | reg = self._stlink.get_debugreg16(addr) 405 | print(' %08x: %04x' % (addr, reg)) 406 | elif cmd == 'dump8' and params: 407 | addr = int(params[0], 0) 408 | reg = self._stlink.get_debugreg8(addr) 409 | print(' %08x: %02x' % (addr, reg)) 410 | elif cmd == 'read' and params: 411 | self.cmd_read(params) 412 | elif cmd == 'set' and params: 413 | self.cmd_set(params) 414 | elif cmd == 'write' and params: 415 | self.cmd_write(params) 416 | elif cmd == 'fill' and params: 417 | self.cmd_fill(params) 418 | elif cmd == 'flash' and params: 419 | self.cmd_flash(params) 420 | elif cmd == 'reset': 421 | if params: 422 | if params[0] == 'halt': 423 | self._driver.core_reset_halt() 424 | else: 425 | raise lib.stlinkex.StlinkExceptionBadParam() 426 | else: 427 | self._driver.core_reset() 428 | elif cmd == 'halt': 429 | self._driver.core_halt() 430 | elif cmd == 'step': 431 | self._driver.core_step() 432 | elif cmd == 'run': 433 | self._driver.core_run() 434 | elif cmd == 'sleep' and len(params) == 1: 435 | time.sleep(float(params[0])) 436 | else: 437 | raise lib.stlinkex.StlinkExceptionBadParam() 438 | 439 | def start(self): 440 | parser = argparse.ArgumentParser(prog='pystlink', formatter_class=argparse.RawTextHelpFormatter, description=DESCRIPTION_STR, epilog=ACTIONS_HELP_STR) 441 | group_verbose = parser.add_argument_group(title='set verbosity level').add_mutually_exclusive_group() 442 | group_verbose.set_defaults(verbosity=1) 443 | group_verbose.add_argument('-q', '--quiet', action='store_const', dest='verbosity', const=0) 444 | group_verbose.add_argument('-i', '--info', action='store_const', dest='verbosity', const=1, help='default') 445 | group_verbose.add_argument('-v', '--verbose', action='store_const', dest='verbosity', const=2) 446 | group_verbose.add_argument('-d', '--debug', action='store_const', dest='verbosity', const=3) 447 | parser.add_argument('-V', '--version', action='version', version=VERSION_STR) 448 | parser.add_argument('-c', '--cpu', action='append', help='set expected CPU type [eg: STM32F051, STM32L4]') 449 | parser.add_argument('-r', '--no-run', action='store_true', help='do not run core when program end (if core was halted)') 450 | parser.add_argument('-u', '--no-unmount', action='store_true', help='do not unmount DISCOVERY from ST-Link/V2-1 on OS/X platform') 451 | parser.add_argument('-s', '--serial', dest='serial', help='Use Stlink with given serial number') 452 | parser.add_argument('-n', '--num-index', type=int, dest='index', default=0, help='Use Stlink with given index') 453 | parser.add_argument('-H', '--hard', action='store_true', help='Reset device with NRST') 454 | group_actions = parser.add_argument_group(title='actions') 455 | group_actions.add_argument('action', nargs='*', help='actions will be processed sequentially') 456 | args = parser.parse_args() 457 | self._dbg = lib.dbg.Dbg(args.verbosity) 458 | self._serial = args.serial 459 | self._index = args.index 460 | self._hard = args.hard 461 | runtime_status = 0 462 | try: 463 | self.detect_cpu(args.cpu, not args.no_unmount) 464 | if args.action and self._driver is None: 465 | raise lib.stlinkex.StlinkExceptionCpuNotSelected() 466 | for action in args.action: 467 | self._dbg.verbose('CMD: %s' % action) 468 | try: 469 | self.cmd(action.split(':')) 470 | except lib.stlinkex.StlinkExceptionBadParam as e: 471 | raise e.set_cmd(action) 472 | except (lib.stlinkex.StlinkExceptionBadParam, lib.stlinkex.StlinkException) as e: 473 | self._dbg.error(e) 474 | runtime_status = 1 475 | except KeyboardInterrupt: 476 | self._dbg.error('Keyboard interrupt') 477 | runtime_status = 1 478 | except (ValueError, OverflowError, FileNotFoundError, Exception) as e: 479 | self._dbg.error('Parameter error: %s' % e) 480 | if args.verbosity >= 3: 481 | raise e 482 | runtime_status = 1 483 | if self._stlink: 484 | try: 485 | if self._driver: 486 | if not args.no_run: 487 | self._driver.core_nodebug() 488 | else: 489 | self._dbg.warning('CPU may stay in halt mode', level=1) 490 | self._stlink.leave_state() 491 | self._stlink.clean_exit() 492 | except lib.stlinkex.StlinkException as e: 493 | self._dbg.error(e) 494 | runtime_status = 1 495 | self._dbg.verbose('DONE in %0.2fs' % (time.time() - self._start_time)) 496 | if runtime_status: 497 | sys.exit(runtime_status) 498 | 499 | 500 | if __name__ == "__main__": 501 | pystlink = PyStlink() 502 | pystlink.start() 503 | -------------------------------------------------------------------------------- /pystlink_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import pystlink 4 | import lib.stm32 5 | import lib.stlinkex 6 | 7 | 8 | class MockDbg(): 9 | def __init__(self): 10 | pass 11 | 12 | def debug(self, msg, level=2): 13 | pass 14 | # print(msg) 15 | 16 | def msg(self, msg, level=1): 17 | pass 18 | # print(msg) 19 | 20 | def verbose(self, msg, level=1): 21 | pass 22 | # print(msg) 23 | 24 | def bargraph_start(self, msg, value_min=0, value_max=100, level=1): 25 | pass 26 | 27 | def bargraph_update(self, value=0, percent=None): 28 | pass 29 | 30 | def bargraph_done(self): 31 | pass 32 | 33 | def set_verbose(self, verbose): 34 | pass 35 | 36 | 37 | class TestStm32(unittest.TestCase): 38 | def setUp(self): 39 | self._pystlink = pystlink.PyStlink() 40 | self._pystlink._dbg = MockDbg() 41 | # self._driver = lib.stm32.Stm32(stlink=None, dbg=dbg) 42 | 43 | # def test_read_version(self): 44 | # class MockStlink(): 45 | # def get_version(self): 46 | # return 0x25c0 47 | # self._driver._driver = MockStlink() 48 | # self._driver.read_version() 49 | # self.assertEqual(self._driver._ver_stlink, 2) 50 | # self.assertEqual(self._driver._ver_jtag, 23) 51 | # self.assertEqual(self._driver._ver_swim, 0) 52 | # self.assertEqual(self._driver._ver_api, 2) 53 | 54 | # def test_read_target_voltage(self): 55 | # class MockStlink(): 56 | # def get_target_voltage(self): 57 | # return 3.3 58 | # self._driver._driver = MockStlink() 59 | # self._driver.read_target_voltage() 60 | # self.assertEqual(self._driver._voltage, 3.3) 61 | 62 | def test_find_mcus_by_core_m0(self): 63 | self._pystlink._devices = [ 64 | {'part_no': 0xc20, 'core': 'CortexM0'}, 65 | {'part_no': 0xc24, 'core': 'CortexM4'}, 66 | ] 67 | 68 | class MockStlink(): 69 | def get_debugreg32(self, reg): 70 | assert reg == 0xe000ed00 71 | return 0x410cc200 72 | self._pystlink._stlink = MockStlink() 73 | self._pystlink.find_mcus_by_core() 74 | self.assertEqual(self._pystlink._mcus_by_core['core'], 'CortexM0') 75 | 76 | def test_find_mcus_by_core_m4(self): 77 | self._pystlink._devices = [ 78 | {'part_no': 0xc20, 'core': 'CortexM0'}, 79 | {'part_no': 0xc24, 'core': 'CortexM4'}, 80 | ] 81 | 82 | class MockStlink(): 83 | def get_debugreg32(self, reg): 84 | assert reg == 0xe000ed00 85 | return 0x410fc241 86 | self._pystlink._stlink = MockStlink() 87 | self._pystlink.find_mcus_by_core() 88 | self.assertEqual(self._pystlink._mcus_by_core['core'], 'CortexM4') 89 | 90 | def test_find_mcus_by_core_fail(self): 91 | self._pystlink._devices = [ 92 | {'part_no': 0xc20, 'core': 'CortexM0'}, 93 | {'part_no': 0xc24, 'core': 'CortexM4'}, 94 | ] 95 | 96 | class MockStlink(): 97 | def get_debugreg32(self, reg): 98 | assert reg == 0xe000ed00 99 | return 0x410fc251 100 | self._pystlink._stlink = MockStlink() 101 | with self.assertRaises(lib.stlinkex.StlinkException): 102 | self._pystlink.find_mcus_by_core() 103 | 104 | def test_find_mcus_by_devid_413(self): 105 | self._pystlink._mcus_by_core = { 106 | 'idcode_reg': 0xE0042000, 107 | 'devices': [ 108 | {'dev_id': 0x413}, 109 | {'dev_id': 0x415}, 110 | ] 111 | } 112 | 113 | class MockStlink(): 114 | def get_debugreg32(self, reg): 115 | assert reg == 0xE0042000 116 | return 0x10016413 117 | self._pystlink._stlink = MockStlink() 118 | self._pystlink.find_mcus_by_devid() 119 | assert self._pystlink._mcus_by_devid['dev_id'] == 0x413 120 | 121 | def test_find_mcus_by_devid_415(self): 122 | self._pystlink._mcus_by_core = { 123 | 'idcode_reg': 0xE0042000, 124 | 'devices': [ 125 | {'dev_id': 0x413}, 126 | {'dev_id': 0x415}, 127 | ] 128 | } 129 | 130 | class MockStlink(): 131 | def get_debugreg32(self, reg): 132 | assert reg == 0xE0042000 133 | return 0x10016415 134 | self._pystlink._stlink = MockStlink() 135 | self._pystlink.find_mcus_by_devid() 136 | assert self._pystlink._mcus_by_devid['dev_id'] == 0x415 137 | 138 | def test_find_mcus_by_devid_fail(self): 139 | self._pystlink._mcus_by_core = { 140 | 'idcode_reg': 0xE0042000, 141 | 'devices': [ 142 | {'dev_id': 0x413}, 143 | {'dev_id': 0x415}, 144 | ] 145 | } 146 | 147 | class MockStlink(): 148 | def get_debugreg32(self, reg): 149 | assert reg == 0xE0042000 150 | return 0x10016417 151 | self._pystlink._stlink = MockStlink() 152 | with self.assertRaises(lib.stlinkex.StlinkException): 153 | self._pystlink.find_mcus_by_devid() 154 | 155 | def test_find_mcus_by_flash_size_64(self): 156 | self._pystlink._mcus_by_devid = { 157 | 'dev_id': 0x414, 158 | 'flash_size_reg': 0x1fff7a22, 159 | 'devices': [ 160 | {'flash_size': 64}, 161 | {'flash_size': 128}, 162 | {'flash_size': 64}, 163 | {'flash_size': 128}, 164 | {'flash_size': 256}, 165 | ] 166 | } 167 | 168 | class MockStlink(): 169 | def get_debugreg16(self, reg): 170 | assert reg == 0x1fff7a22 171 | return 64 172 | self._pystlink._stlink = MockStlink() 173 | self._pystlink.find_mcus_by_flash_size() 174 | assert len(self._pystlink._mcus) == 2 175 | for mcu in self._pystlink._mcus: 176 | self.assertEqual(mcu['flash_size'], 64) 177 | 178 | def test_find_mcus_by_flash_size_256(self): 179 | self._pystlink._mcus_by_devid = { 180 | 'dev_id': 0x414, 181 | 'flash_size_reg': 0x1fff7a22, 182 | 'devices': [ 183 | {'flash_size': 64}, 184 | {'flash_size': 128}, 185 | {'flash_size': 64}, 186 | {'flash_size': 128}, 187 | {'flash_size': 256}, 188 | ] 189 | } 190 | 191 | class MockStlink(): 192 | def get_debugreg16(self, reg): 193 | assert reg == 0x1fff7a22 194 | return 256 195 | self._pystlink._stlink = MockStlink() 196 | self._pystlink.find_mcus_by_flash_size() 197 | assert len(self._pystlink._mcus) == 1 198 | for mcu in self._pystlink._mcus: 199 | self.assertEqual(mcu['flash_size'], 256) 200 | 201 | def test_find_mcus_by_flash_size_fail(self): 202 | self._pystlink._mcus_by_devid = { 203 | 'dev_id': 0x414, 204 | 'flash_size_reg': 0x1fff7a22, 205 | 'devices': [ 206 | {'flash_size': 64}, 207 | {'flash_size': 128}, 208 | {'flash_size': 64}, 209 | {'flash_size': 128}, 210 | {'flash_size': 256}, 211 | ] 212 | } 213 | 214 | class MockStlink(): 215 | def get_debugreg16(self, reg): 216 | assert reg == 0x1fff7a22 217 | return 512 218 | self._pystlink._stlink = MockStlink() 219 | with self.assertRaises(lib.stlinkex.StlinkException): 220 | self._pystlink.find_mcus_by_flash_size() 221 | 222 | def test_filter_detected_cpu_two(self): 223 | self._pystlink._mcus = [ 224 | {'type': 'STM32F030x8'}, 225 | {'type': 'STM32F031x8'}, 226 | {'type': 'STM32F051x8'}, 227 | ] 228 | self._pystlink.filter_detected_cpu(['STM32F03']) 229 | self.assertEqual(len(self._pystlink._mcus), 2) 230 | self.assertEqual(self._pystlink._mcus, [ 231 | {'type': 'STM32F030x8'}, 232 | {'type': 'STM32F031x8'}, 233 | ]) 234 | 235 | def test_filter_detected_cpu_one(self): 236 | self._pystlink._mcus = [ 237 | {'type': 'STM32F030x8'}, 238 | {'type': 'STM32F031x8'}, 239 | {'type': 'STM32F051x8'}, 240 | ] 241 | self._pystlink.filter_detected_cpu(['STM32F051R8']) 242 | self.assertEqual(len(self._pystlink._mcus), 1) 243 | self.assertEqual(self._pystlink._mcus, [ 244 | {'type': 'STM32F051x8'}, 245 | ]) 246 | 247 | def test_filter_detected_cpu_fail(self): 248 | self._pystlink._mcus = [ 249 | {'type': 'STM32F030x8'}, 250 | {'type': 'STM32F031x8'}, 251 | {'type': 'STM32F051x8'}, 252 | ] 253 | with self.assertRaises(lib.stlinkex.StlinkException): 254 | self._pystlink.filter_detected_cpu(['STM32F103']) 255 | 256 | 257 | class TestStm32_get_mem(unittest.TestCase): 258 | def setUp(self): 259 | class MockStlink(): 260 | STLINK_MAXIMUM_TRANSFER_SIZE = 1024 261 | 262 | def __init__(self, test): 263 | self._test = test 264 | self._pointer = None 265 | self._index = 0 266 | 267 | def get_mem32(self, addr, size): 268 | self._test.assertNotEqual(size, 0) 269 | self._test.assertEqual(addr % 4, 0) 270 | self._test.assertEqual(size % 4, 0) 271 | if self._pointer is None: 272 | self._pointer = addr 273 | assert size <= 1024 274 | self._test.assertEqual(addr, self._pointer) 275 | self._pointer += size 276 | old_index = self._index 277 | self._index += size 278 | return [i & 0xff for i in range(old_index, self._index)] 279 | 280 | def get_mem8(self, addr, size): 281 | self._test.assertNotEqual(size, 0) 282 | if self._pointer is None: 283 | self._pointer = addr 284 | assert size <= 64 285 | self._test.assertEqual(addr, self._pointer) 286 | self._pointer += size 287 | old_index = self._index 288 | self._index += size 289 | return [i & 0xff for i in range(old_index, self._index)] 290 | 291 | self._driver = lib.stm32.Stm32(stlink=MockStlink(self), dbg=MockDbg()) 292 | 293 | def _test_get_mem(self, addr, size): 294 | data = self._driver.get_mem(addr, size) 295 | expected_data = [i & 0xff for i in range(0, size)] 296 | self.assertEqual(data, expected_data) 297 | 298 | def test_addr_0_size_0(self): 299 | self._test_get_mem(0, 0) 300 | 301 | def test_addr_0_size_1(self): 302 | self._test_get_mem(0, 1) 303 | 304 | def test_addr_0_size_2(self): 305 | self._test_get_mem(0, 2) 306 | 307 | def test_addr_0_size_3(self): 308 | self._test_get_mem(0, 3) 309 | 310 | def test_addr_0_size_4(self): 311 | self._test_get_mem(0, 4) 312 | 313 | def test_addr_1_size_0(self): 314 | self._test_get_mem(1, 0) 315 | 316 | def test_addr_1_size_1(self): 317 | self._test_get_mem(1, 1) 318 | 319 | def test_addr_1_size_3(self): 320 | self._test_get_mem(1, 3) 321 | 322 | def test_addr_1_size_4(self): 323 | self._test_get_mem(1, 4) 324 | 325 | def test_addr_2_size_1(self): 326 | self._test_get_mem(2, 1) 327 | 328 | def test_addr_2_size_2(self): 329 | self._test_get_mem(2, 2) 330 | 331 | def test_addr_2_size_4(self): 332 | self._test_get_mem(2, 4) 333 | 334 | def test_addr_3_size_1(self): 335 | self._test_get_mem(3, 1) 336 | 337 | def test_addr_3_size_2(self): 338 | self._test_get_mem(3, 2) 339 | 340 | def test_addr_3_size_4(self): 341 | self._test_get_mem(3, 4) 342 | 343 | def test_addr_4_size_1(self): 344 | self._test_get_mem(4, 1) 345 | 346 | def test_addr_4_size_4(self): 347 | self._test_get_mem(4, 4) 348 | 349 | def test_addr_4_size_12(self): 350 | self._test_get_mem(4, 12) 351 | 352 | def test_addr_4_size_13(self): 353 | self._test_get_mem(4, 13) 354 | 355 | def test_addr_5_size_11(self): 356 | self._test_get_mem(5, 11) 357 | 358 | def test_addr_5_size_12(self): 359 | self._test_get_mem(5, 12) 360 | 361 | def test_addr_0_size_1024(self): 362 | self._test_get_mem(0, 1024) 363 | 364 | def test_addr_0_size_1025(self): 365 | self._test_get_mem(0, 1025) 366 | 367 | def test_addr_0_size_1028(self): 368 | self._test_get_mem(0, 1028) 369 | 370 | def test_addr_0_size_2048(self): 371 | self._test_get_mem(0, 2048) 372 | 373 | def test_addr_0_size_8192(self): 374 | self._test_get_mem(0, 8192) 375 | 376 | def test_addr_1_size_8192(self): 377 | self._test_get_mem(1, 8192) 378 | 379 | def test_addr_4095_size_8192(self): 380 | self._test_get_mem(4095, 8192) 381 | 382 | def test_addr_4096_size_8192(self): 383 | self._test_get_mem(4096, 8192) 384 | 385 | def test_addr_1_size_1100(self): 386 | self._test_get_mem(1, 1100) 387 | 388 | def test_addr_4_size_1100(self): 389 | self._test_get_mem(2, 1100) 390 | 391 | 392 | class TestStm32_set_mem(unittest.TestCase): 393 | def setUp(self): 394 | class MockStlink(): 395 | STLINK_MAXIMUM_TRANSFER_SIZE = 1024 396 | 397 | def __init__(self, test): 398 | self._test = test 399 | self._pointer = None 400 | self._index = 0 401 | 402 | def set_mem32(self, addr, data): 403 | self._test.assertNotEqual(len(data), 0) 404 | self._test.assertEqual(addr % 4, 0) 405 | self._test.assertEqual(len(data) % 4, 0) 406 | if self._pointer is None: 407 | self._pointer = addr 408 | assert len(data) <= 1024 409 | self._test.assertEqual(addr, self._pointer) 410 | self._pointer += len(data) 411 | self._index += len(data) 412 | 413 | def set_mem8(self, addr, data): 414 | self._test.assertNotEqual(len(data), 0) 415 | if self._pointer is None: 416 | self._pointer = addr 417 | assert len(data) <= 64 418 | self._test.assertEqual(addr, self._pointer) 419 | self._pointer += len(data) 420 | self._index += len(data) 421 | 422 | self._driver = lib.stm32.Stm32(stlink=MockStlink(self), dbg=MockDbg()) 423 | 424 | def _test_set_mem(self, addr, size): 425 | self._driver.set_mem(addr, [i & 0xff for i in range(0, size)]) 426 | 427 | def test_addr_0_size_0(self): 428 | self._test_set_mem(0, 0) 429 | 430 | def test_addr_0_size_1(self): 431 | self._test_set_mem(0, 1) 432 | 433 | def test_addr_0_size_2(self): 434 | self._test_set_mem(0, 2) 435 | 436 | def test_addr_0_size_3(self): 437 | self._test_set_mem(0, 3) 438 | 439 | def test_addr_0_size_4(self): 440 | self._test_set_mem(0, 4) 441 | 442 | def test_addr_1_size_0(self): 443 | self._test_set_mem(1, 0) 444 | 445 | def test_addr_1_size_1(self): 446 | self._test_set_mem(1, 1) 447 | 448 | def test_addr_1_size_3(self): 449 | self._test_set_mem(1, 3) 450 | 451 | def test_addr_1_size_4(self): 452 | self._test_set_mem(1, 4) 453 | 454 | def test_addr_2_size_1(self): 455 | self._test_set_mem(2, 1) 456 | 457 | def test_addr_2_size_2(self): 458 | self._test_set_mem(2, 2) 459 | 460 | def test_addr_2_size_4(self): 461 | self._test_set_mem(2, 4) 462 | 463 | def test_addr_3_size_1(self): 464 | self._test_set_mem(3, 1) 465 | 466 | def test_addr_3_size_2(self): 467 | self._test_set_mem(3, 2) 468 | 469 | def test_addr_3_size_4(self): 470 | self._test_set_mem(3, 4) 471 | 472 | def test_addr_4_size_1(self): 473 | self._test_set_mem(4, 1) 474 | 475 | def test_addr_4_size_4(self): 476 | self._test_set_mem(4, 4) 477 | 478 | def test_addr_4_size_12(self): 479 | self._test_set_mem(4, 12) 480 | 481 | def test_addr_4_size_13(self): 482 | self._test_set_mem(4, 13) 483 | 484 | def test_addr_5_size_11(self): 485 | self._test_set_mem(5, 11) 486 | 487 | def test_addr_5_size_12(self): 488 | self._test_set_mem(5, 12) 489 | 490 | def test_addr_0_size_1024(self): 491 | self._test_set_mem(0, 1024) 492 | 493 | def test_addr_0_size_1025(self): 494 | self._test_set_mem(0, 1025) 495 | 496 | def test_addr_0_size_1028(self): 497 | self._test_set_mem(0, 1028) 498 | 499 | def test_addr_0_size_2048(self): 500 | self._test_set_mem(0, 2048) 501 | 502 | def test_addr_0_size_8192(self): 503 | self._test_set_mem(0, 8192) 504 | 505 | def test_addr_1_size_8192(self): 506 | self._test_set_mem(1, 8192) 507 | 508 | def test_addr_4095_size_8192(self): 509 | self._test_set_mem(4095, 8192) 510 | 511 | def test_addr_4096_size_8192(self): 512 | self._test_set_mem(4096, 8192) 513 | 514 | def test_addr_1_size_1100(self): 515 | self._test_set_mem(1, 1100) 516 | 517 | def test_addr_4_size_1100(self): 518 | self._test_set_mem(2, 1100) 519 | 520 | 521 | class TestStm32_fill_mem(unittest.TestCase): 522 | def setUp(self): 523 | class MockStlink(): 524 | STLINK_MAXIMUM_TRANSFER_SIZE = 1024 525 | 526 | def __init__(self, test): 527 | self._test = test 528 | self._pointer = None 529 | self._index = 0 530 | 531 | def set_mem32(self, addr, data): 532 | self._test.assertNotEqual(len(data), 0) 533 | self._test.assertEqual(addr % 4, 0) 534 | self._test.assertEqual(len(data) % 4, 0) 535 | if self._pointer is None: 536 | self._pointer = addr 537 | assert len(data) <= 1024 538 | self._test.assertEqual(addr, self._pointer) 539 | self._pointer += len(data) 540 | self._index += len(data) 541 | 542 | def set_mem8(self, addr, data): 543 | self._test.assertNotEqual(len(data), 0) 544 | if self._pointer is None: 545 | self._pointer = addr 546 | assert len(data) <= 64 547 | self._test.assertEqual(addr, self._pointer) 548 | self._pointer += len(data) 549 | self._index += len(data) 550 | 551 | self._driver = lib.stm32.Stm32(stlink=MockStlink(self), dbg=MockDbg()) 552 | 553 | def _test_fill_mem(self, addr, size): 554 | self._driver.fill_mem(addr, size, 0x55) 555 | 556 | def test_addr_0_size_0(self): 557 | self._test_fill_mem(0, 0) 558 | 559 | def test_addr_0_size_1(self): 560 | self._test_fill_mem(0, 1) 561 | 562 | def test_addr_0_size_2(self): 563 | self._test_fill_mem(0, 2) 564 | 565 | def test_addr_0_size_3(self): 566 | self._test_fill_mem(0, 3) 567 | 568 | def test_addr_0_size_4(self): 569 | self._test_fill_mem(0, 4) 570 | 571 | def test_addr_1_size_0(self): 572 | self._test_fill_mem(1, 0) 573 | 574 | def test_addr_1_size_1(self): 575 | self._test_fill_mem(1, 1) 576 | 577 | def test_addr_1_size_3(self): 578 | self._test_fill_mem(1, 3) 579 | 580 | def test_addr_1_size_4(self): 581 | self._test_fill_mem(1, 4) 582 | 583 | def test_addr_2_size_1(self): 584 | self._test_fill_mem(2, 1) 585 | 586 | def test_addr_2_size_2(self): 587 | self._test_fill_mem(2, 2) 588 | 589 | def test_addr_2_size_4(self): 590 | self._test_fill_mem(2, 4) 591 | 592 | def test_addr_3_size_1(self): 593 | self._test_fill_mem(3, 1) 594 | 595 | def test_addr_3_size_2(self): 596 | self._test_fill_mem(3, 2) 597 | 598 | def test_addr_3_size_4(self): 599 | self._test_fill_mem(3, 4) 600 | 601 | def test_addr_4_size_1(self): 602 | self._test_fill_mem(4, 1) 603 | 604 | def test_addr_4_size_4(self): 605 | self._test_fill_mem(4, 4) 606 | 607 | def test_addr_4_size_12(self): 608 | self._test_fill_mem(4, 12) 609 | 610 | def test_addr_4_size_13(self): 611 | self._test_fill_mem(4, 13) 612 | 613 | def test_addr_5_size_11(self): 614 | self._test_fill_mem(5, 11) 615 | 616 | def test_addr_5_size_12(self): 617 | self._test_fill_mem(5, 12) 618 | 619 | def test_addr_0_size_1024(self): 620 | self._test_fill_mem(0, 1024) 621 | 622 | def test_addr_0_size_1025(self): 623 | self._test_fill_mem(0, 1025) 624 | 625 | def test_addr_0_size_1028(self): 626 | self._test_fill_mem(0, 1028) 627 | 628 | def test_addr_0_size_2048(self): 629 | self._test_fill_mem(0, 2048) 630 | 631 | def test_addr_0_size_8192(self): 632 | self._test_fill_mem(0, 8192) 633 | 634 | def test_addr_1_size_8192(self): 635 | self._test_fill_mem(1, 8192) 636 | 637 | def test_addr_4095_size_8192(self): 638 | self._test_fill_mem(4095, 8192) 639 | 640 | def test_addr_4096_size_8192(self): 641 | self._test_fill_mem(4096, 8192) 642 | 643 | def test_addr_1_size_1100(self): 644 | self._test_fill_mem(1, 1100) 645 | 646 | def test_addr_4_size_1100(self): 647 | self._test_fill_mem(2, 1100) 648 | 649 | 650 | if __name__ == '__main__': 651 | unittest.main() 652 | -------------------------------------------------------------------------------- /pystlink_test_system.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import subprocess 3 | 4 | 5 | class Stlink(unittest.TestCase): 6 | def _pystlink(self, arg=None, excepted_err=''): 7 | args = ['python', 'pystlink.py'] 8 | if arg: 9 | args += arg 10 | p = subprocess.Popen( 11 | args, 12 | stdout=subprocess.PIPE, 13 | stderr=subprocess.PIPE, 14 | ) 15 | ret = p.wait() 16 | out, err = p.communicate() 17 | out = out.decode(encoding='UTF-8').strip() 18 | err = err.decode(encoding='UTF-8').strip() 19 | errors = [] 20 | warnings = [] 21 | debug = [] 22 | params = {} 23 | for err_line in err.splitlines(): 24 | e = err_line.strip() 25 | if e.startswith('***') and e.endswith('***'): 26 | errors.append(e.strip('***').strip()) 27 | elif e.startswith('*'): 28 | warnings.append(e.strip('*').strip()) 29 | else: 30 | if e: 31 | debug.append(e) 32 | if ':' in e: 33 | k, v = e.split(':', 1) 34 | params[k.strip()] = v.strip() 35 | output = [] 36 | values = {} 37 | for out_line in out.splitlines(): 38 | o = out_line.strip() 39 | if o: 40 | output.append(o) 41 | if ':' in o: 42 | k, v = o.split(':', 1) 43 | values[k.strip()] = v.strip() 44 | return { 45 | 'ret': ret, 46 | # 'stdout': out, 47 | # 'stderr': err, 48 | 'errors': errors, 49 | 'warnings': warnings, 50 | 'debug': debug, 51 | 'output': output, 52 | 'params': params, 53 | 'values': values, 54 | } 55 | 56 | 57 | class TestNotStlink(Stlink): 58 | def testNotConnectedStlink(self): 59 | ret = self._pystlink() 60 | self.assertEqual(ret['errors'], ['ST-Link/V2 is not connected']) 61 | self.assertEqual(ret['warnings'], []) 62 | self.assertEqual(ret['output'], []) 63 | 64 | 65 | class TestNotCpu(Stlink): 66 | def testNotConnectedCpu(self): 67 | ret = self._pystlink() 68 | self.assertEqual(ret['errors'], ['Not connected to CPU']) 69 | self.assertEqual(ret['warnings'], []) 70 | assert 'DEVICE' in ret['params'] 71 | assert 'SUPPLY' in ret['params'] 72 | self.assertEqual(ret['output'], []) 73 | 74 | 75 | class TestStm32(Stlink): 76 | REGISTERS = ['R0', 'R1', 'R2', 'R3', 'R4', 'R5', 'R6', 'R7', 'R8', 'R9', 'R10', 'R11', 'R12', 'SP', 'LR', 'PC', 'PSR', 'MSP', 'PSP'] 77 | SRAM_START = 0x20000000 78 | FLASH_START = 0x08000000 79 | 80 | def testConnect(self): 81 | ret = self._pystlink() 82 | self.assertEqual(ret['errors'], []) 83 | self.assertEqual(ret['warnings'], []) 84 | assert 'DEVICE' in ret['params'] 85 | assert 'SUPPLY' in ret['params'] 86 | assert 'CORE' in ret['params'] 87 | assert 'MCU' in ret['params'] 88 | assert 'FLASH' in ret['params'] 89 | assert 'SRAM' in ret['params'] 90 | self.assertEqual(ret['output'], []) 91 | 92 | def testCoreReset(self): 93 | ret = self._pystlink(['reset']) 94 | self.assertEqual(ret['errors'], []) 95 | self.assertEqual(ret['warnings'], []) 96 | self.assertEqual(ret['output'], []) 97 | 98 | def testCoreResetHalt(self): 99 | ret = self._pystlink(['reset:halt']) 100 | self.assertEqual(ret['errors'], []) 101 | self.assertEqual(ret['warnings'], []) 102 | self.assertEqual(ret['output'], []) 103 | 104 | def testCoreHalt(self): 105 | ret = self._pystlink(['halt']) 106 | self.assertEqual(ret['errors'], []) 107 | self.assertEqual(ret['warnings'], []) 108 | self.assertEqual(ret['output'], []) 109 | 110 | def testCoreRun(self): 111 | ret = self._pystlink(['run']) 112 | self.assertEqual(ret['errors'], []) 113 | self.assertEqual(ret['warnings'], []) 114 | self.assertEqual(ret['output'], []) 115 | 116 | def testCoreStep(self): 117 | ret = self._pystlink(['step']) 118 | self.assertEqual(ret['errors'], []) 119 | self.assertEqual(ret['warnings'], []) 120 | self.assertEqual(ret['output'], []) 121 | 122 | def testNorun(self): 123 | ret = self._pystlink(['--no-run']) 124 | self.assertEqual(ret['errors'], []) 125 | self.assertEqual(ret['warnings'], ['CPU may stay in halt mode']) 126 | self.assertEqual(ret['output'], []) 127 | 128 | def testDumpRegAll(self): 129 | ret = self._pystlink(['dump:core']) 130 | self.assertEqual(ret['errors'], []) 131 | self.assertEqual(ret['warnings'], []) 132 | for reg in self.REGISTERS: 133 | assert reg in ret['values'] 134 | 135 | def testDumpRegR0(self): 136 | ret = self._pystlink(['dump:R0']) 137 | self.assertEqual(ret['errors'], []) 138 | self.assertEqual(ret['warnings'], []) 139 | assert 'R0' in ret['values'] 140 | 141 | def testDumpRegPC(self): 142 | ret = self._pystlink(['dump:PC']) 143 | self.assertEqual(ret['errors'], []) 144 | self.assertEqual(ret['warnings'], []) 145 | assert 'PC' in ret['values'] 146 | 147 | def testDumpReg(self): 148 | ret = self._pystlink(['dump:0x08000000']) 149 | self.assertEqual(ret['errors'], []) 150 | self.assertEqual(ret['warnings'], []) 151 | assert '08000000' in ret['values'] 152 | assert len(ret['values']['08000000']) == 8 153 | 154 | def testDumpReg16(self): 155 | ret = self._pystlink(['dump16:0x08000000']) 156 | self.assertEqual(ret['errors'], []) 157 | self.assertEqual(ret['warnings'], []) 158 | assert '08000000' in ret['values'] 159 | assert len(ret['values']['08000000']) == 4 160 | 161 | def testDumpReg8(self): 162 | ret = self._pystlink(['dump8:0x08000000']) 163 | self.assertEqual(ret['errors'], []) 164 | self.assertEqual(ret['warnings'], []) 165 | assert '08000000' in ret['values'] 166 | assert len(ret['values']['08000000']) == 2 167 | 168 | def testDumpMem1(self): 169 | ret = self._pystlink(['dump:0x08000000:1']) 170 | self.assertEqual(ret['errors'], []) 171 | self.assertEqual(ret['warnings'], []) 172 | self.assertEqual(len(ret['output']), 2) 173 | self.assertEqual(ret['output'][-1], '08000001') 174 | 175 | def testDumpMem16(self): 176 | ret = self._pystlink(['dump:0x08000000:16']) 177 | self.assertEqual(ret['errors'], []) 178 | self.assertEqual(ret['warnings'], []) 179 | self.assertEqual(len(ret['output']), 2) 180 | self.assertEqual(ret['output'][-1], '08000010') 181 | 182 | def testDumpMem18(self): 183 | ret = self._pystlink(['dump:0x08000000:18']) 184 | self.assertEqual(ret['errors'], []) 185 | self.assertEqual(ret['warnings'], []) 186 | assert len(ret['output']) <= 3 187 | self.assertEqual(ret['output'][-1], '08000012') 188 | 189 | def testDumpMem1024(self): 190 | ret = self._pystlink(['dump:0x08000000:1024']) 191 | self.assertEqual(ret['errors'], []) 192 | self.assertEqual(ret['warnings'], []) 193 | assert len(ret['output']) <= 65 194 | self.assertEqual(ret['output'][-1], '08000400') 195 | 196 | def testDumpMem4008(self): 197 | ret = self._pystlink(['dump:0x08000000:4008']) 198 | self.assertEqual(ret['errors'], []) 199 | self.assertEqual(ret['warnings'], []) 200 | assert len(ret['output']) <= 252 201 | self.assertEqual(ret['output'][-1], '08000fa8') 202 | 203 | # TODO these two tests are disabled because 204 | # if is lot of data in memory, then this script can hang 205 | def _testDumpSram(self): 206 | ret = self._pystlink(['dump:sram']) 207 | self.assertEqual(ret['errors'], []) 208 | self.assertEqual(ret['warnings'], []) 209 | sram_size = int(ret['params']['SRAM'].strip('KB')) * 1024 210 | assert len(ret['output']) <= sram_size // 16 + 1 211 | self.assertEqual(int(ret['output'][0].split()[0], 16), self.SRAM_START) 212 | self.assertEqual(int(ret['output'][-1], 16), self.SRAM_START + sram_size) 213 | 214 | def _testDumpFlash(self): 215 | ret = self._pystlink(['dump:flash']) 216 | self.assertEqual(ret['errors'], []) 217 | self.assertEqual(ret['warnings'], []) 218 | flash_size = int(ret['params']['FLASH'].strip('KB')) * 1024 219 | assert len(ret['output']) <= flash_size // 16 + 1 220 | self.assertEqual(int(ret['output'][0].split()[0], 16), self.FLASH_START) 221 | self.assertEqual(int(ret['output'][-1], 16), self.FLASH_START + flash_size) 222 | 223 | def testWriteRegR0(self): 224 | ret = self._pystlink([ 225 | 'reset:halt', 226 | 'set:R0:0x12345678', 227 | 'dump:R0', 228 | ]) 229 | self.assertEqual(ret['errors'], []) 230 | self.assertEqual(ret['warnings'], []) 231 | self.assertEqual(int(ret['values']['R0'], 16), 0x12345678) 232 | 233 | def testWriteReg(self): 234 | ret = self._pystlink([ 235 | 'reset:halt', 236 | 'set:0x20000000:0x12345678', 237 | 'dump:0x20000000', 238 | ]) 239 | self.assertEqual(ret['errors'], []) 240 | self.assertEqual(ret['warnings'], []) 241 | self.assertEqual(int(ret['values']['20000000'], 16), 0x12345678) 242 | 243 | def testCoreStepCode(self): 244 | ret = self._pystlink([ 245 | 'reset:halt', 246 | 'set:0x20000000:0x46c046c0', # 2 x THMUB NOP (MOV R8, R8) instructions into begin of RAM 247 | 'set:pc:0x20000000', # set PC to begin of RAM 248 | 'dump:pc', 249 | 'step', 250 | 'dump:pc', 251 | 'step', 252 | 'dump:pc', 253 | 'reset', 254 | ]) 255 | self.assertEqual(ret['errors'], []) 256 | self.assertEqual(ret['warnings'], []) 257 | self.assertEqual(ret['output'], ['PC: 20000000', 'PC: 20000002', 'PC: 20000004', ]) 258 | 259 | 260 | if __name__ == '__main__': 261 | import sys 262 | if len(sys.argv) < 2: 263 | print('Select right test case class depending on connected HW (as command line parameter):') 264 | import inspect 265 | for name, obj in inspect.getmembers(sys.modules[__name__]): 266 | if inspect.isclass(obj) and name.startswith('Test'): 267 | print(' ' + name) 268 | sys.exit(0) 269 | unittest.main() 270 | -------------------------------------------------------------------------------- /stlinkv2.rules: -------------------------------------------------------------------------------- 1 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE:="0666", SYMLINK+="stlinkv2_%n" 2 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE:="0666", SYMLINK+="stlinkv2-1_%n" 3 | --------------------------------------------------------------------------------