rvprog 1.5.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.
rvprog-1.5.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.
rvprog-1.5.0/PKG-INFO ADDED
@@ -0,0 +1,113 @@
1
+ Metadata-Version: 2.1
2
+ Name: rvprog
3
+ Version: 1.5.0
4
+ Summary: Programming Tool for WCH-LinkE and CH32Vxxx and CH32Xxxx
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: WCH,CH552,CH32V003,CH32X035,RISC-V,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: pyusb
44
+
45
+ # rvprog - Programming Tool for WCH-LinkE and CH32Vxxx and CH32Xxxx
46
+ ## Description
47
+ With this tool, the WCH RISC-V microcontrollers CH32Vxxx and CH32Xxxx can be programmed with the [WCH-LinkE](http://www.wch-ic.com/products/WCH-Link.html) (pay attention to the "E" in the name) via its serial debug interface.
48
+
49
+ ## Preparations
50
+ To use the WCH-Link on Linux, you need to grant access permissions beforehand by executing the following commands:
51
+ ```
52
+ echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="8010", MODE="666"' | sudo tee /etc/udev/rules.d/99-WCH-LinkE.rules
53
+ echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="8012", MODE="666"' | sudo tee -a /etc/udev/rules.d/99-WCH-LinkE.rules
54
+ sudo udevadm control --reload-rules
55
+ ```
56
+
57
+ On Windows, if you need to you can install the WinUSB driver over the WCH interface 1 using the [Zadig Tool](https://zadig.akeo.ie/).
58
+
59
+ ## Installation
60
+ - Install [Python3](https://www.pythontutorial.net/getting-started/install-python/).
61
+ - Install [pip](https://pip.pypa.io/en/stable/installation/).
62
+ - Install rvprog:
63
+
64
+ ```
65
+ pip install rvprog
66
+ ```
67
+
68
+ ## Usage
69
+ To upload firmware, you should make the following connections to the WCH-LinkE (SWCLK is not present on the CH32V003 and therefore does not need to be connected):
70
+
71
+ ```
72
+ WCH-LinkE CH32V/X
73
+ +-------+ +-------+
74
+ | SWCLK| ---> |SWCLK |
75
+ | SWDIO| <--> |SWDIO |
76
+ | GND| ---> |GND |
77
+ | 3V3| ---> |VDD |
78
+ +-------+ +-------+
79
+ ```
80
+
81
+ If the blue LED on the WCH-LinkE remains illuminated once it is connected to the USB port, it means that the device is currently in ARM mode and must be switched to RISC-V mode initially. There are a few ways to accomplish this:
82
+ - You can utilize the rvprog tool with the -v option (see below).
83
+ - Alternatively, you can select "WCH-LinkRV" in the software provided by WCH, such as MounRiver Studio or WCH-LinkUtility.
84
+ - Another option is to hold down the ModeS button on the device while plugging it into the USB port.
85
+
86
+ More information can be found in the [WCH-Link User Manual](http://www.wch-ic.com/downloads/WCH-LinkUserManual_PDF.html).
87
+
88
+ ```
89
+ Usage: rvprog [-h] [-a] [-v] [-b] [-u] [-l] [-e] [-G] [-R] [-f FLASH]
90
+
91
+ Optional arguments:
92
+ -h, --help show help message and exit
93
+ -a, --armmode switch WCH-Link to ARM mode
94
+ -v, --rvmode switch WCH-Link to RISC-V mode
95
+ -b, --unbrick unbrick chip
96
+ -u, --unlock unlock chip (remove read protection)
97
+ -l, --lock lock chip (set read protection)
98
+ -e, --erase perform a whole chip erase
99
+ -G, --pingpio make nRST pin a GPIO pin (CH32V003 only)
100
+ -R, --pinreset make nRST pin a reset pin (CH32V003 only)
101
+ -f FLASH, --flash FLASH write BIN file to flash
102
+
103
+ Example:
104
+ rvprog -f firmware.bin
105
+ ```
106
+
107
+ ## Links
108
+ - [MCU Flash Tools](https://github.com/wagiminator/MCU-Flash-Tools)
109
+ - [MCU Templates](https://github.com/wagiminator/MCU-Templates)
110
+ - [MCU Development Boards](https://github.com/wagiminator/Development-Boards)
111
+ - [AVR Development Boards](https://github.com/wagiminator/AVR-Development-Boards)
112
+ - [AVR Programmers](https://github.com/wagiminator/AVR-Programmer)
113
+ - [SAMD Development Boards](https://github.com/wagiminator/SAMD-Development-Boards)
rvprog-1.5.0/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # rvprog - Programming Tool for WCH-LinkE and CH32Vxxx and CH32Xxxx
2
+ ## Description
3
+ With this tool, the WCH RISC-V microcontrollers CH32Vxxx and CH32Xxxx can be programmed with the [WCH-LinkE](http://www.wch-ic.com/products/WCH-Link.html) (pay attention to the "E" in the name) via its serial debug interface.
4
+
5
+ ## Preparations
6
+ To use the WCH-Link on Linux, you need to grant access permissions beforehand by executing the following commands:
7
+ ```
8
+ echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="8010", MODE="666"' | sudo tee /etc/udev/rules.d/99-WCH-LinkE.rules
9
+ echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="8012", MODE="666"' | sudo tee -a /etc/udev/rules.d/99-WCH-LinkE.rules
10
+ sudo udevadm control --reload-rules
11
+ ```
12
+
13
+ On Windows, if you need to you can install the WinUSB driver over the WCH interface 1 using the [Zadig Tool](https://zadig.akeo.ie/).
14
+
15
+ ## Installation
16
+ - Install [Python3](https://www.pythontutorial.net/getting-started/install-python/).
17
+ - Install [pip](https://pip.pypa.io/en/stable/installation/).
18
+ - Install rvprog:
19
+
20
+ ```
21
+ pip install rvprog
22
+ ```
23
+
24
+ ## Usage
25
+ To upload firmware, you should make the following connections to the WCH-LinkE (SWCLK is not present on the CH32V003 and therefore does not need to be connected):
26
+
27
+ ```
28
+ WCH-LinkE CH32V/X
29
+ +-------+ +-------+
30
+ | SWCLK| ---> |SWCLK |
31
+ | SWDIO| <--> |SWDIO |
32
+ | GND| ---> |GND |
33
+ | 3V3| ---> |VDD |
34
+ +-------+ +-------+
35
+ ```
36
+
37
+ If the blue LED on the WCH-LinkE remains illuminated once it is connected to the USB port, it means that the device is currently in ARM mode and must be switched to RISC-V mode initially. There are a few ways to accomplish this:
38
+ - You can utilize the rvprog tool with the -v option (see below).
39
+ - Alternatively, you can select "WCH-LinkRV" in the software provided by WCH, such as MounRiver Studio or WCH-LinkUtility.
40
+ - Another option is to hold down the ModeS button on the device while plugging it into the USB port.
41
+
42
+ More information can be found in the [WCH-Link User Manual](http://www.wch-ic.com/downloads/WCH-LinkUserManual_PDF.html).
43
+
44
+ ```
45
+ Usage: rvprog [-h] [-a] [-v] [-b] [-u] [-l] [-e] [-G] [-R] [-f FLASH]
46
+
47
+ Optional arguments:
48
+ -h, --help show help message and exit
49
+ -a, --armmode switch WCH-Link to ARM mode
50
+ -v, --rvmode switch WCH-Link to RISC-V mode
51
+ -b, --unbrick unbrick chip
52
+ -u, --unlock unlock chip (remove read protection)
53
+ -l, --lock lock chip (set read protection)
54
+ -e, --erase perform a whole chip erase
55
+ -G, --pingpio make nRST pin a GPIO pin (CH32V003 only)
56
+ -R, --pinreset make nRST pin a reset pin (CH32V003 only)
57
+ -f FLASH, --flash FLASH write BIN file to flash
58
+
59
+ Example:
60
+ rvprog -f firmware.bin
61
+ ```
62
+
63
+ ## Links
64
+ - [MCU Flash Tools](https://github.com/wagiminator/MCU-Flash-Tools)
65
+ - [MCU Templates](https://github.com/wagiminator/MCU-Templates)
66
+ - [MCU Development Boards](https://github.com/wagiminator/Development-Boards)
67
+ - [AVR Development Boards](https://github.com/wagiminator/AVR-Development-Boards)
68
+ - [AVR Programmers](https://github.com/wagiminator/AVR-Programmer)
69
+ - [SAMD Development Boards](https://github.com/wagiminator/SAMD-Development-Boards)
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "rvprog"
7
+ version = "1.5.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 WCH-LinkE and CH32Vxxx and CH32Xxxx"
15
+ readme = "README.md"
16
+ license = {file = "LICENSE"}
17
+ requires-python = ">=3.8"
18
+ dependencies = [
19
+ "pyusb",
20
+ ]
21
+ keywords = ["WCH", "CH552", "CH32V003", "CH32X035", "RISC-V", "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
+ rvprog = "rvprog:_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 @@
1
+ from .rvprog import _main
@@ -0,0 +1,568 @@
1
+ #!/usr/bin/env python3
2
+ # ===================================================================================
3
+ # Project: rvprog - Programming Tool for WCH-LinkE and CH32Vxxx and CH32Xxxx.
4
+ # Version: v1.5
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 CH32V and CH32X microcontrollers using the WCH-LinkE
14
+ # or compatible programmers/debuggers. The code is based on CNLohr's minichlink.
15
+ # Currently supports: CH32V003, CH32V103, CH32V203, CH32V208, CH32V303, CH32V305,
16
+ # CH32V307, CH32X033, CH32X035.
17
+ #
18
+ # References:
19
+ # -----------
20
+ # - CNLohr minichlink: https://github.com/cnlohr/ch32v003fun/tree/master/minichlink
21
+ # - My mighty USB sniffer
22
+ #
23
+ # Dependencies:
24
+ # -------------
25
+ # - PyUSB
26
+ #
27
+ # Operating Instructions:
28
+ # -----------------------
29
+ # You need to install PyUSB to use rvprog. Install it via "python -m pip install pyusb".
30
+ #
31
+ # Linux users need permission to access the device. Run:
32
+ # echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="8010", MODE="666"' | sudo tee /etc/udev/rules.d/99-WCH-LinkE.rules
33
+ # echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="8012", MODE="666"' | sudo tee -a /etc/udev/rules.d/99-WCH-LinkE.rules
34
+ # sudo udevadm control --reload-rules
35
+ #
36
+ # Connect the WCH-LinkE to your PC and to your CH32Vxxx board. The WCH-LinkE must be
37
+ # in LinkRV mode (blue LED off)! If not, run: python rvprog.py -v
38
+ # Run:
39
+ # - python3 rvprog.py [-h] [-a] [-v] [-b] [-u] [-l] [-e] [-G] [-R] [-f FLASH]
40
+ # -h, --help show help message and exit
41
+ # -a, --armmode switch WCH-Link to ARM mode
42
+ # -v, --rvmode switch WCH-Link to RISC-V mode
43
+ # -b, --unbrick unbrick chip (CH32V003 only)
44
+ # -u, --unlock unlock chip (remove read protection)
45
+ # -l, --lock lock chip (set read protection)
46
+ # -e, --erase perform a whole chip erase
47
+ # -G, --pingpio make nRST pin a GPIO pin (CH32V003 only)
48
+ # -R, --pinreset make nRST pin a reset pin (CH32V003 only)
49
+ # -f FLASH, --flash FLASH write BIN file to flash
50
+ #
51
+ # - Example:
52
+ # python3 rvprog.py -f firmware.bin
53
+
54
+
55
+ import usb.core
56
+ import usb.util
57
+ import sys
58
+ import time
59
+ import argparse
60
+
61
+ # ===================================================================================
62
+ # Main Function
63
+ # ===================================================================================
64
+
65
+ def _main():
66
+ # Parse command line arguments
67
+ parser = argparse.ArgumentParser(description='Minimal command line interface for CH32Vxxx programming')
68
+ parser.add_argument('-a', '--armmode', action='store_true', help='switch WCH-LinkE to ARM mode')
69
+ parser.add_argument('-v', '--rvmode', action='store_true', help='switch WCH-LinkE to RISC-V mode')
70
+ parser.add_argument('-b', '--unbrick', action='store_true', help='unbrick chip (CH32V003 only)')
71
+ parser.add_argument('-u', '--unlock', action='store_true', help='unlock chip (remove read protection)')
72
+ parser.add_argument('-l', '--lock', action='store_true', help='lock chip (set read protection)')
73
+ parser.add_argument('-e', '--erase', action='store_true', help='perform a whole chip erase')
74
+ parser.add_argument('-G', '--pingpio', action='store_true', help='make nRST pin a GPIO pin (CH32V003 only)')
75
+ parser.add_argument('-R', '--pinreset', action='store_true', help='make nRST pin a reset pin (CH32V003 only)')
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.armmode, args.rvmode, args.unbrick, args.unlock, args.lock, args.erase, args.pingpio, args.pinreset, args.flash) ):
81
+ print('No arguments - no action!')
82
+ sys.exit(0)
83
+
84
+ # Switch WCH-Link to RISC-V mode
85
+ try:
86
+ if args.rvmode:
87
+ print('Searching for WCH-LinkE in ARM mode ...')
88
+ armlink = usb.core.find(idVendor = CH_VENDOR_ID, idProduct = CH_ARM_ID)
89
+ if armlink is None:
90
+ raise Exception('No WCH-LinkE in ARM mode found!')
91
+ print('SUCCESS: Found WCH-LinkE in ARM mode.')
92
+ print('Switching WCH-LinkE to RISC-V mode ...')
93
+ armlink.write(0x02, b'\x81\xff\x01\x52')
94
+ time.sleep(2)
95
+ print('DONE.')
96
+ except Exception as ex:
97
+ sys.stderr.write('ERROR: %s!\n' % str(ex))
98
+
99
+ # Establish connection to WCH-Link
100
+ try:
101
+ print('Searching for WCH-LinkE in RISC-V mode ...')
102
+ isp = Programmer()
103
+ print('SUCCESS: Found %s v%s in RISC-V mode.' % (isp.linkname, isp.linkversion))
104
+ except Exception as ex:
105
+ sys.stderr.write('ERROR: %s!\n' % str(ex))
106
+ sys.exit(1)
107
+
108
+ # Performing actions
109
+ try:
110
+ # Unbrick chip
111
+ if args.unbrick:
112
+ print('Unbricking chip ...')
113
+ isp.unbrick()
114
+ print('SUCCESS: Chip is unbricked.')
115
+
116
+ # Establish connection to target MCU
117
+ if any( (args.unlock, args.lock, args.erase, args.flash, args.pingpio, args.pinreset) ):
118
+ print('Connecting to MCU ...')
119
+ isp.connect()
120
+ print('SUCCESS: Connected to %s with %d bytes of flash.' % (isp.chipname, isp.flashsize))
121
+
122
+ # Unlock chip
123
+ if args.unlock:
124
+ print('Unlocking chip ...')
125
+ isp.unlock()
126
+ print('SUCCESS: Chip is unlocked.')
127
+
128
+ # Perform chip erase
129
+ if args.erase:
130
+ print('Performing whole chip erase ...')
131
+ isp.erase()
132
+ print('SUCCESS: Chip is erased.')
133
+
134
+ # Flash binary file
135
+ if args.flash is not None:
136
+ print('Flashing %s to %s ...' % (args.flash, isp.chipname))
137
+ with open(args.flash, 'rb') as f: data = f.read()
138
+ isp.flash_data(data)
139
+ print('SUCCESS: %d bytes written and verified.' % len(data))
140
+
141
+ # Make nRST pin a normal GPIO pin
142
+ if args.pingpio:
143
+ print('Configuring nRST pin as GPIO ...')
144
+ isp.setnrstasgpio(1)
145
+ print('SUCCESS: nRST pin is now a GPIO pin.')
146
+
147
+ # Make nRST pin a reset pin
148
+ if args.pinreset:
149
+ print('Configuring nRST pin as reset ...')
150
+ isp.setnrstasgpio(0)
151
+ print('SUCCESS: nRST pin is now a reset pin.')
152
+
153
+ # Lock chip
154
+ if args.lock:
155
+ print('Locking chip ...')
156
+ isp.lock()
157
+ print('SUCCESS: Chip is locked.')
158
+
159
+ # Switch device to ARM mode
160
+ if args.armmode:
161
+ print('Switching WCH-Link to ARM mode ...')
162
+ isp.exit()
163
+ isp.dev.write(CH_EP_OUT, b'\x81\xff\x01\x41')
164
+ print('DONE: Check if blue LED lights up!')
165
+ sys.exit(0)
166
+
167
+ isp.exit()
168
+
169
+ except Exception as ex:
170
+ sys.stderr.write('ERROR: %s!\n' % str(ex))
171
+ isp.exit()
172
+ sys.exit(1)
173
+
174
+ print('DONE.')
175
+ sys.exit(0)
176
+
177
+ # ===================================================================================
178
+ # Programmer Class
179
+ # ===================================================================================
180
+
181
+ class Programmer:
182
+ # Init programmer
183
+ def __init__(self):
184
+ # Find programmer
185
+ self.dev = usb.core.find(idVendor = CH_VENDOR_ID, idProduct = CH_PRODUCT_ID)
186
+ if self.dev is None:
187
+ raise Exception('WCH-LinkE not found. Check if device is in RISC-V mode')
188
+
189
+ # Clear receive buffers
190
+ self.clearreply()
191
+
192
+ # Get programmer info
193
+ reply = self.sendcommand(b'\x81\x0d\x01\x01')
194
+ if not reply[5] == 0x12:
195
+ raise Exception('Programmer is not a WCH-LinkE')
196
+ self.linkname = 'WCH-LinkE'
197
+ self.linkdevice = reply[5]
198
+ self.linkversion = '%d.%d' % (reply[3], reply[4])
199
+
200
+ # Connect programmer to MCU
201
+ def connect(self):
202
+ # Connect to target MCU and get type
203
+ success = 0
204
+ for i in range(3):
205
+ if i > 0:
206
+ print('Failed to connect, trying to unbrick MCU ...')
207
+ self.sendcommand(b'\x81\x0d\x01\x0f\x09')
208
+ reply = self.sendcommand(b'\x81\x0d\x01\x02')
209
+ if len(reply) < 8 or set(reply[:4]) == set((0x81, 0x55, 0x01, 0x01)):
210
+ time.sleep(0.2)
211
+ continue
212
+
213
+ # Get chip identification data
214
+ self.chipmark = reply[3]
215
+ self.chipseries = reply[4]
216
+ self.chiptype = reply[5]
217
+ self.chipid = (reply[4] << 8) + reply[5]
218
+ self.device = None
219
+
220
+ # Find device in dictionary
221
+ for d in DEVICES:
222
+ if d['id'] == self.chipid:
223
+ self.device = d
224
+ if self.device is None:
225
+ if not self.chipid == 0:
226
+ print('Unsupported chip (ID: 0x%04x)?' % self.chipid)
227
+ continue
228
+
229
+ # Success
230
+ self.chipname = self.device['name']
231
+ success = 1
232
+ break
233
+ if success == 0:
234
+ raise Exception('Failed to connect to target MCU')
235
+
236
+ # Read some chip data
237
+ reply = self.sendcommand((0x81, 0x11, 0x01, self.chipmark))
238
+ self.flashsize = int.from_bytes(reply[2:4], byteorder='big') * 1024
239
+
240
+ # Send command to programmer
241
+ def sendcommand(self, stream):
242
+ self.dev.write(CH_EP_OUT, stream)
243
+ return self.dev.read(CH_EP_IN, CH_PACKET_SIZE, CH_TIMEOUT)
244
+
245
+ # Clear USB receive buffers
246
+ def clearreply(self):
247
+ try: self.dev.read(CH_EP_IN, CH_PACKET_SIZE, 1)
248
+ except: None
249
+ try: self.dev.read(CH_EP_IN_RAW, CH_PACKET_SIZE, 1)
250
+ except: None
251
+
252
+ # Write to MCU register
253
+ def writereg(self, addr, data):
254
+ stream = bytes((0x81, 0x08, 0x06, addr)) + data.to_bytes(4, byteorder='big') + b'\x02'
255
+ reply = self.sendcommand(stream)
256
+ if (len(reply) != 9) or (reply[3] != addr):
257
+ raise Exception('Failed to write register')
258
+
259
+ # Read from MCU register
260
+ def readreg(self, addr):
261
+ stream = (0x81, 0x08, 0x06, addr, 0, 0, 0, 0, 1)
262
+ reply = self.sendcommand(stream)
263
+ if (len(reply) != 9) or (reply[3] != addr):
264
+ raise Exception('Failed to read register')
265
+ return int.from_bytes(reply[4:8], byteorder='big')
266
+
267
+ # Unbrick MCU
268
+ def unbrick(self):
269
+ self.sendcommand(b'\x81\x0d\x01\x0f\x09')
270
+
271
+ # Lock MCU (set read protection)
272
+ def lock(self):
273
+ if self.chipseries == 0x00:
274
+ self.sendcommand(b'\x81\x06\x08\x03\xf7\xff\xff\xff\xff\xff\xff')
275
+ elif self.chipseries == 0x25 or self.chipseries == 0x03:
276
+ self.sendcommand(b'\x81\x06\x08\x03\xff\xff\xff\xff\xff\xff\xff')
277
+ elif self.chipseries == 0x20 or self.chipseries == 0x30:
278
+ self.sendcommand(b'\x81\x06\x08\x03\x3f\xff\xff\xff\xff\xff\xff')
279
+
280
+ # Unlock MCU (remove read protection -> erase chip!!!)
281
+ def unlock(self):
282
+ reply = self.sendcommand(b'\x81\x06\x01\x01')
283
+ if reply[3] == 0x01:
284
+ if self.chipseries == 0x00:
285
+ self.sendcommand(b'\x81\x06\x08\x02\xf7\xff\xff\xff\xff\xff\xff')
286
+ elif self.chipseries == 0x25 or self.chipseries == 0x03:
287
+ self.sendcommand(b'\x81\x06\x08\x02\xff\xff\xff\xff\xff\xff\xff')
288
+ elif self.chipseries == 0x20 or self.chipseries == 0x30:
289
+ self.sendcommand(b'\x81\x06\x08\x02\x3f\xff\xff\xff\xff\xff\xff')
290
+
291
+ # Perform a whole chip erase
292
+ def erase(self):
293
+ self.sendcommand(b'\x81\x02\x01\x01')
294
+ self.sendcommand(b'\x81\x0d\x01\x02')
295
+
296
+ # Make reset pin a normal GPIO pin (0=RESET, 1=GPIO)
297
+ def setnrstasgpio(self, state):
298
+ if self.chipseries == 0x00:
299
+ if state:
300
+ self.sendcommand(b'\x81\x06\x08\x02\xff\xff\xff\xff\xff\xff\xff')
301
+ else:
302
+ self.sendcommand(b'\x81\x06\x08\x02\xf7\xff\xff\xff\xff\xff\xff')
303
+ else:
304
+ raise Exception('RST pin option not available for this MCU')
305
+
306
+ # Enable/disable programmer's 3V3 output
307
+ def poweron3v3(self):
308
+ self.sendcommand(b'\x81\x0d\x01\x09')
309
+ def poweroff3v3(self):
310
+ self.sendcommand(b'\x81\x0d\x01\x0a')
311
+
312
+ # Enable/disable programmer's 5V output
313
+ def poweron5v(self):
314
+ self.sendcommand(b'\x81\x0d\x01\x0b')
315
+ def poweroff5v(self):
316
+ self.sendcommand(b'\x81\x0d\x01\x0c')
317
+
318
+ # Disconnect from MCU
319
+ def exit(self):
320
+ self.sendcommand(b'\x81\x0b\x01\x01')
321
+ self.sendcommand(b'\x81\x0d\x01\xff')
322
+
323
+ #--------------------------------------------------------------
324
+
325
+ # Get padded data length
326
+ def padlen(self, data, pagesize):
327
+ if (len(data) % pagesize) == 0:
328
+ return len(data)
329
+ else:
330
+ return (len(data) + (pagesize - (len(data) % pagesize)))
331
+
332
+ # Pad data and divide into pages
333
+ def page_data(self, data, pagesize):
334
+ if (len(data) % pagesize) > 0:
335
+ data += b'\xff' * (pagesize - (len(data) % pagesize))
336
+ result = list()
337
+ while len(data):
338
+ result.append(data[:pagesize])
339
+ data = data[pagesize:]
340
+ return result
341
+
342
+ # Write data blob to flash
343
+ def writebinaryblob(self, addr, blocksize, bootloader, data):
344
+ if addr & (blocksize - 1):
345
+ raise Exception('Blob is not %d byte aligned' % blocksize)
346
+ self.unlock()
347
+ stream = b'\x81\x01\x08' \
348
+ + addr.to_bytes(4, byteorder='big') \
349
+ + self.padlen(data, blocksize).to_bytes(4, byteorder='big')
350
+ self.sendcommand(stream)
351
+ self.sendcommand(b'\x81\x02\x01\x05')
352
+ pages = self.page_data(bootloader, 128)
353
+ for page in pages:
354
+ self.dev.write(CH_EP_OUT_RAW, page)
355
+ self.sendcommand(b'\x81\x02\x01\x07')
356
+ self.sendcommand(b'\x81\x02\x01\x04')
357
+ pages = self.page_data(data, blocksize)
358
+ for page in pages:
359
+ self.dev.write(CH_EP_OUT_RAW, page)
360
+ reply = self.dev.read(CH_EP_IN_RAW, CH_PACKET_SIZE, CH_TIMEOUT)
361
+ if set(reply) != set((0x41, 0x01, 0x01, 0x04)):
362
+ raise Exception('Failed writing/verifying data blob')
363
+
364
+ # Write data to code flash
365
+ def flash_data(self, data):
366
+ if len(data) > self.flashsize:
367
+ raise Exception('Not enough memory')
368
+ self.writebinaryblob(CH_CODE_BASE, self.device['block-size'], self.device['loader'], data)
369
+
370
+ # ===================================================================================
371
+ # Device Constants
372
+ # ===================================================================================
373
+
374
+ # USB device settings
375
+ CH_VENDOR_ID = 0x1A86 # VID
376
+ CH_PRODUCT_ID = 0x8010 # PID in RISC-V mode
377
+ CH_ARM_ID = 0x8012 # PID in ARM mode
378
+ CH_PACKET_SIZE = 1024 # packet size
379
+ CH_INTERFACE = 0 # interface number
380
+ CH_EP_OUT = 0x01 # endpoint for command transfer out
381
+ CH_EP_IN = 0x81 # endpoint for reply transfer in
382
+ CH_EP_OUT_RAW = 0x02 # endpoint for raw data transfer out
383
+ CH_EP_IN_RAW = 0x82 # endpoint for raw data transfer in
384
+ CH_TIMEOUT = 5000 # timeout for USB operations
385
+
386
+ # Memory constants
387
+ CH_RAM_BASE = 0x20000000
388
+ CH_CODE_BASE = 0x08000000
389
+ CH_BOOT_BASE = 0x1FFFF000
390
+
391
+ # ===================================================================================
392
+ # Flash Bootloader
393
+ # ===================================================================================
394
+
395
+ LOADER_V003 = \
396
+ b"\x21\x11\x22\xca\x26\xc8\x93\x77\x15\x00\x99\xcf\xb7\x06\x67\x45" \
397
+ +b"\xb7\x27\x02\x40\x93\x86\x36\x12\x37\x97\xef\xcd\xd4\xc3\x13\x07" \
398
+ +b"\xb7\x9a\xd8\xc3\xd4\xd3\xd8\xd3\x93\x77\x25\x00\x9d\xc7\xb7\x27" \
399
+ +b"\x02\x40\x98\x4b\xad\x66\x37\x33\x00\x40\x13\x67\x47\x00\x98\xcb" \
400
+ +b"\x98\x4b\x93\x86\xa6\xaa\x13\x67\x07\x04\x98\xcb\xd8\x47\x05\x8b" \
401
+ +b"\x63\x16\x07\x10\x98\x4b\x6d\x9b\x98\xcb\x93\x77\x45\x00\xa9\xcb" \
402
+ +b"\x93\x07\xf6\x03\x99\x83\x2e\xc0\x2d\x63\x81\x76\x3e\xc4\xb7\x32" \
403
+ +b"\x00\x40\xb7\x27\x02\x40\x13\x03\xa3\xaa\xfd\x16\x98\x4b\xb7\x03" \
404
+ +b"\x02\x00\x33\x67\x77\x00\x98\xcb\x02\x47\xd8\xcb\x98\x4b\x13\x67" \
405
+ +b"\x07\x04\x98\xcb\xd8\x47\x05\x8b\x69\xe7\x98\x4b\x75\x8f\x98\xcb" \
406
+ +b"\x02\x47\x13\x07\x07\x04\x3a\xc0\x22\x47\x7d\x17\x3a\xc4\x79\xf7" \
407
+ +b"\x93\x77\x85\x00\xf1\xcf\x93\x07\xf6\x03\x2e\xc0\x99\x83\x37\x27" \
408
+ +b"\x02\x40\x3e\xc4\x1c\x4b\xc1\x66\x2d\x63\xd5\x8f\x1c\xcb\x37\x07" \
409
+ +b"\x00\x20\x13\x07\x07\x20\xb7\x27\x02\x40\xb7\x03\x08\x00\xb7\x32" \
410
+ +b"\x00\x40\x13\x03\xa3\xaa\x94\x4b\xb3\xe6\x76\x00\x94\xcb\xd4\x47" \
411
+ +b"\x85\x8a\xf5\xfe\x82\x46\xba\x84\x37\x04\x04\x00\x36\xc2\xc1\x46" \
412
+ +b"\x36\xc6\x92\x46\x84\x40\x11\x07\x84\xc2\x94\x4b\xc1\x8e\x94\xcb" \
413
+ +b"\xd4\x47\x85\x8a\xb1\xea\x92\x46\xba\x84\x91\x06\x36\xc2\xb2\x46" \
414
+ +b"\xfd\x16\x36\xc6\xf9\xfe\x82\x46\xd4\xcb\x94\x4b\x93\xe6\x06\x04" \
415
+ +b"\x94\xcb\xd4\x47\x85\x8a\x85\xee\xd4\x47\xc1\x8a\x85\xce\xd8\x47" \
416
+ +b"\xb7\x06\xf3\xff\xfd\x16\x13\x67\x07\x01\xd8\xc7\x98\x4b\x21\x45" \
417
+ +b"\x75\x8f\x98\xcb\x52\x44\xc2\x44\x61\x01\x02\x90\x23\x20\xd3\x00" \
418
+ +b"\xf5\xb5\x23\xa0\x62\x00\x3d\xb7\x23\xa0\x62\x00\x55\xb7\x23\xa0" \
419
+ +b"\x62\x00\xc1\xb7\x82\x46\x93\x86\x06\x04\x36\xc0\xa2\x46\xfd\x16" \
420
+ +b"\x36\xc4\xb5\xf2\x98\x4b\xb7\x06\xf3\xff\xfd\x16\x75\x8f\x98\xcb" \
421
+ +b"\x41\x89\x05\xcd\x2e\xc0\x0d\x06\x02\xc4\x09\x82\xb7\x07\x00\x20" \
422
+ +b"\x32\xc6\x93\x87\x07\x20\x98\x43\x13\x86\x47\x00\xa2\x47\x82\x46" \
423
+ +b"\x8a\x07\xb6\x97\x9c\x43\x63\x1c\xf7\x00\xa2\x47\x85\x07\x3e\xc4" \
424
+ +b"\xa2\x46\x32\x47\xb2\x87\xe3\xe0\xe6\xfe\x01\x45\x61\xb7\x41\x45" \
425
+ +b"\x51\xb7"
426
+
427
+ LOADER_V103 = \
428
+ b"\x93\x77\x15\x00\x41\x11\x99\xcf\xb7\x06\x67\x45\xb7\x27\x02\x40" \
429
+ +b"\x93\x86\x36\x12\x37\x97\xef\xcd\xd4\xc3\x13\x07\xb7\x9a\xd8\xc3" \
430
+ +b"\xd4\xd3\xd8\xd3\x93\x77\x25\x00\x9d\xc7\xb7\x27\x02\x40\x98\x4b" \
431
+ +b"\xad\x66\x37\x38\x00\x40\x13\x67\x47\x00\x98\xcb\x98\x4b\x93\x86" \
432
+ +b"\xa6\xaa\x13\x67\x07\x04\x98\xcb\xd8\x47\x05\x8b\x63\x1f\x07\x10" \
433
+ +b"\x98\x4b\x6d\x9b\x98\xcb\x93\x77\x45\x00\xa9\xcb\x93\x07\xf6\x07" \
434
+ +b"\x9d\x83\x2e\xc0\x2d\x68\x81\x76\x3e\xc4\xb7\x08\x02\x00\xb7\x27" \
435
+ +b"\x02\x40\x37\x33\x00\x40\x13\x08\xa8\xaa\xfd\x16\x98\x4b\x33\x67" \
436
+ +b"\x17\x01\x98\xcb\x02\x47\xd8\xcb\x98\x4b\x13\x67\x07\x04\x98\xcb" \
437
+ +b"\xd8\x47\x05\x8b\x71\xef\x98\x4b\x75\x8f\x98\xcb\x02\x47\x13\x07" \
438
+ +b"\x07\x08\x3a\xc0\x22\x47\x7d\x17\x3a\xc4\x69\xfb\x93\x77\x85\x00" \
439
+ +b"\xed\xc3\x93\x07\xf6\x07\x2e\xc0\x9d\x83\x37\x27\x02\x40\x3e\xc4" \
440
+ +b"\x1c\x4b\xc1\x66\x37\x08\x08\x00\xd5\x8f\x1c\xcb\xa1\x48\x37\x17" \
441
+ +b"\x00\x20\xb7\x27\x02\x40\x37\x03\x04\x00\x94\x4b\xb3\xe6\x06\x01" \
442
+ +b"\x94\xcb\xd4\x47\x85\x8a\xf5\xfe\x82\x46\x3a\x8e\x36\xc2\x46\xc6" \
443
+ +b"\x92\x46\x83\x2e\x07\x00\x41\x07\x23\xa0\xd6\x01\x92\x46\x83\x2e" \
444
+ +b"\x47\xff\x23\xa2\xd6\x01\x92\x46\x83\x2e\x87\xff\x23\xa4\xd6\x01" \
445
+ +b"\x92\x46\x03\x2e\xce\x00\x23\xa6\xc6\x01\x94\x4b\xb3\xe6\x66\x00" \
446
+ +b"\x94\xcb\xd4\x47\x85\x8a\xf5\xfe\x92\x46\x3a\x8e\xc1\x06\x36\xc2" \
447
+ +b"\xb2\x46\xfd\x16\x36\xc6\xcd\xfe\x82\x46\xd4\xcb\x94\x4b\x93\xe6" \
448
+ +b"\x06\x04\x94\xcb\xd4\x47\x85\x8a\xf5\xfe\xd4\x47\xd1\x8a\x85\xc6" \
449
+ +b"\xd8\x47\xb7\x06\xf3\xff\xfd\x16\x13\x67\x47\x01\xd8\xc7\x98\x4b" \
450
+ +b"\x21\x45\x75\x8f\x98\xcb\x41\x01\x02\x90\x23\x20\xd8\x00\xe9\xbd" \
451
+ +b"\x23\x20\x03\x01\x31\xbf\x82\x46\x93\x86\x06\x08\x36\xc0\xa2\x46" \
452
+ +b"\xfd\x16\x36\xc4\xb9\xfa\x98\x4b\xb7\x06\xf3\xff\xfd\x16\x75\x8f" \
453
+ +b"\x98\xcb\x41\x89\x15\xc9\x2e\xc0\x0d\x06\x02\xc4\x09\x82\x32\xc6" \
454
+ +b"\xb7\x17\x00\x20\x98\x43\x13\x86\x47\x00\xa2\x47\x82\x46\x8a\x07" \
455
+ +b"\xb6\x97\x9c\x43\x63\x1c\xf7\x00\xa2\x47\x85\x07\x3e\xc4\xa2\x46" \
456
+ +b"\x32\x47\xb2\x87\xe3\xe0\xe6\xfe\x01\x45\x71\xbf\x41\x45\x61\xbf"
457
+
458
+ LOADER_V203 = \
459
+ b"\x93\x77\x15\x00\x41\x11\x99\xcf\xb7\x06\x67\x45\xb7\x27\x02\x40" \
460
+ +b"\x93\x86\x36\x12\x37\x97\xef\xcd\xd4\xc3\x13\x07\xb7\x9a\xd8\xc3" \
461
+ +b"\xd4\xd3\xd8\xd3\x93\x77\x25\x00\x95\xc7\xb7\x27\x02\x40\x98\x4b" \
462
+ +b"\xad\x66\x37\x38\x00\x40\x13\x67\x47\x00\x98\xcb\x98\x4b\x93\x86" \
463
+ +b"\xa6\xaa\x13\x67\x07\x04\x98\xcb\xd8\x47\x05\x8b\x61\xeb\x98\x4b" \
464
+ +b"\x6d\x9b\x98\xcb\x93\x77\x45\x00\xa9\xcb\x93\x07\xf6\x0f\xa1\x83" \
465
+ +b"\x2e\xc0\x2d\x68\x81\x76\x3e\xc4\xb7\x08\x02\x00\xb7\x27\x02\x40" \
466
+ +b"\x37\x33\x00\x40\x13\x08\xa8\xaa\xfd\x16\x98\x4b\x33\x67\x17\x01" \
467
+ +b"\x98\xcb\x02\x47\xd8\xcb\x98\x4b\x13\x67\x07\x04\x98\xcb\xd8\x47" \
468
+ +b"\x05\x8b\x41\xeb\x98\x4b\x75\x8f\x98\xcb\x02\x47\x13\x07\x07\x10" \
469
+ +b"\x3a\xc0\x22\x47\x7d\x17\x3a\xc4\x69\xfb\x93\x77\x85\x00\xd5\xcb" \
470
+ +b"\x93\x07\xf6\x0f\x2e\xc0\xa1\x83\x3e\xc4\x37\x27\x02\x40\x1c\x4b" \
471
+ +b"\xc1\x66\x41\x68\xd5\x8f\x1c\xcb\xb7\x16\x00\x20\xb7\x27\x02\x40" \
472
+ +b"\x93\x08\x00\x04\x37\x03\x20\x00\x98\x4b\x33\x67\x07\x01\x98\xcb" \
473
+ +b"\xd8\x47\x05\x8b\x75\xff\x02\x47\x3a\xc2\x46\xc6\x32\x47\x0d\xef" \
474
+ +b"\x98\x4b\x33\x67\x67\x00\x98\xcb\xd8\x47\x05\x8b\x75\xff\xd8\x47" \
475
+ +b"\x41\x8b\x39\xc3\xd8\x47\xc1\x76\xfd\x16\x13\x67\x07\x01\xd8\xc7" \
476
+ +b"\x98\x4b\x21\x45\x75\x8f\x98\xcb\x41\x01\x02\x90\x23\x20\xd8\x00" \
477
+ +b"\x25\xb7\x23\x20\x03\x01\xa5\xb7\x12\x47\x13\x8e\x46\x00\x94\x42" \
478
+ +b"\x14\xc3\x12\x47\x11\x07\x3a\xc2\x32\x47\x7d\x17\x3a\xc6\xd8\x47" \
479
+ +b"\x09\x8b\x75\xff\xf2\x86\x5d\xb7\x02\x47\x13\x07\x07\x10\x3a\xc0" \
480
+ +b"\x22\x47\x7d\x17\x3a\xc4\x49\xf3\x98\x4b\xc1\x76\xfd\x16\x75\x8f" \
481
+ +b"\x98\xcb\x41\x89\x15\xc9\x2e\xc0\x0d\x06\x02\xc4\x09\x82\x32\xc6" \
482
+ +b"\xb7\x17\x00\x20\x98\x43\x13\x86\x47\x00\xa2\x47\x82\x46\x8a\x07" \
483
+ +b"\xb6\x97\x9c\x43\x63\x1c\xf7\x00\xa2\x47\x85\x07\x3e\xc4\xa2\x46" \
484
+ +b"\x32\x47\xb2\x87\xe3\xe0\xe6\xfe\x01\x45\xbd\xbf\x41\x45\xad\xbf"
485
+
486
+ LOADER_X035 = \
487
+ b"\x01\x11\x02\xce\x93\x77\x15\x00\x99\xcf\xb7\x06\x67\x45\xb7\x27" \
488
+ +b"\x02\x40\x93\x86\x36\x12\x37\x97\xef\xcd\xd4\xc3\x13\x07\xb7\x9a" \
489
+ +b"\xd8\xc3\xd4\xd3\xd8\xd3\x93\x77\x25\x00\x9d\xc7\xb7\x27\x02\x40" \
490
+ +b"\x98\x4b\xad\x66\x37\x38\x00\x40\x13\x67\x47\x00\x98\xcb\x98\x4b" \
491
+ +b"\x93\x86\xa6\xaa\x13\x67\x07\x04\x98\xcb\xd8\x47\x05\x8b\x63\x16" \
492
+ +b"\x07\x10\x98\x4b\x6d\x9b\x98\xcb\x93\x77\x45\x00\xa9\xcb\x93\x07" \
493
+ +b"\xf6\x0f\xa1\x83\x2e\xc6\x2d\x68\x81\x76\x3e\xca\xb7\x08\x02\x00" \
494
+ +b"\xb7\x27\x02\x40\x37\x33\x00\x40\x13\x08\xa8\xaa\xfd\x16\x98\x4b" \
495
+ +b"\x33\x67\x17\x01\x98\xcb\x32\x47\xd8\xcb\x98\x4b\x13\x67\x07\x04" \
496
+ +b"\x98\xcb\xd8\x47\x05\x8b\x69\xe7\x98\x4b\x75\x8f\x98\xcb\x32\x47" \
497
+ +b"\x13\x07\x07\x10\x3a\xc6\x52\x47\x7d\x17\x3a\xca\x69\xfb\x93\x77" \
498
+ +b"\x85\x00\xf1\xcf\x93\x07\xf6\x0f\x2e\xc6\xa1\x83\x3e\xca\x37\x27" \
499
+ +b"\x02\x40\x1c\x4b\xc1\x66\x2d\x68\xd5\x8f\x1c\xcb\xb7\x16\x00\x20" \
500
+ +b"\xb7\x27\x02\x40\x37\x03\x08\x00\x13\x0e\x00\x04\xb7\x0e\x04\x00" \
501
+ +b"\xb7\x38\x00\x40\x13\x08\xa8\xaa\x98\x4b\x33\x67\x67\x00\x98\xcb" \
502
+ +b"\xd8\x47\x05\x8b\x75\xff\x32\x47\x36\x8f\x3a\xc8\x72\xcc\x42\x47" \
503
+ +b"\x03\x2f\x0f\x00\x91\x06\x23\x20\xe7\x01\x98\x4b\x33\x67\xd7\x01" \
504
+ +b"\x98\xcb\xd8\x47\x05\x8b\x21\xeb\x42\x47\x36\x8f\x11\x07\x3a\xc8" \
505
+ +b"\x62\x47\x7d\x17\x3a\xcc\x61\xff\x32\x47\xd8\xcb\x98\x4b\x13\x67" \
506
+ +b"\x07\x04\x98\xcb\xd8\x47\x05\x8b\x15\xeb\xd8\x47\x41\x8b\x15\xcb" \
507
+ +b"\xd8\x47\xb7\x06\xf3\xff\xfd\x16\x13\x67\x07\x01\xd8\xc7\x98\x4b" \
508
+ +b"\x21\x45\x75\x8f\x98\xcb\x05\x61\x02\x90\x23\x20\xd8\x00\xf5\xb5" \
509
+ +b"\x23\x20\x03\x01\x3d\xb7\x23\xa0\x08\x01\x65\xb7\x23\xa0\x08\x01" \
510
+ +b"\xd1\xb7\x32\x47\x13\x07\x07\x10\x3a\xc6\x52\x47\x7d\x17\x3a\xca" \
511
+ +b"\x25\xf7\x98\x4b\xb7\x06\xf3\xff\xfd\x16\x75\x8f\x98\xcb\x41\x89" \
512
+ +b"\x19\xe1\x01\x45\xc9\xb7\x2e\xc6\x0d\x06\x02\xca\x09\x82\x32\xcc" \
513
+ +b"\xb7\x17\x00\x20\x98\x43\x13\x86\x47\x00\xd2\x47\xb2\x46\x8a\x07" \
514
+ +b"\xb6\x97\x9c\x43\x63\x18\xf7\x02\xd2\x47\x32\x47\x8a\x07\xba\x97" \
515
+ +b"\x98\x43\xf2\x47\xba\x97\x3e\xce\xd2\x47\x85\x07\x3e\xca\xd2\x46" \
516
+ +b"\x62\x47\xb2\x87\xe3\xe8\xe6\xfc\xb7\x27\x00\x20\x98\x4b\xf2\x47" \
517
+ +b"\xe3\x09\xf7\xfa\x41\x45\x85\xbf"
518
+
519
+ # ===================================================================================
520
+ # Device definitions
521
+ # ===================================================================================
522
+
523
+ DEVICES = [
524
+ {'name': 'CH32V003J4M6', 'id': 0x0033, 'block-size': 64, 'loader': LOADER_V003},
525
+ {'name': 'CH32V003A4M6', 'id': 0x0032, 'block-size': 64, 'loader': LOADER_V003},
526
+ {'name': 'CH32V003F4U6', 'id': 0x0031, 'block-size': 64, 'loader': LOADER_V003},
527
+ {'name': 'CH32V003F4P6', 'id': 0x0030, 'block-size': 64, 'loader': LOADER_V003},
528
+
529
+ {'name': 'CH32V103', 'id': 0x2500, 'block-size': 128, 'loader': LOADER_V103},
530
+
531
+ {'name': 'CH32V203C8U6', 'id': 0x2030, 'block-size': 256, 'loader': LOADER_V203},
532
+ {'name': 'CH32V203C8T6', 'id': 0x2031, 'block-size': 256, 'loader': LOADER_V203},
533
+ {'name': 'CH32V203K8T6', 'id': 0x2032, 'block-size': 256, 'loader': LOADER_V203},
534
+ {'name': 'CH32V203C6T6', 'id': 0x2033, 'block-size': 256, 'loader': LOADER_V203},
535
+ {'name': 'CH32V203RBT6', 'id': 0x2034, 'block-size': 256, 'loader': LOADER_V203},
536
+ {'name': 'CH32V203K6T6', 'id': 0x2035, 'block-size': 256, 'loader': LOADER_V203},
537
+ {'name': 'CH32V203G6U6', 'id': 0x2036, 'block-size': 256, 'loader': LOADER_V203},
538
+ {'name': 'CH32V203F6P6', 'id': 0x2037, 'block-size': 256, 'loader': LOADER_V203},
539
+ {'name': 'CH32V203F8P6', 'id': 0x203a, 'block-size': 256, 'loader': LOADER_V203},
540
+ {'name': 'CH32V203G8R6', 'id': 0x203b, 'block-size': 256, 'loader': LOADER_V203},
541
+ {'name': 'CH32V208WBU6', 'id': 0x2080, 'block-size': 256, 'loader': LOADER_V203},
542
+ {'name': 'CH32V208RBT6', 'id': 0x2081, 'block-size': 256, 'loader': LOADER_V203},
543
+ {'name': 'CH32V208CBU6', 'id': 0x2082, 'block-size': 256, 'loader': LOADER_V203},
544
+ {'name': 'CH32V208GBU6', 'id': 0x2083, 'block-size': 256, 'loader': LOADER_V203},
545
+
546
+ {'name': 'CH32V303VCT6', 'id': 0x3030, 'block-size': 256, 'loader': LOADER_V203},
547
+ {'name': 'CH32V303RCT6', 'id': 0x3031, 'block-size': 256, 'loader': LOADER_V203},
548
+ {'name': 'CH32V303RBT6', 'id': 0x3033, 'block-size': 256, 'loader': LOADER_V203},
549
+ {'name': 'CH32V303CBT6', 'id': 0x3034, 'block-size': 256, 'loader': LOADER_V203},
550
+ {'name': 'CH32V305RBT6', 'id': 0x3050, 'block-size': 256, 'loader': LOADER_V203},
551
+ {'name': 'CH32V305FBP6', 'id': 0x3052, 'block-size': 256, 'loader': LOADER_V203},
552
+ {'name': 'CH32V307VCT6', 'id': 0x3070, 'block-size': 256, 'loader': LOADER_V203},
553
+ {'name': 'CH32V307RCT6', 'id': 0x3071, 'block-size': 256, 'loader': LOADER_V203},
554
+ {'name': 'CH32V307WCU6', 'id': 0x3073, 'block-size': 256, 'loader': LOADER_V203},
555
+
556
+ {'name': 'CH32X033F8P6', 'id': 0x035a, 'block-size': 256, 'loader': LOADER_X035},
557
+ {'name': 'CH32X035R8T6', 'id': 0x0350, 'block-size': 256, 'loader': LOADER_X035},
558
+ {'name': 'CH32X035C8T6', 'id': 0x0351, 'block-size': 256, 'loader': LOADER_X035},
559
+ {'name': 'CH32X035F8U6', 'id': 0x035e, 'block-size': 256, 'loader': LOADER_X035},
560
+ {'name': 'CH32X035G8U6', 'id': 0x0356, 'block-size': 256, 'loader': LOADER_X035},
561
+ {'name': 'CH32X035G8R6', 'id': 0x035b, 'block-size': 256, 'loader': LOADER_X035},
562
+ {'name': 'CH32X035F7P6', 'id': 0x0357, 'block-size': 256, 'loader': LOADER_X035}
563
+ ]
564
+
565
+ # ===================================================================================
566
+
567
+ if __name__ == "__main__":
568
+ _main()
@@ -0,0 +1,113 @@
1
+ Metadata-Version: 2.1
2
+ Name: rvprog
3
+ Version: 1.5.0
4
+ Summary: Programming Tool for WCH-LinkE and CH32Vxxx and CH32Xxxx
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: WCH,CH552,CH32V003,CH32X035,RISC-V,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: pyusb
44
+
45
+ # rvprog - Programming Tool for WCH-LinkE and CH32Vxxx and CH32Xxxx
46
+ ## Description
47
+ With this tool, the WCH RISC-V microcontrollers CH32Vxxx and CH32Xxxx can be programmed with the [WCH-LinkE](http://www.wch-ic.com/products/WCH-Link.html) (pay attention to the "E" in the name) via its serial debug interface.
48
+
49
+ ## Preparations
50
+ To use the WCH-Link on Linux, you need to grant access permissions beforehand by executing the following commands:
51
+ ```
52
+ echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="8010", MODE="666"' | sudo tee /etc/udev/rules.d/99-WCH-LinkE.rules
53
+ echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="8012", MODE="666"' | sudo tee -a /etc/udev/rules.d/99-WCH-LinkE.rules
54
+ sudo udevadm control --reload-rules
55
+ ```
56
+
57
+ On Windows, if you need to you can install the WinUSB driver over the WCH interface 1 using the [Zadig Tool](https://zadig.akeo.ie/).
58
+
59
+ ## Installation
60
+ - Install [Python3](https://www.pythontutorial.net/getting-started/install-python/).
61
+ - Install [pip](https://pip.pypa.io/en/stable/installation/).
62
+ - Install rvprog:
63
+
64
+ ```
65
+ pip install rvprog
66
+ ```
67
+
68
+ ## Usage
69
+ To upload firmware, you should make the following connections to the WCH-LinkE (SWCLK is not present on the CH32V003 and therefore does not need to be connected):
70
+
71
+ ```
72
+ WCH-LinkE CH32V/X
73
+ +-------+ +-------+
74
+ | SWCLK| ---> |SWCLK |
75
+ | SWDIO| <--> |SWDIO |
76
+ | GND| ---> |GND |
77
+ | 3V3| ---> |VDD |
78
+ +-------+ +-------+
79
+ ```
80
+
81
+ If the blue LED on the WCH-LinkE remains illuminated once it is connected to the USB port, it means that the device is currently in ARM mode and must be switched to RISC-V mode initially. There are a few ways to accomplish this:
82
+ - You can utilize the rvprog tool with the -v option (see below).
83
+ - Alternatively, you can select "WCH-LinkRV" in the software provided by WCH, such as MounRiver Studio or WCH-LinkUtility.
84
+ - Another option is to hold down the ModeS button on the device while plugging it into the USB port.
85
+
86
+ More information can be found in the [WCH-Link User Manual](http://www.wch-ic.com/downloads/WCH-LinkUserManual_PDF.html).
87
+
88
+ ```
89
+ Usage: rvprog [-h] [-a] [-v] [-b] [-u] [-l] [-e] [-G] [-R] [-f FLASH]
90
+
91
+ Optional arguments:
92
+ -h, --help show help message and exit
93
+ -a, --armmode switch WCH-Link to ARM mode
94
+ -v, --rvmode switch WCH-Link to RISC-V mode
95
+ -b, --unbrick unbrick chip
96
+ -u, --unlock unlock chip (remove read protection)
97
+ -l, --lock lock chip (set read protection)
98
+ -e, --erase perform a whole chip erase
99
+ -G, --pingpio make nRST pin a GPIO pin (CH32V003 only)
100
+ -R, --pinreset make nRST pin a reset pin (CH32V003 only)
101
+ -f FLASH, --flash FLASH write BIN file to flash
102
+
103
+ Example:
104
+ rvprog -f firmware.bin
105
+ ```
106
+
107
+ ## Links
108
+ - [MCU Flash Tools](https://github.com/wagiminator/MCU-Flash-Tools)
109
+ - [MCU Templates](https://github.com/wagiminator/MCU-Templates)
110
+ - [MCU Development Boards](https://github.com/wagiminator/Development-Boards)
111
+ - [AVR Development Boards](https://github.com/wagiminator/AVR-Development-Boards)
112
+ - [AVR Programmers](https://github.com/wagiminator/AVR-Programmer)
113
+ - [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
+ rvprog/__init__.py
6
+ rvprog/rvprog.py
7
+ rvprog.egg-info/PKG-INFO
8
+ rvprog.egg-info/SOURCES.txt
9
+ rvprog.egg-info/dependency_links.txt
10
+ rvprog.egg-info/entry_points.txt
11
+ rvprog.egg-info/requires.txt
12
+ rvprog.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ rvprog = rvprog:_main
@@ -0,0 +1 @@
1
+ pyusb
@@ -0,0 +1 @@
1
+ rvprog
rvprog-1.5.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
rvprog-1.5.0/setup.py ADDED
@@ -0,0 +1,15 @@
1
+ from setuptools import setup
2
+
3
+ setup(
4
+ name='rvprog',
5
+ version='1.5.0',
6
+ description='Programming Tool for WCH-LinkE and CH32Vxxx and CH32Xxxx',
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=['rvprog'],
12
+ install_requires=[
13
+ 'pyusb',
14
+ ],
15
+ )