puyaisp 1.4.0__tar.gz

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.
puyaisp-1.4.0/LICENSE ADDED
@@ -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.
puyaisp-1.4.0/PKG-INFO ADDED
@@ -0,0 +1,101 @@
1
+ Metadata-Version: 2.1
2
+ Name: puyaisp
3
+ Version: 1.4.0
4
+ Summary: Programming Tool for PUYA PY32F0xx 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: PUYA,PY32F002A,PY32F003,PY32F030,microcontroller
34
+ Classifier: Development Status :: 5 - Production/Stable
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
+ # puyaisp - Programming Tool for PUYA PY32F0xx Microcontrollers
46
+ ## Description
47
+ With this tool, PUYA microcontrollers of the series PY32F0xx (and maybe other PY32) can be flashed via a simple USB-to-serial converter by utilizing the factory built-in embedded UART bootloader.
48
+
49
+ ## Preparations
50
+ If necessary, a driver for the USB-to-serial converter used must be installed.
51
+
52
+ ## Installation
53
+ - Install [Python3](https://www.pythontutorial.net/getting-started/install-python/).
54
+ - Install [pip](https://pip.pypa.io/en/stable/installation/).
55
+ - Install puyaisp:
56
+
57
+ ```
58
+ pip install puyaisp
59
+ ```
60
+
61
+ ## Usage
62
+ Connect your USB-to-serial converter to your PY32F0xx MCU as follows:
63
+
64
+ ```
65
+ USB2SERIAL PY32F0xx
66
+ +--------+ +-------------------+
67
+ | RXD| <--- |PA2 or PA9 or PA14|
68
+ | TXD| ---> |PA3 or PA10 or PA15|
69
+ | VDD| ---> |VDD |
70
+ | GND| ---> |GND |
71
+ +--------+ +-------------------+
72
+ ```
73
+
74
+ Set your MCU to bootloader mode by using ONE of the following methods:
75
+ - Disconnect your USB-to-serial converter, pull BOOT0 pin (PF4) to VCC (or press and hold the BOOT button, if your board has one), then connect the converter to your USB port. BOOT0 pin (or BOOT button) can be released now.
76
+ - Connect your USB-to-serial converter to your USB port. Pull BOOT0 pin (PF4) to VCC, then pull nRST (PF2) 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).
77
+
78
+ ```
79
+ Usage: puyaisp [-h] [-u] [-l] [-e] [-o] [-G] [-R] [-f FLASH]
80
+
81
+ Optional arguments:
82
+ -h, --help show this help message and exit
83
+ -u, --unlock unlock chip (remove read protection)
84
+ -l, --lock lock chip (set read protection)
85
+ -e, --erase perform chip erase (implied with -f)
86
+ -o, --rstoption reset option bytes
87
+ -G, --nrstgpio make nRST pin a GPIO pin
88
+ -R, --nrstreset make nRST pin a RESET pin
89
+ -f FLASH, --flash FLASH write BIN file to flash and verify
90
+
91
+ Example:
92
+ puyaisp -f firmware.bin
93
+ ```
94
+
95
+ ## Links
96
+ - [MCU Flash Tools](https://github.com/wagiminator/MCU-Flash-Tools)
97
+ - [MCU Templates](https://github.com/wagiminator/MCU-Templates)
98
+ - [MCU Development Boards](https://github.com/wagiminator/Development-Boards)
99
+ - [AVR Development Boards](https://github.com/wagiminator/AVR-Development-Boards)
100
+ - [AVR Programmers](https://github.com/wagiminator/AVR-Programmer)
101
+ - [SAMD Development Boards](https://github.com/wagiminator/SAMD-Development-Boards)
@@ -0,0 +1,57 @@
1
+ # puyaisp - Programming Tool for PUYA PY32F0xx Microcontrollers
2
+ ## Description
3
+ With this tool, PUYA microcontrollers of the series PY32F0xx (and maybe other PY32) can be flashed via a simple USB-to-serial converter by utilizing the factory built-in embedded UART bootloader.
4
+
5
+ ## Preparations
6
+ If necessary, a driver for the USB-to-serial converter used must be installed.
7
+
8
+ ## Installation
9
+ - Install [Python3](https://www.pythontutorial.net/getting-started/install-python/).
10
+ - Install [pip](https://pip.pypa.io/en/stable/installation/).
11
+ - Install puyaisp:
12
+
13
+ ```
14
+ pip install puyaisp
15
+ ```
16
+
17
+ ## Usage
18
+ Connect your USB-to-serial converter to your PY32F0xx MCU as follows:
19
+
20
+ ```
21
+ USB2SERIAL PY32F0xx
22
+ +--------+ +-------------------+
23
+ | RXD| <--- |PA2 or PA9 or PA14|
24
+ | TXD| ---> |PA3 or PA10 or PA15|
25
+ | VDD| ---> |VDD |
26
+ | GND| ---> |GND |
27
+ +--------+ +-------------------+
28
+ ```
29
+
30
+ Set your MCU to bootloader mode by using ONE of the following methods:
31
+ - Disconnect your USB-to-serial converter, pull BOOT0 pin (PF4) to VCC (or press and hold the BOOT button, if your board has one), then connect the converter to your USB port. BOOT0 pin (or BOOT button) can be released now.
32
+ - Connect your USB-to-serial converter to your USB port. Pull BOOT0 pin (PF4) to VCC, then pull nRST (PF2) 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).
33
+
34
+ ```
35
+ Usage: puyaisp [-h] [-u] [-l] [-e] [-o] [-G] [-R] [-f FLASH]
36
+
37
+ Optional arguments:
38
+ -h, --help show this help message and exit
39
+ -u, --unlock unlock chip (remove read protection)
40
+ -l, --lock lock chip (set read protection)
41
+ -e, --erase perform chip erase (implied with -f)
42
+ -o, --rstoption reset option bytes
43
+ -G, --nrstgpio make nRST pin a GPIO pin
44
+ -R, --nrstreset make nRST pin a RESET pin
45
+ -f FLASH, --flash FLASH write BIN file to flash and verify
46
+
47
+ Example:
48
+ puyaisp -f firmware.bin
49
+ ```
50
+
51
+ ## Links
52
+ - [MCU Flash Tools](https://github.com/wagiminator/MCU-Flash-Tools)
53
+ - [MCU Templates](https://github.com/wagiminator/MCU-Templates)
54
+ - [MCU Development Boards](https://github.com/wagiminator/Development-Boards)
55
+ - [AVR Development Boards](https://github.com/wagiminator/AVR-Development-Boards)
56
+ - [AVR Programmers](https://github.com/wagiminator/AVR-Programmer)
57
+ - [SAMD Development Boards](https://github.com/wagiminator/SAMD-Development-Boards)
@@ -0,0 +1 @@
1
+ from .puyaisp import _main
@@ -0,0 +1,392 @@
1
+ #!/usr/bin/env python3
2
+ # ===================================================================================
3
+ # Project: puyaisp - Programming Tool for PUYA PY32F0xx Microcontrollers
4
+ # Version: v1.4
5
+ # Year: 2023
6
+ # Author: Stefan Wagner
7
+ # Github: https://github.com/wagiminator
8
+ # License: MIT License
9
+ # ===================================================================================
10
+ #
11
+ # Description:
12
+ # ------------
13
+ # Simple Python tool for flashing PY32F0xx (and maybe other PY32) microcontrollers
14
+ # via USB-to-serial converter utilizing the factory built-in embedded boot loader.
15
+ #
16
+ # Dependencies:
17
+ # -------------
18
+ # - pyserial
19
+ #
20
+ # Operating Instructions:
21
+ # -----------------------
22
+ # You need to install PySerial to use puyaisp.
23
+ # Install it via "python3 -m pip install pyserial".
24
+ # You may need to install a driver for your USB-to-serial converter.
25
+ #
26
+ # Connect your USB-to-serial converter to your MCU:
27
+ # USB2SERIAL PY32F0xx
28
+ # RXD <--- PA2 or PA9 or PA14
29
+ # TXD ---> PA3 or PA10 or PA15
30
+ # VCC ---> VCC
31
+ # GND ---> GND
32
+ #
33
+ # Set your MCU to bootloader mode by using ONE of the following methods:
34
+ # - Disconnect your USB-to-serial converter, pull BOOT0 pin (PF4) to VCC (or press
35
+ # and hold the BOOT button, if your board has one), then connect the converter to
36
+ # your USB port. BOOT0 pin (or BOOT button) can be released now.
37
+ # - Connect your USB-to-serial converter to your USB port. Pull BOOT0 pin (PF4)
38
+ # to VCC, then pull nRST (PF2) shortly to GND (or press and hold the BOOT button,
39
+ # then press and release the RESET button and then release the BOOT button, if
40
+ # your board has them).
41
+ # These steps are not necessary when using a CH340X USB-to-serial converter with
42
+ # control lines for nRST and BOOT0. In this case, the software automatically puts
43
+ # the MCU into bootloader mode.
44
+ #
45
+ # Run "python3 puyaisp.py -f firmware.bin".
46
+
47
+ # If the PID/VID of the USB-to-Serial converter is known, it can be defined here,
48
+ # which can make the auto-detection a lot faster. If not, comment out or delete.
49
+ #PY_VID = '1A86'
50
+ #PY_PID = '7523'
51
+
52
+ # Define BAUD rate here, range: 4800 - 1000000, default and recommended: 115200
53
+ PY_BAUD = 115200
54
+
55
+ # Libraries
56
+ import sys
57
+ import time
58
+ import argparse
59
+ import serial
60
+ from serial import Serial
61
+ from serial.tools.list_ports import comports
62
+
63
+ # ===================================================================================
64
+ # Main Function
65
+ # ===================================================================================
66
+
67
+ def _main():
68
+ # Parse command line arguments
69
+ parser = argparse.ArgumentParser(description='Minimal command line interface for PY32 IAP')
70
+ parser.add_argument('-u', '--unlock', action='store_true', help='unlock chip (remove read protection)')
71
+ parser.add_argument('-l', '--lock', action='store_true', help='lock chip (set read protection)')
72
+ parser.add_argument('-e', '--erase', action='store_true', help='perform chip erase (implied with -f)')
73
+ parser.add_argument('-o', '--rstoption',action='store_true', help='reset option bytes')
74
+ parser.add_argument('-G', '--nrstgpio', action='store_true', help='make nRST pin a GPIO pin')
75
+ parser.add_argument('-R', '--nrstreset',action='store_true', help='make nRST pin a RESET pin')
76
+ parser.add_argument('-f', '--flash', help='write BIN file to flash and verify')
77
+ args = parser.parse_args(sys.argv[1:])
78
+
79
+ # Check arguments
80
+ if not any( (args.rstoption, args.unlock, args.lock, args.erase, args.nrstgpio, args.nrstreset, args.flash) ):
81
+ print('No arguments - no action!')
82
+ sys.exit(0)
83
+
84
+ # Establish connection to MCU via USB-to-serial converter
85
+ try:
86
+ print('Connecting to MCU via USB-to-serial converter ...')
87
+ isp = Programmer()
88
+ print('SUCCESS: Connection established via', isp.port + '.')
89
+ except Exception as ex:
90
+ sys.stderr.write('ERROR: ' + str(ex) + '!\n')
91
+ sys.exit(1)
92
+
93
+ # Performing actions
94
+ try:
95
+ # Get chip info
96
+ print('Getting chip info ...')
97
+ isp.readinfo()
98
+ if isp.pid == PY_CHIP_PID:
99
+ print('SUCCESS: Found PY32F0xx with bootloader v' + isp.verstr + '.')
100
+ else:
101
+ print('WARNING: Chip with PID 0x%04x is not a PY32F0xx!' % isp.pid)
102
+
103
+ # Unlock chip
104
+ if args.unlock:
105
+ print('Unlocking chip ...')
106
+ isp.unlock()
107
+ print('SUCCESS: Chip is unlocked.')
108
+ print('INFO: Other options are ignored!')
109
+ isp.reset()
110
+ print('DONE.')
111
+ sys.exit(0)
112
+
113
+ # Read option bytes and check, if chip is locked
114
+ print('Reading OPTION bytes ...')
115
+ isp.readoption()
116
+ print('SUCCESS:', isp.optionstr + '.')
117
+
118
+ # Perform chip erase
119
+ if (args.erase) or (args.flash is not None):
120
+ print('Performing chip erase ...')
121
+ isp.erase()
122
+ print('SUCCESS: Chip is erased.')
123
+
124
+ # Flash binary file
125
+ if args.flash is not None:
126
+ print('Flashing', args.flash, 'to MCU ...')
127
+ with open(args.flash, 'rb') as f: data = f.read()
128
+ isp.writeflash(PY_CODE_ADDR, data)
129
+ print('Verifying ...')
130
+ isp.verifyflash(PY_CODE_ADDR, data)
131
+ print('SUCCESS:', len(data), 'bytes written and verified.')
132
+
133
+ # Manipulate OPTION bytes (only for identified chips)
134
+ if isp.pid == PY_CHIP_PID and any( (args.rstoption, args.nrstgpio, args.nrstreset, args.lock) ):
135
+ if args.rstoption:
136
+ print('Setting OPTION bytes to default values ...')
137
+ isp.resetoption()
138
+ if args.nrstgpio:
139
+ print('Setting nRST pin as GPIO in OPTION bytes ...')
140
+ isp.nrst2gpio()
141
+ if args.nrstreset:
142
+ print('Setting nRST pin as RESET in OPTION bytes ...')
143
+ isp.nrst2reset()
144
+ if args.lock:
145
+ print('Setting read protection in OPTION BYTES ...')
146
+ isp.lock()
147
+ print('Writing OPTION bytes ...')
148
+ isp.writeoption()
149
+ print('SUCCESS: OPTION bytes written.')
150
+ isp.reset()
151
+ else:
152
+ isp.run()
153
+
154
+ except Exception as ex:
155
+ sys.stderr.write('ERROR: ' + str(ex) + '!\n')
156
+ isp.reset()
157
+ sys.exit(1)
158
+
159
+ print('DONE.')
160
+ sys.exit(0)
161
+
162
+ # ===================================================================================
163
+ # Programmer Class
164
+ # ===================================================================================
165
+
166
+ class Programmer(Serial):
167
+ def __init__(self):
168
+ # BAUD rate: 4800 - 1000000bps (default: 115200), will be auto-detected
169
+ # Data frame: 1 start bit, 8 data bit, 1 parity bit set to even, 1 stop bit
170
+ super().__init__(baudrate = PY_BAUD, parity = serial.PARITY_EVEN, timeout = 1)
171
+ self.identify()
172
+
173
+ # Identify port of programmer and enter programming mode
174
+ def identify(self):
175
+ for p in comports():
176
+ if (('PY_VID' not in globals()) or (PY_VID in p.hwid)) and (('PY_PID' not in globals()) or (PY_PID in p.hwid)):
177
+ self.port = p.device
178
+ try:
179
+ self.open()
180
+ except:
181
+ continue
182
+ self.boot()
183
+ self.reset_input_buffer()
184
+ self.write([PY_SYNCH])
185
+ if not self.checkreply():
186
+ self.close()
187
+ continue
188
+ return
189
+ raise Exception('No MCU in boot mode found')
190
+
191
+ # Send command
192
+ def sendcommand(self, command):
193
+ self.write([command, command ^ 0xff])
194
+ if not self.checkreply():
195
+ raise Exception('Device has not acknowledged the command 0x%02x' % command)
196
+
197
+ # Send address
198
+ def sendaddress(self, addr):
199
+ stream = addr.to_bytes(4, byteorder='big')
200
+ parity = 0x00
201
+ for x in range(4):
202
+ parity ^= stream[x]
203
+ self.write(stream)
204
+ self.write([parity])
205
+ if not self.checkreply():
206
+ raise Exception('Failed to send address')
207
+
208
+ # Check if device acknowledged
209
+ def checkreply(self):
210
+ reply = self.read(1)
211
+ return (len(reply) == 1 and reply[0] == PY_REPLY_ACK)
212
+
213
+ #--------------------------------------------------------------------------------
214
+
215
+ # Start bootloader
216
+ def boot(self):
217
+ self.rts = False
218
+ self.dtr = False
219
+ self.rts = True
220
+ time.sleep(0.01)
221
+ self.rts = False
222
+ time.sleep(0.01)
223
+
224
+ # Reset and disconnect
225
+ def reset(self):
226
+ self.dtr = True
227
+ self.rts = True
228
+ time.sleep(0.01)
229
+ self.rts = False
230
+ self.close()
231
+
232
+ # Start firmware and disconnect
233
+ def run(self):
234
+ self.sendcommand(PY_CMD_GO)
235
+ self.sendaddress(PY_CODE_ADDR)
236
+ self.dtr = True
237
+ self.close()
238
+
239
+ #--------------------------------------------------------------------------------
240
+
241
+ # Read info stream
242
+ def readinfostream(self, command):
243
+ self.sendcommand(command)
244
+ size = self.read(1)[0]
245
+ stream = self.read(size + 1)
246
+ if not self.checkreply():
247
+ raise Exception('Failed to read info')
248
+ return stream
249
+
250
+ # Get chip info
251
+ def readinfo(self):
252
+ self.ver = self.readinfostream(PY_CMD_GET)[0]
253
+ self.verstr = '%x.%x' % (self.ver >> 4, self.ver & 7)
254
+ self.pid = int.from_bytes(self.readinfostream(PY_CMD_PID), byteorder='big')
255
+
256
+ # Read UID
257
+ def readuid(self):
258
+ return self.readflash(PY_UID_ADDR, 128)
259
+
260
+ # Read OPTION bytes
261
+ def readoption(self):
262
+ try:
263
+ self.option = list(self.readflash(PY_OPTION_ADDR, 16))
264
+ except:
265
+ raise Exception('Chip is locked')
266
+ self.optionstr = 'OPTR: 0x%04x, SDKR: 0x%04x, WRPR: 0x%04x' % \
267
+ (( (self.option[ 0] << 8) + self.option[ 1], \
268
+ (self.option[ 4] << 8) + self.option[ 5], \
269
+ (self.option[12] << 8) + self.option[13] ))
270
+
271
+ # Write OPTION bytes
272
+ def writeoption(self):
273
+ self.writeflash(PY_OPTION_ADDR, self.option)
274
+
275
+ # Reset OPTION bytes
276
+ def resetoption(self):
277
+ self.option = list(PY_OPTION_DEFAULT)
278
+
279
+ # Set read protection in OPTION bytes
280
+ def lock(self):
281
+ self.option[0] = 0x55
282
+ self.option[2] = 0xaa
283
+
284
+ # Set nRST pin as GPIO in OPTION bytes
285
+ def nrst2gpio(self):
286
+ self.option[1] |= 0x40
287
+ self.option[3] &= 0xbf
288
+
289
+ # Set nRST pin as RESET in OPTION bytes
290
+ def nrst2reset(self):
291
+ self.option[1] &= 0xbf
292
+ self.option[3] |= 0x40
293
+
294
+ # Unlock (clear) chip and reset
295
+ def unlock(self):
296
+ self.sendcommand(PY_CMD_R_UNLOCK)
297
+ if not self.checkreply():
298
+ raise Exception('Failed to unlock chip')
299
+
300
+ #--------------------------------------------------------------------------------
301
+
302
+ # Erase whole chip
303
+ def erase(self):
304
+ self.sendcommand(PY_CMD_ERASE)
305
+ self.write(b'\xff\xff\x00')
306
+ if not self.checkreply():
307
+ raise Exception('Failed to erase chip')
308
+
309
+ # Read flash
310
+ def readflash(self, addr, size):
311
+ data = bytes()
312
+ while size > 0:
313
+ blocksize = size
314
+ if blocksize > PY_BLOCKSIZE: blocksize = PY_BLOCKSIZE
315
+ self.sendcommand(PY_CMD_READ)
316
+ self.sendaddress(addr)
317
+ self.sendcommand(blocksize - 1)
318
+ data += self.read(blocksize)
319
+ addr += blocksize
320
+ size -= blocksize
321
+ return data
322
+
323
+ # Write flash
324
+ def writeflash(self, addr, data):
325
+ size = len(data)
326
+ while size > 0:
327
+ blocksize = size
328
+ if blocksize > PY_BLOCKSIZE: blocksize = PY_BLOCKSIZE
329
+ block = data[:blocksize]
330
+ parity = blocksize - 1
331
+ for x in range(blocksize):
332
+ parity ^= block[x]
333
+ self.sendcommand(PY_CMD_WRITE)
334
+ self.sendaddress(addr)
335
+ self.write([blocksize - 1])
336
+ self.write(block)
337
+ self.write([parity])
338
+ if not self.checkreply():
339
+ raise Exception('Failed to write to address 0x%08x' % addr)
340
+ data = data[blocksize:]
341
+ addr += blocksize
342
+ size -= blocksize
343
+
344
+ # Verify flash
345
+ def verifyflash(self, addr, data):
346
+ flash = self.readflash(addr, len(data))
347
+ if set(flash) != set(data):
348
+ raise Exception('Verification failed')
349
+
350
+ # ===================================================================================
351
+ # Device Constants
352
+ # ===================================================================================
353
+
354
+ # Device and Memory constants
355
+ PY_CHIP_PID = 0x440
356
+ PY_BLOCKSIZE = 128
357
+ PY_FLASH_ADDR = 0x08000000
358
+ PY_CODE_ADDR = 0x08000000
359
+ PY_SRAM_ADDR = 0x20000000
360
+ PY_BOOT_ADDR = 0x1fff0000
361
+ PY_UID_ADDR = 0x1fff0e00
362
+ PY_OPTION_ADDR = 0x1fff0e80
363
+ PY_CONFIG_ADDR = 0x1fff0f00
364
+
365
+ # Command codes
366
+ PY_CMD_GET = 0x00
367
+ PY_CMD_VER = 0x01
368
+ PY_CMD_PID = 0x02
369
+ PY_CMD_READ = 0x11
370
+ PY_CMD_WRITE = 0x31
371
+ PY_CMD_ERASE = 0x44
372
+ PY_CMD_GO = 0x21
373
+ PY_CMD_W_LOCK = 0x63
374
+ PY_CMD_W_UNLOCK = 0x73
375
+ PY_CMD_R_LOCK = 0x82
376
+ PY_CMD_R_UNLOCK = 0x92
377
+
378
+ # Reply codes
379
+ PY_REPLY_ACK = 0x79
380
+ PY_REPLY_NACK = 0x1f
381
+ PY_REPLY_BUSY = 0xaa
382
+
383
+ # Other codes
384
+ PY_SYNCH = 0x7f
385
+
386
+ # Default option bytes
387
+ PY_OPTION_DEFAULT = b'\xaa\xbe\x55\x41\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\x00\x00'
388
+
389
+ # ===================================================================================
390
+
391
+ if __name__ == "__main__":
392
+ _main()
@@ -0,0 +1,101 @@
1
+ Metadata-Version: 2.1
2
+ Name: puyaisp
3
+ Version: 1.4.0
4
+ Summary: Programming Tool for PUYA PY32F0xx 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: PUYA,PY32F002A,PY32F003,PY32F030,microcontroller
34
+ Classifier: Development Status :: 5 - Production/Stable
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
+ # puyaisp - Programming Tool for PUYA PY32F0xx Microcontrollers
46
+ ## Description
47
+ With this tool, PUYA microcontrollers of the series PY32F0xx (and maybe other PY32) can be flashed via a simple USB-to-serial converter by utilizing the factory built-in embedded UART bootloader.
48
+
49
+ ## Preparations
50
+ If necessary, a driver for the USB-to-serial converter used must be installed.
51
+
52
+ ## Installation
53
+ - Install [Python3](https://www.pythontutorial.net/getting-started/install-python/).
54
+ - Install [pip](https://pip.pypa.io/en/stable/installation/).
55
+ - Install puyaisp:
56
+
57
+ ```
58
+ pip install puyaisp
59
+ ```
60
+
61
+ ## Usage
62
+ Connect your USB-to-serial converter to your PY32F0xx MCU as follows:
63
+
64
+ ```
65
+ USB2SERIAL PY32F0xx
66
+ +--------+ +-------------------+
67
+ | RXD| <--- |PA2 or PA9 or PA14|
68
+ | TXD| ---> |PA3 or PA10 or PA15|
69
+ | VDD| ---> |VDD |
70
+ | GND| ---> |GND |
71
+ +--------+ +-------------------+
72
+ ```
73
+
74
+ Set your MCU to bootloader mode by using ONE of the following methods:
75
+ - Disconnect your USB-to-serial converter, pull BOOT0 pin (PF4) to VCC (or press and hold the BOOT button, if your board has one), then connect the converter to your USB port. BOOT0 pin (or BOOT button) can be released now.
76
+ - Connect your USB-to-serial converter to your USB port. Pull BOOT0 pin (PF4) to VCC, then pull nRST (PF2) 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).
77
+
78
+ ```
79
+ Usage: puyaisp [-h] [-u] [-l] [-e] [-o] [-G] [-R] [-f FLASH]
80
+
81
+ Optional arguments:
82
+ -h, --help show this help message and exit
83
+ -u, --unlock unlock chip (remove read protection)
84
+ -l, --lock lock chip (set read protection)
85
+ -e, --erase perform chip erase (implied with -f)
86
+ -o, --rstoption reset option bytes
87
+ -G, --nrstgpio make nRST pin a GPIO pin
88
+ -R, --nrstreset make nRST pin a RESET pin
89
+ -f FLASH, --flash FLASH write BIN file to flash and verify
90
+
91
+ Example:
92
+ puyaisp -f firmware.bin
93
+ ```
94
+
95
+ ## Links
96
+ - [MCU Flash Tools](https://github.com/wagiminator/MCU-Flash-Tools)
97
+ - [MCU Templates](https://github.com/wagiminator/MCU-Templates)
98
+ - [MCU Development Boards](https://github.com/wagiminator/Development-Boards)
99
+ - [AVR Development Boards](https://github.com/wagiminator/AVR-Development-Boards)
100
+ - [AVR Programmers](https://github.com/wagiminator/AVR-Programmer)
101
+ - [SAMD Development Boards](https://github.com/wagiminator/SAMD-Development-Boards)
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ puyaisp/__init__.py
6
+ puyaisp/puyaisp.py
7
+ puyaisp.egg-info/PKG-INFO
8
+ puyaisp.egg-info/SOURCES.txt
9
+ puyaisp.egg-info/dependency_links.txt
10
+ puyaisp.egg-info/entry_points.txt
11
+ puyaisp.egg-info/requires.txt
12
+ puyaisp.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ puyaisp = puyaisp:_main
@@ -0,0 +1 @@
1
+ pyserial
@@ -0,0 +1 @@
1
+ puyaisp
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "puyaisp"
7
+ version = "1.4.0"
8
+ authors = [
9
+ { name="Stefan Wagner", email="wagiminator@web.de" },
10
+ ]
11
+ maintainers = [
12
+ { name="Stefan Wagner", email="wagiminator@web.de" },
13
+ ]
14
+ description = "Programming Tool for PUYA PY32F0xx Microcontrollers"
15
+ readme = "README.md"
16
+ license = {file = "LICENSE"}
17
+ requires-python = ">=3.8"
18
+ dependencies = [
19
+ "pyserial",
20
+ ]
21
+ keywords = ["PUYA", "PY32F002A", "PY32F003", "PY32F030", "microcontroller"]
22
+ classifiers = [
23
+ "Development Status :: 5 - Production/Stable",
24
+ "Programming Language :: Python :: 3",
25
+ "License :: OSI Approved :: MIT License",
26
+ "Operating System :: OS Independent",
27
+ "Intended Audience :: Developers",
28
+ "Topic :: Software Development :: Embedded Systems",
29
+ ]
30
+
31
+ [project.scripts]
32
+ puyaisp = "puyaisp:_main"
33
+
34
+ [project.urls]
35
+ Homepage = "https://wagiminator.github.io/"
36
+ Repository = "https://github.com/wagiminator/MCU-Flash-Tools"
37
+ Issues = "https://github.com/wagiminator/MCU-Flash-Tools/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
puyaisp-1.4.0/setup.py ADDED
@@ -0,0 +1,15 @@
1
+ from setuptools import setup
2
+
3
+ setup(
4
+ name='puyaisp',
5
+ version='1.4.0',
6
+ description='Programming Tool for PUYA PY32F0xx Microcontrollers',
7
+ url='https://github.com/wagiminator/MCU-Flash-Tools',
8
+ author='Stefan Wagner',
9
+ author_email='wagiminator@web.de',
10
+ license='MIT License',
11
+ packages=['puyaisp'],
12
+ install_requires=[
13
+ 'pyserial',
14
+ ],
15
+ )