stm32isp 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
stm32isp/__init__.py ADDED
@@ -0,0 +1 @@
1
+ from .stm32isp import _main
stm32isp/stm32isp.py ADDED
@@ -0,0 +1,418 @@
1
+ #!/usr/bin/env python3
2
+ # ===================================================================================
3
+ # Project: stm32isp - Programming Tool for some STM32 Microcontrollers
4
+ # Version: v0.8
5
+ # Year: 2023
6
+ # Author: Stefan Wagner
7
+ # Github: https://github.com/wagiminator
8
+ # License: MIT License
9
+ # ===================================================================================
10
+ #
11
+ # Description:
12
+ # ------------
13
+ # Python tool for flashing some entry-level STM32 microcontrollers via USB-to-serial
14
+ # converter utilizing the factory built-in UART boot loader. Supported devices:
15
+ # - STM32C011/031
16
+ # - STM32F03xx4/6
17
+ # - STM32G03x/04x
18
+ # - STM32L01x/02x
19
+ # !!! THIS TOOL IS IN AN EARLY STAGE OF DEVELOPMENT !!!
20
+ #
21
+ # Dependencies:
22
+ # -------------
23
+ # - pyserial
24
+ #
25
+ # Operating Instructions:
26
+ # -----------------------
27
+ # You need to install PySerial to use stm32isp.
28
+ # Install it via "python3 -m pip install pyserial".
29
+ # You may need to install a driver for your USB-to-serial converter.
30
+ #
31
+ # On some STM32, the BOOT0 pin is disabled by default. As soon as the chip is brand
32
+ # new and/or the main flash memory is deleted, this is not a problem, the embedded
33
+ # bootloader will automatically start. Using this stm32isp tool will automatically
34
+ # activate the BOOT0 pin so that it can also be used in the following. However, if
35
+ # the chip has already been written to before using a different software tool, it
36
+ # is likely that the bootloader can no longer be activated via the BOOT0 pin. In
37
+ # this case, the bit nBOOT_SEL in the User Option Bytes must be deleted (set to 0)
38
+ # using an SWD programmer (e.g. ST-Link) and appropriate software.
39
+ #
40
+ # Connect your USB-to-serial converter to your MCU:
41
+ # USB2SERIAL STM32C011/031
42
+ # RXD <--- PA9 (PA11)
43
+ # TXD ---> PA10 (PA12)
44
+ # VCC ---> VCC
45
+ # GND ---> GND
46
+ #
47
+ # USB2SERIAL STM32F03xx4/6
48
+ # RXD <--- PA9 or PA14
49
+ # TXD ---> PA10 or PA15
50
+ # VCC ---> VCC
51
+ # GND ---> GND
52
+ #
53
+ # USB2SERIAL STM32G03x/04x
54
+ # RXD <--- PA2 or PA9
55
+ # TXD ---> PA3 or PA10
56
+ # VCC ---> VCC
57
+ # GND ---> GND
58
+ #
59
+ # USB2SERIAL STM32L01x/02x
60
+ # RXD <--- PA2 or PA9
61
+ # TXD ---> PA3 or PA10
62
+ # VCC ---> VCC
63
+ # GND ---> GND
64
+ #
65
+ # Set your MCU to boot mode by using the following method:
66
+ # - Connect your USB-to-serial converter to your USB port. Pull BOOT0 pin (PA14)
67
+ # to VCC, then pull nRST shortly to GND (or press and hold the BOOT button,
68
+ # then press and release the RESET button and then release the BOOT button, if
69
+ # your board has them).
70
+ #
71
+ # Run "python3 stm32isp.py -f firmware.bin".
72
+
73
+ # If the PID/VID of the USB-to-Serial converter is known, it can be defined here,
74
+ # which can make the auto-detection a lot faster. If not, comment out or delete.
75
+ #ST_VID = '1A86'
76
+ #ST_PID = '7523'
77
+
78
+ # Define BAUD rate here, range: 1200 - 115200, default: 115200
79
+ ST_BAUD = 115200
80
+
81
+ # Libraries
82
+ import sys
83
+ import argparse
84
+ import serial
85
+ from serial import Serial
86
+ from serial.tools.list_ports import comports
87
+
88
+ # ===================================================================================
89
+ # Main Function
90
+ # ===================================================================================
91
+
92
+ def _main():
93
+ # Parse command line arguments
94
+ parser = argparse.ArgumentParser(description='Minimal command line interface for STM32 ISP')
95
+ parser.add_argument('-u', '--unlock', action='store_true', help='unlock chip (remove read protection)')
96
+ parser.add_argument('-l', '--lock', action='store_true', help='lock chip (set read protection)')
97
+ parser.add_argument('-e', '--erase', action='store_true', help='perform a chip erase (implied with -f)')
98
+ parser.add_argument('-f', '--flash', help='write BIN file to flash and verify')
99
+ args = parser.parse_args(sys.argv[1:])
100
+
101
+ # Check arguments
102
+ if not any( (args.unlock, args.lock, args.erase, args.flash) ):
103
+ print('No arguments - no action!')
104
+ sys.exit(0)
105
+
106
+ # Establish connection to MCU via USB-to-serial converter
107
+ try:
108
+ print('Connecting to MCU via USB-to-serial converter ...')
109
+ isp = Programmer()
110
+ print('SUCCESS: Connection established via', isp.port + '.')
111
+ except Exception as ex:
112
+ sys.stderr.write('ERROR: ' + str(ex) + '!\n')
113
+ sys.exit(1)
114
+
115
+ # Performing actions
116
+ try:
117
+ # Get chip info
118
+ print('Getting chip info ...')
119
+ isp.readinfo()
120
+ print('SUCCESS: Found', isp.chipname, 'with bootloader v' + isp.verstr + '.')
121
+
122
+ # Check if chip is locked, unlock if so; erase chip
123
+ if not isp.readoption():
124
+ print('Chip is locked, unlocking and erasing ...')
125
+ isp.unlock()
126
+ isp.sendcommand(ST_SYNCH)
127
+ isp.readoption()
128
+ print('SUCCESS: Chip is unlocked and erased.')
129
+ else:
130
+ if args.unlock:
131
+ print('INFO: Chip is already unlocked.')
132
+ if (args.erase) or (args.flash is not None):
133
+ print('Performing chip erase ...')
134
+ isp.erase()
135
+ print('SUCCESS: Chip is erased.')
136
+
137
+ # Flash binary file
138
+ if args.flash is not None:
139
+ print('Flashing', args.flash, 'to', isp.chipname, '...')
140
+ with open(args.flash, 'rb') as f: data = f.read()
141
+ isp.writeflash(ST_CODE_ADDR, data)
142
+ print('Verifying ...')
143
+ isp.verifyflash(ST_CODE_ADDR, data)
144
+ print('SUCCESS:', len(data), 'bytes written and verified.')
145
+
146
+ # Enable BOOT0 pin in OPTION bytes (nBOOT_SEL = 0) for STM32C/G
147
+ if (isp.pid in (0x443, 0x453, 0x466)) and isp.checkbootpin():
148
+ print('Enabling BOOT0 pin in OPTION bytes ...')
149
+ isp.enablebootpin()
150
+ print('SUCCESS: Modified OPTION bytes written.')
151
+ isp.close()
152
+
153
+ # Lock chip (set readout protection)
154
+ if args.lock:
155
+ print('Locking chip ...')
156
+ isp.lock()
157
+ print('SUCCESS: Chip is locked.')
158
+ print('INFO: A power-on reset may need to be performed.')
159
+ isp.close()
160
+
161
+ # Run firmware
162
+ if isp.isOpen():
163
+ isp.run()
164
+
165
+ except Exception as ex:
166
+ sys.stderr.write('ERROR: ' + str(ex) + '!\n')
167
+ isp.close()
168
+ sys.exit(1)
169
+
170
+ print('DONE.')
171
+ sys.exit(0)
172
+
173
+ # ===================================================================================
174
+ # Programmer Class
175
+ # ===================================================================================
176
+
177
+ class Programmer(Serial):
178
+ def __init__(self):
179
+ # BAUD rate: 1200 - 115200bps (default: 115200), will be auto-detected
180
+ # Data frame: 1 start bit, 8 data bit, 1 parity bit set to even, 1 stop bit
181
+ super().__init__(baudrate = ST_BAUD, parity = serial.PARITY_EVEN, timeout = 1)
182
+ self.identify()
183
+
184
+ # Identify port of programmer and enter programming mode
185
+ def identify(self):
186
+ for p in comports():
187
+ if (('ST_VID' not in globals()) or (ST_VID in p.hwid)) and (('ST_PID' not in globals()) or (ST_PID in p.hwid)):
188
+ self.port = p.device
189
+ try:
190
+ self.open()
191
+ except:
192
+ continue
193
+ self.reset_input_buffer()
194
+ self.write([ST_SYNCH])
195
+ if not self.checkreply():
196
+ self.close()
197
+ continue
198
+ return
199
+ raise Exception('No MCU in boot mode found')
200
+
201
+ # Send command
202
+ def sendcommand(self, command):
203
+ self.write([command, command ^ 0xff])
204
+ if not self.checkreply():
205
+ raise Exception('Device has not acknowledged the command 0x%02x' % command)
206
+
207
+ # Send address
208
+ def sendaddress(self, addr):
209
+ stream = addr.to_bytes(4, byteorder='big')
210
+ parity = 0x00
211
+ for x in range(4):
212
+ parity ^= stream[x]
213
+ self.write(stream)
214
+ self.write([parity])
215
+ if not self.checkreply():
216
+ raise Exception('Failed to send address')
217
+
218
+ # Check if device acknowledged
219
+ def checkreply(self):
220
+ reply = self.read(1)
221
+ return (len(reply) == 1 and reply[0] == ST_REPLY_ACK)
222
+
223
+ #--------------------------------------------------------------------------------
224
+
225
+ # Read info stream
226
+ def readinfostream(self, command):
227
+ self.sendcommand(command)
228
+ size = self.read(1)[0]
229
+ stream = self.read(size + 1)
230
+ if not self.checkreply():
231
+ raise Exception('Failed to read info')
232
+ return stream
233
+
234
+ # Get chip info
235
+ def readinfo(self):
236
+ self.info = self.readinfostream(ST_CMD_GET)
237
+ self.ver = self.info[0]
238
+ self.verstr = '%x.%x' % (self.ver >> 4, self.ver & 7)
239
+ self.cmds = list(self.info[1:])
240
+ self.pid = int.from_bytes(self.readinfostream(ST_CMD_PID), byteorder='big')
241
+ self.device = None
242
+
243
+ # Find device in dictionary
244
+ for d in DEVICES:
245
+ if d['id'] == self.pid:
246
+ self.device = d
247
+ if self.device is None:
248
+ raise Exception('Unsupported chip (ID: 0x%04x)' % self.chipid)
249
+
250
+ # Set parameters according to dictionary
251
+ self.chipname = self.device['name']
252
+ self.option_address = self.device['opt_addr']
253
+
254
+ # Read OPTION bytes
255
+ def readoption(self):
256
+ try:
257
+ self.option = list(self.readflash(self.option_address, 8))
258
+ except:
259
+ return False
260
+ if self.pid == 0x457:
261
+ self.optionbytes = int.from_bytes(self.option[0:2], byteorder='little') \
262
+ | (int.from_bytes(self.option[4:6], byteorder='little') << 16)
263
+ else:
264
+ self.optionbytes = int.from_bytes(self.option[:4], byteorder='little')
265
+ return True
266
+
267
+ # Check if BOOT0 pin ist disabled in OPTION bytes (STM32C/G only)
268
+ def checkbootpin(self):
269
+ return ((self.option[3] & 0x01) == 0x01)
270
+
271
+ # Enable BOOT0 pin in OPTION bytes (nBOOT_SEL = 0), STM32C/G only
272
+ def enablebootpin(self):
273
+ if self.pid in (0x443, 0x453, 0x466):
274
+ self.option[3] = (self.option[3] & 0b11111000) | 0b00000110
275
+ for x in range(4):
276
+ self.option[x+4] = self.option[x] ^ 0xff
277
+ self.writeflash(self.option_address, self.option)
278
+
279
+ # Unlock chip (remove readout protection), erase and reset
280
+ def unlock(self):
281
+ self.sendcommand(ST_CMD_R_UNLOCK)
282
+ if not self.checkreply():
283
+ raise Exception('Failed to unlock chip')
284
+
285
+ # Lock chip (set readout protection)
286
+ def lock(self):
287
+ self.sendcommand(ST_CMD_R_LOCK)
288
+ if not self.checkreply():
289
+ raise Exception('Failed to lock chip')
290
+
291
+ # Start firmware and disconnect
292
+ def run(self):
293
+ self.sendcommand(ST_CMD_GO)
294
+ self.sendaddress(ST_CODE_ADDR)
295
+ self.close()
296
+
297
+ #--------------------------------------------------------------------------------
298
+
299
+ # Erase whole chip
300
+ def erase(self):
301
+ if self.pid == 0x457:
302
+ self.erasepages(128)
303
+ return
304
+ elif ST_CMD_ERASE_X in self.cmds:
305
+ self.sendcommand(ST_CMD_ERASE_X)
306
+ self.write(b'\xff\xff\x00')
307
+ else:
308
+ self.sendcommand(ST_CMD_ERASE)
309
+ self.write(b'\xff\x00')
310
+ if not self.checkreply():
311
+ raise Exception('Failed to erase chip')
312
+
313
+ # Erase number of pages
314
+ def erasepages(self, pagecount):
315
+ pagecount -= 1
316
+ self.sendcommand(ST_CMD_ERASE_X)
317
+ self.write([pagecount >> 16, pagecount & 0xff])
318
+ parity = (pagecount >> 16) ^ (pagecount & 0xff)
319
+ for x in range(pagecount + 1):
320
+ self.write([x >> 16, x & 0xff])
321
+ parity ^= (x >> 16) ^ (x & 0xff)
322
+ self.write([parity])
323
+ if not self.checkreply():
324
+ raise Exception('Failed to erase pages')
325
+
326
+ # Read flash
327
+ def readflash(self, addr, size):
328
+ data = bytes()
329
+ while size > 0:
330
+ blocksize = min(size, ST_PAGE_SIZE)
331
+ self.sendcommand(ST_CMD_READ)
332
+ self.sendaddress(addr)
333
+ self.sendcommand(blocksize - 1)
334
+ data += self.read(blocksize)
335
+ addr += blocksize
336
+ size -= blocksize
337
+ return data
338
+
339
+ # Write to flash
340
+ def writeflash(self, addr, data):
341
+ size = len(data)
342
+ while size > 0:
343
+ blocksize = min(size, ST_PAGE_SIZE)
344
+ block = data[:blocksize]
345
+ parity = blocksize - 1
346
+ for x in range(blocksize):
347
+ parity ^= block[x]
348
+ self.sendcommand(ST_CMD_WRITE)
349
+ self.sendaddress(addr)
350
+ self.write([blocksize - 1])
351
+ self.write(block)
352
+ self.write([parity])
353
+ if not self.checkreply():
354
+ raise Exception('Failed to write to address 0x%08x' % addr)
355
+ data = data[blocksize:]
356
+ addr += blocksize
357
+ size -= blocksize
358
+
359
+ # Verify flash
360
+ def verifyflash(self, addr, data):
361
+ flash = self.readflash(addr, len(data))
362
+ if set(flash) != set(data):
363
+ raise Exception('Verification failed')
364
+
365
+ # Pad data
366
+ def paddata(self, data, pagesize):
367
+ if (len(data) % pagesize) > 0:
368
+ data += b'\xff' * (pagesize - (len(data) % pagesize))
369
+ return data
370
+
371
+ # ===================================================================================
372
+ # Device Constants
373
+ # ===================================================================================
374
+
375
+ # Device and Memory constants
376
+ ST_PAGE_SIZE = 256
377
+ ST_FLASH_ADDR = 0x08000000
378
+ ST_CODE_ADDR = 0x08000000
379
+ ST_SRAM_ADDR = 0x20000000
380
+
381
+ # Command codes
382
+ ST_CMD_GET = 0x00
383
+ ST_CMD_VER = 0x01
384
+ ST_CMD_PID = 0x02
385
+ ST_CMD_READ = 0x11
386
+ ST_CMD_WRITE = 0x31
387
+ ST_CMD_ERASE = 0x43
388
+ ST_CMD_ERASE_X = 0x44
389
+ ST_CMD_GO = 0x21
390
+ ST_CMD_W_LOCK = 0x63
391
+ ST_CMD_W_UNLOCK = 0x73
392
+ ST_CMD_R_LOCK = 0x82
393
+ ST_CMD_R_UNLOCK = 0x92
394
+
395
+ # Reply codes
396
+ ST_REPLY_ACK = 0x79
397
+ ST_REPLY_NACK = 0x1f
398
+ ST_REPLY_BUSY = 0xaa
399
+
400
+ # Other codes
401
+ ST_SYNCH = 0x7f
402
+
403
+ # ===================================================================================
404
+ # Device definitions
405
+ # ===================================================================================
406
+
407
+ DEVICES = [
408
+ {'name': 'STM32C011xx', 'id': 0x443, 'opt_addr': 0x1fff7800, 'opt_default': 0xfffffeaa},
409
+ {'name': 'STM32C031xx', 'id': 0x453, 'opt_addr': 0x1fff7800, 'opt_default': 0xfffffeaa},
410
+ {'name': 'STM32G03x/04x', 'id': 0x466, 'opt_addr': 0x1fff7800, 'opt_default': 0xfffffeaa},
411
+ {'name': 'STM32L01x/02x', 'id': 0x457, 'opt_addr': 0x1ff80000, 'opt_default': 0x807000aa},
412
+ {'name': 'STM32F03xx4/6', 'id': 0x444, 'opt_addr': 0x1ffff800, 'opt_default': 0x00ff55aa}
413
+ ]
414
+
415
+ # ===================================================================================
416
+
417
+ if __name__ == "__main__":
418
+ _main()
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Stefan Wagner
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.
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.1
2
+ Name: stm32isp
3
+ Version: 0.8.0
4
+ Summary: Programming Tool for some STM32 Microcontrollers
5
+ Home-page: https://github.com/wagiminator/MCU-Flash-Tools
6
+ Author: Stefan Wagner
7
+ Author-email: Stefan Wagner <wagiminator@web.de>
8
+ Maintainer-email: Stefan Wagner <wagiminator@web.de>
9
+ License: MIT License
10
+
11
+ Copyright (c) 2023 Stefan Wagner
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ Project-URL: Homepage, https://wagiminator.github.io/
31
+ Project-URL: Repository, https://github.com/wagiminator/MCU-Flash-Tools
32
+ Project-URL: Issues, https://github.com/wagiminator/MCU-Flash-Tools/issues
33
+ Keywords: STM32,STM32C011,STM32F030,STM32G030,STM32L011,microcontroller
34
+ Classifier: Development Status :: 4 - Beta
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Operating System :: OS Independent
38
+ Classifier: Intended Audience :: Developers
39
+ Classifier: Topic :: Software Development :: Embedded Systems
40
+ Requires-Python: >=3.8
41
+ Description-Content-Type: text/markdown
42
+ License-File: LICENSE
43
+ Requires-Dist: pyserial
44
+
45
+ # stm32isp - Programming Tool for some STM32 Microcontrollers
46
+ ## Description
47
+ With this tool, some entry-level STM32 microcontrollers can be flashed via a simple USB-to-serial converter by utilizing the factory built-in UART bootloader. It currently supports the following devices:
48
+ - STM32C011/031
49
+ - STM32F03xx4/6
50
+ - STM32G03x/04x
51
+ - STM32L01x/02x
52
+
53
+ ## Preparations
54
+ If necessary, a driver for the USB-to-serial converter used must be installed.
55
+
56
+ ## Installation
57
+ - Install [Python3](https://www.pythontutorial.net/getting-started/install-python/).
58
+ - Install [pip](https://pip.pypa.io/en/stable/installation/).
59
+ - Install stm32isp:
60
+
61
+ ```
62
+ pip install stm32isp
63
+ ```
64
+
65
+ ## Usage
66
+ Connect your USB-to-serial converter to your STM32 MCU as follows:
67
+
68
+ ```
69
+ USB2SERIAL STM32C011/031
70
+ +--------+ +------------+
71
+ | RXD| <--- |PA9 (PA11) |
72
+ | TXD| ---> |PA10 (PA12) |
73
+ | 3V3| ---> |VDD (3V3) |
74
+ | GND| ---> |GND |
75
+ +--------+ +------------+
76
+
77
+ USB2SERIAL STM32F03xx4/6
78
+ +--------+ +------------+
79
+ | RXD| <--- |PA9 or PA14|
80
+ | TXD| ---> |PA10 or PA15|
81
+ | 3V3| ---> |VDD (3V3) |
82
+ | GND| ---> |GND |
83
+ +--------+ +------------+
84
+
85
+ USB2SERIAL STM32G03x/04x
86
+ +--------+ +------------+
87
+ | RXD| <--- |PA2 or PA9 |
88
+ | TXD| ---> |PA3 or PA10 |
89
+ | 3V3| ---> |VDD (3V3) |
90
+ | GND| ---> |GND |
91
+ +--------+ +------------+
92
+
93
+ USB2SERIAL STM32L01x/02x
94
+ +--------+ +------------+
95
+ | RXD| <--- |PA2 or PA9 |
96
+ | TXD| ---> |PA3 or PA10 |
97
+ | 3V3| ---> |VDD (3V3) |
98
+ | GND| ---> |GND |
99
+ +--------+ +------------+
100
+ ```
101
+
102
+ Set your MCU to boot mode by using ONE of the following method:
103
+ - Disconnect your board from all power supplies, pull BOOT0 pin to VCC (or press and hold the BOOT button if your board has one), then connect the board to your USB port. The BOOT button can be released now.
104
+ - Connect your USB-to-serial converter to your USB port. Pull BOOT0 pin to VCC, then pull nRST shortly to GND (or press and hold the BOOT button, then press and release the RESET button and then release the BOOT button, if your board has them).
105
+
106
+ On STM32G03x/04x microcontrollers, the BOOT0 pin is initially disabled. When the chip is brand new or the main flash memory is erased, this isn't an issue as the embedded bootloader automatically kicks in. By using the stm32isp tool, the BOOT0 pin will be activated for subsequent use. However, if the chip has been previously programmed using a different software tool, the bootloader might not be accessible through the BOOT0 pin anymore. In such cases, the nBOOT_SEL bit in the User Option Bytes must be cleared (set to 0) using an SWD programmer like ST-Link and the appropriate software.
107
+
108
+ ```
109
+ Usage: stm32isp [-h] [-u] [-l] [-e] [-f FLASH]
110
+
111
+ Optional arguments:
112
+ -h, --help show this help message and exit
113
+ -u, --unlock unlock chip (remove read protection)
114
+ -l, --lock lock chip (set read protection)
115
+ -e, --erase perform chip erase (implied with -f)
116
+ -f FLASH, --flash FLASH write BIN file to flash and verify
117
+
118
+ Example:
119
+ stm32isp -f firmware.bin
120
+ ```
121
+
122
+ ## Links
123
+ - [MCU Flash Tools](https://github.com/wagiminator/MCU-Flash-Tools)
124
+ - [MCU Templates](https://github.com/wagiminator/MCU-Templates)
125
+ - [MCU Development Boards](https://github.com/wagiminator/Development-Boards)
126
+ - [AVR Development Boards](https://github.com/wagiminator/AVR-Development-Boards)
127
+ - [AVR Programmers](https://github.com/wagiminator/AVR-Programmer)
128
+ - [SAMD Development Boards](https://github.com/wagiminator/SAMD-Development-Boards)
@@ -0,0 +1,8 @@
1
+ stm32isp/__init__.py,sha256=Bh6Qq09dlS7NyC3YsfgRld6Jg8grZHBLROxjlFjt14Q,27
2
+ stm32isp/stm32isp.py,sha256=AGZgDaag8PbnzhmZ1LOeEQOhgcM4mbnSH6r0w_SYb6A,15335
3
+ stm32isp-0.8.0.dist-info/LICENSE,sha256=kph2e2d1k_-VvrU6YbwdbUJ2GKXsFgBGCSym5wVv2j8,1089
4
+ stm32isp-0.8.0.dist-info/METADATA,sha256=v1W6gjfeb8oENbfkJK0Ch_u7NixPXcasbn-vwJaNO2g,5809
5
+ stm32isp-0.8.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
6
+ stm32isp-0.8.0.dist-info/entry_points.txt,sha256=KrPwmj9BZ7OgNdmaoWGFSce4I2Q4zZcdLMUJ2V9A7kk,44
7
+ stm32isp-0.8.0.dist-info/top_level.txt,sha256=ymspw44mJvCL5yOuXL5c6ExSZ6oHZB5qumMZW9wtRAI,9
8
+ stm32isp-0.8.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (72.1.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ stm32isp = stm32isp:_main
@@ -0,0 +1 @@
1
+ stm32isp