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 +21 -0
- puyaisp-1.4.0/PKG-INFO +101 -0
- puyaisp-1.4.0/README.md +57 -0
- puyaisp-1.4.0/puyaisp/__init__.py +1 -0
- puyaisp-1.4.0/puyaisp/puyaisp.py +392 -0
- puyaisp-1.4.0/puyaisp.egg-info/PKG-INFO +101 -0
- puyaisp-1.4.0/puyaisp.egg-info/SOURCES.txt +12 -0
- puyaisp-1.4.0/puyaisp.egg-info/dependency_links.txt +1 -0
- puyaisp-1.4.0/puyaisp.egg-info/entry_points.txt +2 -0
- puyaisp-1.4.0/puyaisp.egg-info/requires.txt +1 -0
- puyaisp-1.4.0/puyaisp.egg-info/top_level.txt +1 -0
- puyaisp-1.4.0/pyproject.toml +37 -0
- puyaisp-1.4.0/setup.cfg +4 -0
- puyaisp-1.4.0/setup.py +15 -0
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)
|
puyaisp-1.4.0/README.md
ADDED
|
@@ -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 @@
|
|
|
1
|
+
|
|
@@ -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"
|
puyaisp-1.4.0/setup.cfg
ADDED
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
|
+
)
|