stc8usb 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
stc8usb/__init__.py ADDED
@@ -0,0 +1 @@
1
+ from .stc8usb import _main
stc8usb/stc8usb.py ADDED
@@ -0,0 +1,321 @@
1
+ #!/usr/bin/env python3
2
+ # ===================================================================================
3
+ # Project: stc8usb - USB Programming Tool for STC8H8KxxU Microcontrollers
4
+ # Version: v0.2
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 STC8H8KxxU microcontrollers via USB utilizing the
14
+ # factory built-in embedded USB boot loader.
15
+ # !!! THIS TOOL IS IN AN EARLY STAGE OF DEVELOPMENT !!!
16
+ #
17
+ # Dependencies:
18
+ # -------------
19
+ # - pyhidapi
20
+ #
21
+ # Operating Instructions:
22
+ # -----------------------
23
+ # You need to install pyhidapi to use stc8usb.
24
+ # Install it via "python3 -m pip install hid".
25
+ #
26
+ # By default Linux will not expose enough permission to access the USB bootloader.
27
+ # In order to fix this, open a terminal and run the following commands:
28
+ # echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="34bf", ATTR{idProduct}=="1001", MODE="666"' | sudo tee /etc/udev/rules.d/99-STC-ISP.rules
29
+ # sudo udevadm control --reload-rules
30
+ #
31
+ # The bootloader must be started manually for new uploads. To do this, the board must
32
+ # first be disconnected from the USB port and all voltage sources. Now press the BOOT
33
+ # button and keep it pressed while reconnecting the board to the USB port of your PC.
34
+ # The chip now starts in bootloader mode, the BOOT button can be released and new
35
+ # firmware can be uploaded via USB. If there is no BOOT button on the board, you have
36
+ # to short pin P3.2 to ground while connecting.
37
+ #
38
+ # Run "python3 stc8usb.py -t 24000000 -f firmware.bin".
39
+
40
+ # ===================================================================================
41
+ # Libraries
42
+ # ===================================================================================
43
+
44
+ import sys
45
+ import hid
46
+ import argparse
47
+
48
+ # ===================================================================================
49
+ # Main Function
50
+ # ===================================================================================
51
+
52
+ def _main():
53
+ # Parse command line arguments
54
+ parser = argparse.ArgumentParser(description='Minimal command line interface for stc8usb')
55
+ parser.add_argument('-t', '--trim', help='trim IRC to frequency in Hz')
56
+ parser.add_argument('-e', '--erase', action='store_true', help='perform chip erase (implied with -f)')
57
+ parser.add_argument('-f', '--flash', help='write BIN file to flash')
58
+ args = parser.parse_args(sys.argv[1:])
59
+
60
+ # Establish connection to USB-to-serial converter
61
+ try:
62
+ print('Connecting to MCU via USB ...')
63
+ isp = Programmer()
64
+ except Exception as ex:
65
+ sys.stderr.write('ERROR: ' + str(ex) + '!\n')
66
+ sys.exit(1)
67
+
68
+ # Performing actions
69
+ try:
70
+ # Connect to and identify MCU
71
+ isp.connect()
72
+ print('SUCCESS: Found %s v%s @ %s.' % (isp.chipname, isp.chipverstr, isp.foscstr))
73
+
74
+ # Perform chip erase
75
+ if (args.erase) or (args.flash is not None) or (args.trim is not None):
76
+ print('Performing chip erase ...')
77
+ isp.erase()
78
+ print('SUCCESS: Chip is erased.')
79
+
80
+ # Flash binary file
81
+ if args.flash is not None:
82
+ print('Flashing %s to %s ...' % (args.flash, isp.chipname))
83
+ with open(args.flash, 'rb') as f: data = f.read()
84
+ isp.writeflash(0, data)
85
+ print('SUCCESS: %d bytes written.' % len(data))
86
+
87
+ # Set frequency
88
+ if args.trim is not None:
89
+ print('Setting frequency ...')
90
+ isp.setfreq(int(args.trim))
91
+ print('SUCCESS: Frequency set to %s Hz.' % args.trim)
92
+
93
+ # Close connection
94
+ isp.disconnect()
95
+
96
+ except Exception as ex:
97
+ sys.stderr.write('ERROR: ' + str(ex) + '!\n')
98
+ isp.close()
99
+ sys.exit(1)
100
+
101
+ print('DONE.')
102
+ sys.exit(0)
103
+
104
+ # ===================================================================================
105
+ # Programmer Class
106
+ # ===================================================================================
107
+
108
+ class Programmer:
109
+ # Init programmer
110
+ def __init__(self):
111
+ # Find programmer
112
+ try:
113
+ self.dev = hid.Device(STC_VID, STC_PID)
114
+ except:
115
+ raise Exception('Unable to open device')
116
+
117
+ # Close connection
118
+ def close(self):
119
+ self.dev.close()
120
+
121
+ #--------------------------------------------------------------------------------
122
+
123
+ # Transmit data block
124
+ def transmit(self, data):
125
+ size = len(data) + 6
126
+ parity = STC_TX_CODE + (size >> 8) + (size & 0xff)
127
+ for x in range(len(data)):
128
+ parity += data[x]
129
+ block = [STC_PREFIX, STC_PREFIX ^ 0xff, STC_TX_CODE]
130
+ block += size.to_bytes(2, byteorder='big')
131
+ block += data
132
+ block += parity.to_bytes(2, byteorder='big')
133
+ block += [STC_SUFFIX]
134
+ block = self.paddata(bytes(block), STC_HID_SIZE, 0x00)
135
+ self.dev.write(block)
136
+
137
+ # Receive data block
138
+ def receive(self):
139
+ reply = self.dev.read(STC_HID_SIZE, STC_TIMEOUT)
140
+ if len(reply) != STC_HID_SIZE:
141
+ raise Exception('No response from device')
142
+ size = int.from_bytes(reply[3:5], byteorder='big')
143
+ return reply[5:size-1]
144
+
145
+ #--------------------------------------------------------------------------------
146
+
147
+ # Connect to and identify MCU
148
+ def connect(self):
149
+ self.transmit([STC_CMD_INIT])
150
+ reply = self.receive()
151
+
152
+ # Get chip ID
153
+ self.chipid = int.from_bytes(reply[20:22], byteorder='big')
154
+
155
+ # Find chip in dictionary
156
+ self.device = None
157
+ for d in STC_DEVICES:
158
+ if d['id'] == self.chipid:
159
+ self.device = d
160
+ if self.device is None:
161
+ raise Exception('Unsupported chip (ID: 0x%04x)' % self.chipid)
162
+ self.chipname = self.device['name']
163
+ self.flash_size = self.device['flash_size']
164
+
165
+ # Get chip version
166
+ self.chipversion = reply[17]
167
+ self.chipverstr = '%d.%d.%d%c' % (reply[17] >> 4, reply[17] & 0x0f, \
168
+ reply[22] & 0x0f, reply[18])
169
+
170
+ # Get USER-IRC oscillator frequency
171
+ self.fosc = int.from_bytes(reply[1:5], byteorder='big')
172
+ if self.fosc == 0xffffffff:
173
+ self.foscstr = 'untrimmed frequency'
174
+ else:
175
+ self.foscstr = str(self.fosc) + ' Hz'
176
+
177
+ # Set BAUD (dummy)
178
+ self.transmit([STC_CMD_BAUD_SET, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80])
179
+ self.receive()
180
+ self.transmit([STC_CMD_BAUD_CHECK, 0x00, 0x00, 0x5a, 0xa5])
181
+ self.receive()
182
+
183
+ # Disconnect from MCU
184
+ def disconnect(self):
185
+ self.transmit([STC_CMD_EXIT])
186
+ self.dev.close()
187
+
188
+ #--------------------------------------------------------------------------------
189
+
190
+ # Erase flash
191
+ def erase(self):
192
+ self.transmit([STC_CMD_ERASE, 0, 0, STC_BREAK, STC_BREAK ^ 0xff])
193
+ reply = self.receive()
194
+ if reply is None or reply[0] != STC_CMD_ERASE:
195
+ raise Exception('Failed to erase flash')
196
+
197
+ # Write data to flash
198
+ def writeflash(self, addr, data):
199
+ data = self.paddata(data, STC_PAGE_SIZE, 0xff)
200
+ size = len(data)
201
+ if size > (self.flash_size - addr):
202
+ raise Exception('Not enough memory')
203
+ cmd = STC_CMD_WRITE
204
+ while size > 0:
205
+ blocksize = min(size, STC_PAGE_SIZE)
206
+ block = [cmd]
207
+ block += addr.to_bytes(2, byteorder='big')
208
+ block += [STC_BREAK, STC_BREAK ^ 0xff]
209
+ block += data[:blocksize]
210
+ self.transmit(block)
211
+ reply = self.receive()
212
+ if reply is None or reply[0] != STC_CMD_WRITE_CONT:
213
+ raise Exception('Failed to write to address 0x%04x' % addr)
214
+ cmd = STC_CMD_WRITE_CONT
215
+ data = data[blocksize:]
216
+ addr += blocksize
217
+ size -= blocksize
218
+
219
+ # Set frequency by writing option bytes
220
+ def setfreq(self, freq):
221
+ trim = None
222
+ for f in STC_FREQUENCIES:
223
+ if f['freq'] == freq:
224
+ trim = f['trim']
225
+ if trim is None:
226
+ raise Exception('Unsupported frequency')
227
+ block = [STC_CMD_OPTIONS, 0, 0, STC_BREAK, STC_BREAK ^ 0xff]
228
+ block += STC_BLOCK_OPTIONS1
229
+ block += freq.to_bytes(4, byteorder='big')
230
+ block += trim
231
+ block += STC_BLOCK_OPTIONS2
232
+ self.transmit(block)
233
+ reply = self.receive()
234
+ if reply is None or reply[0] != STC_CMD_OPTIONS:
235
+ raise Exception('Failed to write option bytes')
236
+
237
+ # Pad data
238
+ def paddata(self, data, pagesize, filler):
239
+ if (len(data) % pagesize) > 0:
240
+ data += bytes([filler]) * (pagesize - (len(data) % pagesize))
241
+ return data
242
+
243
+ # ===================================================================================
244
+ # Device Constants
245
+ # ===================================================================================
246
+
247
+ STC_VID = 0x34bf
248
+ STC_PID = 0x1001
249
+ STC_HID_SIZE = 64
250
+ STC_PAGE_SIZE = 128
251
+ STC_TIMEOUT = 1000
252
+
253
+ STC_PREFIX = 0x46
254
+ STC_BREAK = 0x5a
255
+ STC_SUFFIX = 0x16
256
+ STC_TX_CODE = 0x6a
257
+ STC_RX_CODE = 0x68
258
+ STC_RPL_INFO = 0x50
259
+
260
+ STC_CMD_INIT = 0x00
261
+ STC_CMD_BAUD_SET = 0x01
262
+ STC_CMD_BAUD_CHECK = 0x05
263
+ STC_CMD_ERASE = 0x03
264
+ STC_CMD_OPTIONS = 0x04
265
+ STC_CMD_WRITE = 0x32
266
+ STC_CMD_WRITE_CONT = 0x02
267
+ STC_CMD_EXIT = 0xff
268
+
269
+ STC_BLOCK_OPTIONS1 = [0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
270
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
271
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff]
272
+ STC_BLOCK_OPTIONS2 = [0xff, 0xff, 0xff, 0xff, 0x3e, 0xbf, 0xaf, 0xf7, 0xfe]
273
+
274
+ # ===================================================================================
275
+ # Device Dictionary
276
+ # ===================================================================================
277
+
278
+ STC_DEVICES = [
279
+ {'name': 'STC8H8K16U', 'id': 0xF781, 'flash_size': 16384},
280
+ {'name': 'STC8H8K32U', 'id': 0xF782, 'flash_size': 32768},
281
+ {'name': 'STC8H8K60U', 'id': 0xF783, 'flash_size': 61440},
282
+ {'name': 'STC8H8K64U', 'id': 0xF784, 'flash_size': 65024},
283
+ {'name': 'STC8H8K48U', 'id': 0xF785, 'flash_size': 49152}
284
+ ]
285
+
286
+ STC_FREQUENCIES = [
287
+ {'freq': 250000, 'trim': [0x48, 0x20, 96]},
288
+ {'freq': 500000, 'trim': [0x48, 0x20, 48]},
289
+ {'freq': 1000000, 'trim': [0x48, 0x20, 24]},
290
+ {'freq': 2000000, 'trim': [0x48, 0x20, 12]},
291
+ {'freq': 3000000, 'trim': [0x48, 0x20, 8]},
292
+ {'freq': 4000000, 'trim': [0x48, 0x20, 6]},
293
+ {'freq': 5000000, 'trim': [0x73, 0x30, 8]},
294
+ {'freq': 6000000, 'trim': [0x48, 0x20, 4]},
295
+ {'freq': 8000000, 'trim': [0x48, 0x20, 3]},
296
+ {'freq': 10000000, 'trim': [0x73, 0x30, 4]},
297
+ {'freq': 12000000, 'trim': [0x48, 0x20, 2]},
298
+ {'freq': 16000000, 'trim': [0xc6, 0x30, 3]},
299
+ {'freq': 20000000, 'trim': [0x73, 0x30, 2]},
300
+ {'freq': 24000000, 'trim': [0x48, 0x20, 1]},
301
+ {'freq': 27000000, 'trim': [0x7a, 0x20, 1]},
302
+ {'freq': 30000000, 'trim': [0xb1, 0x20, 1]},
303
+ {'freq': 35000000, 'trim': [0x44, 0x30, 1]},
304
+ {'freq': 40000000, 'trim': [0x73, 0x30, 1]},
305
+ {'freq': 48000000, 'trim': [0xc6, 0x30, 1]},
306
+
307
+ {'freq': 1382400, 'trim': [0x28, 0x20, 16]},
308
+ {'freq': 2764800, 'trim': [0x28, 0x20, 8]},
309
+ {'freq': 5529600, 'trim': [0x28, 0x20, 4]},
310
+ {'freq': 11059200, 'trim': [0x28, 0x20, 2]},
311
+ {'freq': 18432000, 'trim': [0x56, 0x30, 2]},
312
+ {'freq': 22118400, 'trim': [0x28, 0x20, 1]},
313
+ {'freq': 33177600, 'trim': [0xe9, 0x20, 1]},
314
+ {'freq': 36864000, 'trim': [0x56, 0x30, 1]},
315
+ {'freq': 44236800, 'trim': [0x9f, 0x30, 1]}
316
+ ]
317
+
318
+ # ===================================================================================
319
+
320
+ if __name__ == "__main__":
321
+ _main()
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Stefan Wagner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,90 @@
1
+ Metadata-Version: 2.1
2
+ Name: stc8usb
3
+ Version: 0.2.0
4
+ Summary: USB Programming Tool for STC8H8KxxU 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: STC,STC8,STC8H8K64U,microcontroller
34
+ Classifier: Development Status :: 4 - Beta
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Operating System :: OS Independent
38
+ Classifier: Intended Audience :: Developers
39
+ Classifier: Topic :: Software Development :: Embedded Systems
40
+ Requires-Python: >=3.8
41
+ Description-Content-Type: text/markdown
42
+ License-File: LICENSE
43
+ Requires-Dist: hid
44
+
45
+ # stc8usb - USB Programming Tool for STC8H8KxxU Microcontrollers
46
+ ## Description
47
+ This tool allows you to flash STC8H8KxxU microcontrollers through their USB interface, using the pre-installed embedded USB bootloader.
48
+
49
+ ## Preparations
50
+ Because the USB bootloader functions as a Human Interface Device (HID), there's no need to install drivers. However, Linux doesn't initially grant sufficient permissions to access the bootloader. To resolve this issue, open a terminal and execute the following commands:
51
+
52
+ ```
53
+ echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="34bf", ATTR{idProduct}=="1001", MODE="666"' | sudo tee /etc/udev/rules.d/99-STC-ISP.rules
54
+ sudo udevadm control --reload-rules
55
+ ```
56
+
57
+ ## Installation
58
+ - Install [Python3](https://www.pythontutorial.net/getting-started/install-python/).
59
+ - Install [pip](https://pip.pypa.io/en/stable/installation/).
60
+ - Install stc8usb:
61
+
62
+ ```
63
+ pip install stc8usb
64
+ ```
65
+
66
+ ## Usage
67
+ To initiate new uploads, the bootloader needs to be manually started. Begin by unplugging the board from the USB port and disconnecting all power sources. Then, press and hold the BOOT button while reconnecting the board to your PC's USB port. This action triggers the chip to enter bootloader mode. Once in this mode, you can release the BOOT button and proceed to upload new firmware via USB.
68
+
69
+ If your board doesn't have a BOOT button, you'll need to short pin P3.2 to ground while connecting to achieve the same effect.
70
+
71
+ ```
72
+ Usage: stc8usb [-h] [-t TRIM] [-e] [-f FLASH]
73
+
74
+ Optional arguments:
75
+ -h, --help show this help message and exit
76
+ -t TRIM, --trim TRIM set MCU system frequency
77
+ -e, --erase perform chip erase (implied with -f)
78
+ -f FLASH, --flash FLASH write BIN file to flash
79
+
80
+ Example:
81
+ stc8usb -t 24000000 -f firmware.bin
82
+ ```
83
+
84
+ ## Links
85
+ - [MCU Flash Tools](https://github.com/wagiminator/MCU-Flash-Tools)
86
+ - [MCU Templates](https://github.com/wagiminator/MCU-Templates)
87
+ - [MCU Development Boards](https://github.com/wagiminator/Development-Boards)
88
+ - [AVR Development Boards](https://github.com/wagiminator/AVR-Development-Boards)
89
+ - [AVR Programmers](https://github.com/wagiminator/AVR-Programmer)
90
+ - [SAMD Development Boards](https://github.com/wagiminator/SAMD-Development-Boards)
@@ -0,0 +1,8 @@
1
+ stc8usb/__init__.py,sha256=DDwQn_GFt_rff2fsgVs2s7DrqZuzRkivE9db5RBtB98,26
2
+ stc8usb/stc8usb.py,sha256=flYdM9trSbDDoOnuO8w5X-dgbfLXzIyC_Ot3FJLDLLQ,12235
3
+ stc8usb-0.2.0.dist-info/LICENSE,sha256=kph2e2d1k_-VvrU6YbwdbUJ2GKXsFgBGCSym5wVv2j8,1089
4
+ stc8usb-0.2.0.dist-info/METADATA,sha256=APLYpMpfeG_IBnP1-vWdGrSADs-QHd-UVwGI-IKKAEg,4413
5
+ stc8usb-0.2.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
6
+ stc8usb-0.2.0.dist-info/entry_points.txt,sha256=hYlzgFW2FOnpnT9iha545aDI7EBb2Vb3C50xXvNNszs,42
7
+ stc8usb-0.2.0.dist-info/top_level.txt,sha256=v1iXuIe8A6-AoKC3Q3qPMustVK3BYcSYaLWXDu2yTYU,8
8
+ stc8usb-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (72.1.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ stc8usb = stc8usb:_main
@@ -0,0 +1 @@
1
+ stc8usb