stc8isp 0.3.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.
- stc8isp/__init__.py +1 -0
- stc8isp/stc8isp.py +503 -0
- stc8isp-0.3.0.dist-info/LICENSE +21 -0
- stc8isp-0.3.0.dist-info/METADATA +96 -0
- stc8isp-0.3.0.dist-info/RECORD +8 -0
- stc8isp-0.3.0.dist-info/WHEEL +5 -0
- stc8isp-0.3.0.dist-info/entry_points.txt +2 -0
- stc8isp-0.3.0.dist-info/top_level.txt +1 -0
stc8isp/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .stc8isp import _main
|
stc8isp/stc8isp.py
ADDED
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# ===================================================================================
|
|
3
|
+
# Project: stc8isp - Programming Tool for STC8G/8H Microcontrollers
|
|
4
|
+
# Version: v0.3
|
|
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 STC8G/8H microcontrollers via USB-to-serial
|
|
14
|
+
# converter utilizing the factory built-in embedded boot loader.
|
|
15
|
+
# !!! THIS TOOL IS IN AN EARLY STAGE OF DEVELOPMENT !!!
|
|
16
|
+
#
|
|
17
|
+
# Dependencies:
|
|
18
|
+
# -------------
|
|
19
|
+
# - pyserial
|
|
20
|
+
#
|
|
21
|
+
# Operating Instructions:
|
|
22
|
+
# -----------------------
|
|
23
|
+
# You need to install PySerial to use stc8isp.
|
|
24
|
+
# Install it via "python3 -m pip install pyserial".
|
|
25
|
+
# You may need to install a driver for your USB-to-serial converter.
|
|
26
|
+
#
|
|
27
|
+
# Connect your USB-to-serial converter to your MCU:
|
|
28
|
+
# USB2SERIAL STC8G/8H
|
|
29
|
+
# VCC --/ --> VCC interruptible (for power cycle)
|
|
30
|
+
# RXD --|R|-- P3.1 resistor (100R - 1000R)
|
|
31
|
+
# TXD --|<|-- P3.0 diode (e.g. 1N5819)
|
|
32
|
+
# GND ------- GND common ground
|
|
33
|
+
#
|
|
34
|
+
# Run "python3 stc8isp.py -p /dev/ttyUSB0 -t 24000000 -f firmware.bin".
|
|
35
|
+
# Perform a power cycle of your MCU (reconnect to power) when prompted.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# ===================================================================================
|
|
39
|
+
# Software Settings
|
|
40
|
+
# ===================================================================================
|
|
41
|
+
|
|
42
|
+
# If the PID/VID of the USB-to-Serial converter is known, it can be defined here.
|
|
43
|
+
# The specified COM port is then ignored, and all ports are automatically searched
|
|
44
|
+
# for the device. Comment the lines to ignore PID/VID.
|
|
45
|
+
#STC_VID = '1A86'
|
|
46
|
+
#STC_PID = '7523'
|
|
47
|
+
|
|
48
|
+
# Define the default COM port here. This will be used if no VID/PID is defined and
|
|
49
|
+
# no COM port is specified within the command line arguments.
|
|
50
|
+
STC_PORT = '/dev/ttyUSB0'
|
|
51
|
+
|
|
52
|
+
# Define the default BAUD rates here. The minimum BAUD rate is used to calibrate the
|
|
53
|
+
# oscillator and should be low to achieve higher accuracy. The maximum BAUD rate is
|
|
54
|
+
# used to transfer the firmware and should be high to achieve higher speed.
|
|
55
|
+
STC_BAUD_MIN = 2400
|
|
56
|
+
STC_BAUD_MAX = 115200
|
|
57
|
+
|
|
58
|
+
# Define time to wait for power cycle in seconds, default: 10
|
|
59
|
+
STC_WAIT = 10
|
|
60
|
+
|
|
61
|
+
# Define minimum and maximum IRC frequency in Hz, that can be specified by the
|
|
62
|
+
# respective command line argument. Expanding the limit values can lead to problems!
|
|
63
|
+
STC_FCPU_MIN = 128000
|
|
64
|
+
STC_FCPU_MAX = 36000000
|
|
65
|
+
|
|
66
|
+
# ===================================================================================
|
|
67
|
+
# Libraries
|
|
68
|
+
# ===================================================================================
|
|
69
|
+
|
|
70
|
+
# Libraries
|
|
71
|
+
import sys
|
|
72
|
+
import time
|
|
73
|
+
import argparse
|
|
74
|
+
import serial
|
|
75
|
+
from serial import Serial
|
|
76
|
+
from serial.tools.list_ports import comports
|
|
77
|
+
|
|
78
|
+
# ===================================================================================
|
|
79
|
+
# Main Function
|
|
80
|
+
# ===================================================================================
|
|
81
|
+
|
|
82
|
+
def _main():
|
|
83
|
+
# Parse command line arguments
|
|
84
|
+
parser = argparse.ArgumentParser(description='Minimal command line interface for stc8isp')
|
|
85
|
+
parser.add_argument('-p', '--port', default=STC_PORT, help='set COM port')
|
|
86
|
+
parser.add_argument('-t', '--trim', help='trim IRC to frequency in Hz')
|
|
87
|
+
parser.add_argument('-e', '--erase', action='store_true', help='perform chip erase (implied with -f)')
|
|
88
|
+
parser.add_argument('-f', '--flash', help='write BIN file to flash')
|
|
89
|
+
args = parser.parse_args(sys.argv[1:])
|
|
90
|
+
|
|
91
|
+
# Checking command line arguments
|
|
92
|
+
if (args.trim is not None) and (int(args.trim) < STC_FCPU_MIN or int(args.trim) > STC_FCPU_MAX):
|
|
93
|
+
sys.stderr.write('ERROR: Trim value out of range (%d - %d)!\n' % (STC_FCPU_MIN, STC_FCPU_MAX))
|
|
94
|
+
sys.exit(1)
|
|
95
|
+
|
|
96
|
+
# Establish connection to USB-to-serial converter
|
|
97
|
+
try:
|
|
98
|
+
print('Connecting to USB-to-serial converter ...')
|
|
99
|
+
isp = Programmer(args.port)
|
|
100
|
+
print('SUCCESS: Connected via', isp.port + '.')
|
|
101
|
+
except Exception as ex:
|
|
102
|
+
sys.stderr.write('ERROR: ' + str(ex) + '!\n')
|
|
103
|
+
sys.exit(1)
|
|
104
|
+
|
|
105
|
+
# Performing actions
|
|
106
|
+
try:
|
|
107
|
+
# Connect to and identify MCU
|
|
108
|
+
print('Waiting for MCU power cycle ...')
|
|
109
|
+
isp.connect()
|
|
110
|
+
print('SUCCESS: Found %s v%s @ %s.' % (isp.chipname, isp.chipverstr, isp.foscstr))
|
|
111
|
+
|
|
112
|
+
# Calibrate user IRC oscillator frequency
|
|
113
|
+
if args.trim is not None:
|
|
114
|
+
print('Calibrating user IRC frequency to %s Hz ...' % args.trim)
|
|
115
|
+
isp.trim(int(args.trim))
|
|
116
|
+
print('SUCCESS: Trimmed to %d Hz (error %.2f%%).' % (isp.osc_freq, 100 * isp.osc_error))
|
|
117
|
+
|
|
118
|
+
# Switch BAUD rate
|
|
119
|
+
print('Switching BAUD rate ...')
|
|
120
|
+
isp.setbaud(STC_BAUD_MAX)
|
|
121
|
+
print('SUCCESS: BAUD rate set to %d.' % STC_BAUD_MAX)
|
|
122
|
+
|
|
123
|
+
# Perform chip erase
|
|
124
|
+
if (args.erase) or (args.flash is not None) or (args.trim is not None):
|
|
125
|
+
print('Performing chip erase ...')
|
|
126
|
+
isp.erase()
|
|
127
|
+
print('SUCCESS: Chip is erased.')
|
|
128
|
+
|
|
129
|
+
# Flash binary file
|
|
130
|
+
if args.flash is not None:
|
|
131
|
+
print('Flashing %s to MCU ...' % args.flash)
|
|
132
|
+
with open(args.flash, 'rb') as f: data = f.read()
|
|
133
|
+
isp.writeflash(0, data)
|
|
134
|
+
print('SUCCESS: %d bytes written.' % len(data))
|
|
135
|
+
|
|
136
|
+
# Write option bytes
|
|
137
|
+
if args.trim is not None:
|
|
138
|
+
print('Writing option bytes ...')
|
|
139
|
+
isp.writeoptions()
|
|
140
|
+
print('SUCCESS: Option bytes written.')
|
|
141
|
+
|
|
142
|
+
# Close connection
|
|
143
|
+
isp.disconnect()
|
|
144
|
+
|
|
145
|
+
except Exception as ex:
|
|
146
|
+
sys.stderr.write('ERROR: ' + str(ex) + '!\n')
|
|
147
|
+
isp.close()
|
|
148
|
+
sys.exit(1)
|
|
149
|
+
|
|
150
|
+
print('DONE.')
|
|
151
|
+
sys.exit(0)
|
|
152
|
+
|
|
153
|
+
# ===================================================================================
|
|
154
|
+
# Programmer Class
|
|
155
|
+
# ===================================================================================
|
|
156
|
+
|
|
157
|
+
class Programmer(Serial):
|
|
158
|
+
def __init__(self, port=STC_PORT, baud=STC_BAUD_MIN):
|
|
159
|
+
# Data frame: 1 start bit, 8 data bit, 1 parity bit set to even, 1 stop bit
|
|
160
|
+
super().__init__(baudrate = baud, parity = serial.PARITY_EVEN, timeout = 0.01)
|
|
161
|
+
|
|
162
|
+
# Use COM port to define device
|
|
163
|
+
if 'STC_VID' not in globals() or 'STC_PID' not in globals():
|
|
164
|
+
self.port = port
|
|
165
|
+
|
|
166
|
+
# Use VID/PID to find device
|
|
167
|
+
else:
|
|
168
|
+
for p in comports():
|
|
169
|
+
if (STC_VID in p.hwid) and (STC_PID in p.hwid):
|
|
170
|
+
self.port = p.device
|
|
171
|
+
break
|
|
172
|
+
|
|
173
|
+
# Open connection
|
|
174
|
+
try:
|
|
175
|
+
self.open()
|
|
176
|
+
except:
|
|
177
|
+
raise Exception('Failed to connect to USB-to-serial converter')
|
|
178
|
+
|
|
179
|
+
#--------------------------------------------------------------------------------
|
|
180
|
+
|
|
181
|
+
# Transmit data block
|
|
182
|
+
def transmit(self, data):
|
|
183
|
+
size = len(data) + 6
|
|
184
|
+
parity = STC_TX_CODE + (size >> 8) + (size & 0xff)
|
|
185
|
+
for x in range(len(data)):
|
|
186
|
+
parity += data[x]
|
|
187
|
+
block = [STC_PREFIX, STC_PREFIX ^ 0xff, STC_TX_CODE]
|
|
188
|
+
block += size.to_bytes(2, byteorder='big')
|
|
189
|
+
block += data
|
|
190
|
+
block += parity.to_bytes(2, byteorder='big')
|
|
191
|
+
block += [STC_SUFFIX]
|
|
192
|
+
self.write(block)
|
|
193
|
+
|
|
194
|
+
# Receive and check data block
|
|
195
|
+
def receive(self):
|
|
196
|
+
reply = self.read(1)
|
|
197
|
+
if len(reply) == 0 or reply[0] != STC_PREFIX:
|
|
198
|
+
return None
|
|
199
|
+
self.timeout = 1
|
|
200
|
+
reply = self.read(2)
|
|
201
|
+
if len(reply) != 2 or reply[0] != (STC_PREFIX ^ 0xff) or reply[1] != STC_RX_CODE:
|
|
202
|
+
raise Exception('Invalid data prefix from MCU')
|
|
203
|
+
size = int.from_bytes(self.read(2), byteorder='big')
|
|
204
|
+
if size < 7:
|
|
205
|
+
raise Exception('Invalid data size from MCU')
|
|
206
|
+
data = self.read(size - 6)
|
|
207
|
+
if len(data) != size - 6:
|
|
208
|
+
raise Exception('Missing data from MCU')
|
|
209
|
+
check = int.from_bytes(self.read(2), byteorder='big')
|
|
210
|
+
suffix = self.read(1)[0]
|
|
211
|
+
if suffix != STC_SUFFIX:
|
|
212
|
+
raise Exception('Invalid data suffix from MCU')
|
|
213
|
+
parity = STC_RX_CODE + (size >> 8) + (size & 0xff)
|
|
214
|
+
for x in range(len(data)):
|
|
215
|
+
parity += data[x]
|
|
216
|
+
if (parity & 0xffff) != check:
|
|
217
|
+
raise Exception('Invalid data checksum from MCU')
|
|
218
|
+
return data
|
|
219
|
+
|
|
220
|
+
# Repeat sending sync character until reply or timeout
|
|
221
|
+
def pulse(self, char, pulsetime=0.01, timeout=10):
|
|
222
|
+
counter = timeout
|
|
223
|
+
while self.in_waiting == 0:
|
|
224
|
+
self.write([char])
|
|
225
|
+
time.sleep(pulsetime)
|
|
226
|
+
counter -= pulsetime
|
|
227
|
+
if counter <= 0:
|
|
228
|
+
raise Exception('Timout waiting for response')
|
|
229
|
+
|
|
230
|
+
#--------------------------------------------------------------------------------
|
|
231
|
+
|
|
232
|
+
# Connect to and identify MCU
|
|
233
|
+
def connect(self):
|
|
234
|
+
# Ping MCU, wait for power cycle, read info bytes
|
|
235
|
+
self.reset_input_buffer()
|
|
236
|
+
waitcounter = STC_WAIT * 100
|
|
237
|
+
reply = None
|
|
238
|
+
while (waitcounter > 0) and (reply is None):
|
|
239
|
+
self.write([STC_CHAR_SYNC])
|
|
240
|
+
reply = self.receive()
|
|
241
|
+
waitcounter -= 1
|
|
242
|
+
if waitcounter == 0:
|
|
243
|
+
raise Exception('Timeout, failed to connect to MCU')
|
|
244
|
+
if reply is None or len(reply) < 42 or reply[0] != STC_RPL_INFO:
|
|
245
|
+
raise Exception('Invalid response from MCU')
|
|
246
|
+
|
|
247
|
+
# Get chip ID
|
|
248
|
+
self.chipid = int.from_bytes(reply[20:22], byteorder='big')
|
|
249
|
+
|
|
250
|
+
# Find chip in dictionary
|
|
251
|
+
self.device = None
|
|
252
|
+
for d in DEVICES:
|
|
253
|
+
if d['id'] == self.chipid:
|
|
254
|
+
self.device = d
|
|
255
|
+
if self.device is None:
|
|
256
|
+
raise Exception('Unsupported chip (ID: 0x%04x)' % self.chipid)
|
|
257
|
+
self.chipname = self.device['name']
|
|
258
|
+
self.flash_size = self.device['flash_size']
|
|
259
|
+
|
|
260
|
+
# Get chip version
|
|
261
|
+
self.chipversion = reply[17]
|
|
262
|
+
self.chipverstr = '%d.%d.%d%c' % (reply[17] >> 4, reply[17] & 0x0f, \
|
|
263
|
+
reply[22] & 0x0f, reply[18])
|
|
264
|
+
|
|
265
|
+
# Get ISP-IRC and USER-IRC oscillator frequencies
|
|
266
|
+
self.fisp = int.from_bytes(reply[13:15], byteorder='big') * self.baudrate
|
|
267
|
+
self.fosc = int.from_bytes(reply[1:5], byteorder='big')
|
|
268
|
+
if self.fosc == 0xffffffff:
|
|
269
|
+
self.foscstr = 'untrimmed frequency'
|
|
270
|
+
else:
|
|
271
|
+
self.foscstr = str(self.fosc) + ' Hz'
|
|
272
|
+
|
|
273
|
+
# Get option bytes
|
|
274
|
+
self.options = reply[9:12] + reply[15:17]
|
|
275
|
+
|
|
276
|
+
# Disconnect from MCU and USB-to-serial converter
|
|
277
|
+
def disconnect(self):
|
|
278
|
+
self.transmit([STC_CMD_EXIT])
|
|
279
|
+
self.close()
|
|
280
|
+
|
|
281
|
+
#--------------------------------------------------------------------------------
|
|
282
|
+
|
|
283
|
+
# Set and calibrate USER-IRC oscillator frequency
|
|
284
|
+
def trim(self, freq):
|
|
285
|
+
# Get global trim values
|
|
286
|
+
self.transmit(STC_BLOCK_TRIM)
|
|
287
|
+
self.pulse(STC_CHAR_TRIM)
|
|
288
|
+
reply = self.receive()
|
|
289
|
+
if reply is None or reply[0] != STC_CMD_TRIM:
|
|
290
|
+
raise Exception('Invalid responde from MCU')
|
|
291
|
+
|
|
292
|
+
# Calculate mean trim value for specified frequency
|
|
293
|
+
freq1 = int.from_bytes(reply[ 2: 4], byteorder='big') * self.baudrate
|
|
294
|
+
freq2 = int.from_bytes(reply[ 4: 6], byteorder='big') * self.baudrate
|
|
295
|
+
freq3 = int.from_bytes(reply[ 6: 8], byteorder='big') * self.baudrate
|
|
296
|
+
freq4 = int.from_bytes(reply[ 8:10], byteorder='big') * self.baudrate
|
|
297
|
+
freq5 = int.from_bytes(reply[10:12], byteorder='big') * self.baudrate
|
|
298
|
+
self.osc_div = 1
|
|
299
|
+
while freq * self.osc_div < freq1: self.osc_div += 1
|
|
300
|
+
if freq * self.osc_div < freq5:
|
|
301
|
+
self.osc_trimx = round( (freq * self.osc_div - freq1) *
|
|
302
|
+
(STC_BLOCK_TRIM[4] - STC_BLOCK_TRIM[2]) / (freq2 - freq1) + STC_BLOCK_TRIM[2] )
|
|
303
|
+
self.osc_bandx = STC_BLOCK_TRIM[3]
|
|
304
|
+
else:
|
|
305
|
+
self.osc_trimx = round( (freq * self.osc_div - freq3) *
|
|
306
|
+
(STC_BLOCK_TRIM[8] - STC_BLOCK_TRIM[6]) / (freq4 - freq3) + STC_BLOCK_TRIM[2] )
|
|
307
|
+
self.osc_bandx = STC_BLOCK_TRIM[7]
|
|
308
|
+
|
|
309
|
+
# Get fine tuned trim values for specified frequency
|
|
310
|
+
count = 24
|
|
311
|
+
block = [0x00, count]
|
|
312
|
+
for x in range(count):
|
|
313
|
+
block += [self.osc_trimx - 2 + (x>>2), self.osc_bandx + (x & 0x03)]
|
|
314
|
+
self.transmit(block)
|
|
315
|
+
self.pulse(STC_CHAR_TRIM)
|
|
316
|
+
reply = self.receive()
|
|
317
|
+
if reply is None or reply[0] != STC_CMD_TRIM:
|
|
318
|
+
raise Exception('Invalid responde from MCU')
|
|
319
|
+
|
|
320
|
+
# Find optimal trim value
|
|
321
|
+
best = sys.maxsize
|
|
322
|
+
for x in range(count):
|
|
323
|
+
freq1 = int.from_bytes(reply[2*x+2:2*x+4], byteorder='big') * self.baudrate
|
|
324
|
+
if abs(freq * self.osc_div - freq1) < best:
|
|
325
|
+
best = abs(freq * self.osc_div - freq1)
|
|
326
|
+
self.osc_freq = round(freq1 / self.osc_div)
|
|
327
|
+
self.osc_trim = self.osc_trimx - 2 + (x>>2)
|
|
328
|
+
self.osc_band = self.osc_bandx + (x & 0x03)
|
|
329
|
+
self.osc_error = (self.osc_freq - freq) / freq
|
|
330
|
+
|
|
331
|
+
# Set/switch BAUD rate
|
|
332
|
+
def setbaud(self, baud=STC_BAUD_MAX):
|
|
333
|
+
# Set BAUD rate
|
|
334
|
+
count = round(65536 - (self.fisp / (4 * baud)))
|
|
335
|
+
block = [STC_CMD_BAUD_SET, self.fosc & 0xff, 0x40]
|
|
336
|
+
block += count.to_bytes(2, byteorder='big')
|
|
337
|
+
block += [0x00, 0x00, 0x97]
|
|
338
|
+
self.transmit(block)
|
|
339
|
+
reply = self.receive()
|
|
340
|
+
if reply is None or reply[0] != STC_CMD_BAUD_SET:
|
|
341
|
+
raise Exception('Failed to set BAUD rate')
|
|
342
|
+
self.baudrate = baud
|
|
343
|
+
time.sleep(0.01)
|
|
344
|
+
|
|
345
|
+
# Check BAUD rate
|
|
346
|
+
if self.chipversion < 0x72:
|
|
347
|
+
self.transmit([STC_CMD_BAUD_CHECK])
|
|
348
|
+
else:
|
|
349
|
+
self.transmit([STC_CMD_BAUD_CHECK, 0, 0, STC_BREAK, STC_BREAK ^ 0xff])
|
|
350
|
+
reply = self.receive()
|
|
351
|
+
if reply is None or reply[0] != STC_CMD_BAUD_CHECK:
|
|
352
|
+
raise Exception('Failed to check BAUD rate')
|
|
353
|
+
|
|
354
|
+
#--------------------------------------------------------------------------------
|
|
355
|
+
|
|
356
|
+
# Erase flash
|
|
357
|
+
def erase(self):
|
|
358
|
+
self.transmit([STC_CMD_ERASE, 0, 0, STC_BREAK, STC_BREAK ^ 0xff])
|
|
359
|
+
reply = self.receive()
|
|
360
|
+
if reply is None or reply[0] != STC_CMD_ERASE:
|
|
361
|
+
raise Exception('Failed to erase flash')
|
|
362
|
+
|
|
363
|
+
# Write data to flash
|
|
364
|
+
def writeflash(self, addr, data):
|
|
365
|
+
size = len(data)
|
|
366
|
+
if size > (self.flash_size - addr):
|
|
367
|
+
raise Exception('Not enough memory')
|
|
368
|
+
cmd = STC_CMD_WRITE
|
|
369
|
+
while size > 0:
|
|
370
|
+
blocksize = min(size, STC_PAGE_SIZE)
|
|
371
|
+
block = [cmd]
|
|
372
|
+
block += addr.to_bytes(2, byteorder='big')
|
|
373
|
+
block += [STC_BREAK, STC_BREAK ^ 0xff]
|
|
374
|
+
block += data[:blocksize]
|
|
375
|
+
self.transmit(block)
|
|
376
|
+
reply = self.receive()
|
|
377
|
+
if reply is None or reply[0] != STC_CMD_WRITE_CONT:
|
|
378
|
+
raise Exception('Failed to write to address 0x%04x' % addr)
|
|
379
|
+
cmd = STC_CMD_WRITE_CONT
|
|
380
|
+
data = data[blocksize:]
|
|
381
|
+
addr += blocksize
|
|
382
|
+
size -= blocksize
|
|
383
|
+
|
|
384
|
+
# Write option bytes
|
|
385
|
+
def writeoptions(self):
|
|
386
|
+
block = [STC_CMD_OPTIONS, 0, 0, STC_BREAK, STC_BREAK ^ 0xff]
|
|
387
|
+
block += STC_BLOCK_OPTIONS1
|
|
388
|
+
block += self.osc_freq.to_bytes(4, byteorder='big')
|
|
389
|
+
block += [self.osc_trim, self.osc_band, self.osc_div]
|
|
390
|
+
block += STC_BLOCK_OPTIONS2
|
|
391
|
+
self.transmit(block)
|
|
392
|
+
reply = self.receive()
|
|
393
|
+
if reply is None or reply[0] != STC_CMD_OPTIONS:
|
|
394
|
+
raise Exception('Failed to write option bytes')
|
|
395
|
+
|
|
396
|
+
# ===================================================================================
|
|
397
|
+
# Device Constants
|
|
398
|
+
# ===================================================================================
|
|
399
|
+
|
|
400
|
+
STC_PAGE_SIZE = 128
|
|
401
|
+
|
|
402
|
+
STC_CHAR_SYNC = 0x7f
|
|
403
|
+
STC_CHAR_TRIM = 0x66
|
|
404
|
+
|
|
405
|
+
STC_PREFIX = 0x46
|
|
406
|
+
STC_BREAK = 0x5a
|
|
407
|
+
STC_SUFFIX = 0x16
|
|
408
|
+
STC_TX_CODE = 0x6a
|
|
409
|
+
STC_RX_CODE = 0x68
|
|
410
|
+
STC_RPL_INFO = 0x50
|
|
411
|
+
|
|
412
|
+
STC_CMD_TRIM = 0x00
|
|
413
|
+
STC_CMD_BAUD_SET = 0x01
|
|
414
|
+
STC_CMD_BAUD_CHECK = 0x05
|
|
415
|
+
STC_CMD_ERASE = 0x03
|
|
416
|
+
STC_CMD_OPTIONS = 0x04
|
|
417
|
+
STC_CMD_WRITE = 0x22
|
|
418
|
+
STC_CMD_WRITE_CONT = 0x02
|
|
419
|
+
STC_CMD_EXIT = 0xff
|
|
420
|
+
|
|
421
|
+
STC_BLOCK_TRIM = [0x00, 0x05, 0x02, 0x00, 0x80, 0x00, 0x00, 0x80,
|
|
422
|
+
0x80, 0x80, 0xfd, 0x00]
|
|
423
|
+
STC_BLOCK_OPTIONS1 = [0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
|
424
|
+
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
425
|
+
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff]
|
|
426
|
+
STC_BLOCK_OPTIONS2 = [0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xbf, 0xf7, 0xff]
|
|
427
|
+
|
|
428
|
+
# ===================================================================================
|
|
429
|
+
# Device Dictionary
|
|
430
|
+
# ===================================================================================
|
|
431
|
+
|
|
432
|
+
DEVICES = [
|
|
433
|
+
{'name': 'STC8H1K16', 'id': 0xF721, 'flash_size': 16384},
|
|
434
|
+
{'name': 'STC8H1K20', 'id': 0xF722, 'flash_size': 20480},
|
|
435
|
+
{'name': 'STC8H1K24', 'id': 0xF723, 'flash_size': 24576},
|
|
436
|
+
{'name': 'STC8H1K28', 'id': 0xF724, 'flash_size': 28672},
|
|
437
|
+
{'name': 'STC8H1K33', 'id': 0xF725, 'flash_size': 33792},
|
|
438
|
+
{'name': 'STC8H1K02', 'id': 0xF731, 'flash_size': 2048},
|
|
439
|
+
{'name': 'STC8H1K04', 'id': 0xF732, 'flash_size': 4096},
|
|
440
|
+
{'name': 'STC8H1K06', 'id': 0xF733, 'flash_size': 6144},
|
|
441
|
+
{'name': 'STC8H1K08', 'id': 0xF734, 'flash_size': 8192},
|
|
442
|
+
{'name': 'STC8H1K10', 'id': 0xF735, 'flash_size': 10240},
|
|
443
|
+
{'name': 'STC8H1K12', 'id': 0xF736, 'flash_size': 12288},
|
|
444
|
+
{'name': 'STC8H1K17', 'id': 0xF737, 'flash_size': 17408},
|
|
445
|
+
{'name': 'STC8H3K16S4', 'id': 0xF741, 'flash_size': 16384},
|
|
446
|
+
{'name': 'STC8H3K32S4', 'id': 0xF742, 'flash_size': 32768},
|
|
447
|
+
{'name': 'STC8H3K60S4', 'id': 0xF743, 'flash_size': 61440},
|
|
448
|
+
{'name': 'STC8H3K64S4', 'id': 0xF744, 'flash_size': 65024},
|
|
449
|
+
{'name': 'STC8H3K48S4', 'id': 0xF745, 'flash_size': 49152},
|
|
450
|
+
{'name': 'STC8H3K16S2', 'id': 0xF749, 'flash_size': 16384},
|
|
451
|
+
{'name': 'STC8H3K32S2', 'id': 0xF74A, 'flash_size': 32768},
|
|
452
|
+
{'name': 'STC8H3K60S2', 'id': 0xF74B, 'flash_size': 61440},
|
|
453
|
+
{'name': 'STC8H3K64S2', 'id': 0xF74C, 'flash_size': 65024},
|
|
454
|
+
{'name': 'STC8H3K48S2', 'id': 0xF74D, 'flash_size': 49152},
|
|
455
|
+
{'name': 'STC8G1K02-20/16P', 'id': 0xF751, 'flash_size': 2048},
|
|
456
|
+
{'name': 'STC8G1K04-20/16P', 'id': 0xF752, 'flash_size': 4096},
|
|
457
|
+
{'name': 'STC8G1K06-20/16P', 'id': 0xF753, 'flash_size': 6144},
|
|
458
|
+
{'name': 'STC8G1K08-20/16P', 'id': 0xF754, 'flash_size': 8192},
|
|
459
|
+
{'name': 'STC8G1K10-20/16P', 'id': 0xF755, 'flash_size': 10240},
|
|
460
|
+
{'name': 'STC8G1K12-20/16P', 'id': 0xF756, 'flash_size': 12288},
|
|
461
|
+
{'name': 'STC8G1K17-20/16P', 'id': 0xF757, 'flash_size': 17408},
|
|
462
|
+
{'name': 'STC8G2K16S4', 'id': 0xF761, 'flash_size': 16384},
|
|
463
|
+
{'name': 'STC8G2K32S4', 'id': 0xF762, 'flash_size': 32768},
|
|
464
|
+
{'name': 'STC8G2K60S4', 'id': 0xF763, 'flash_size': 61440},
|
|
465
|
+
{'name': 'STC8G2K64S4', 'id': 0xF764, 'flash_size': 65024},
|
|
466
|
+
{'name': 'STC8G2K48S4', 'id': 0xF765, 'flash_size': 49152},
|
|
467
|
+
{'name': 'STC8G2K16S2', 'id': 0xF769, 'flash_size': 16384},
|
|
468
|
+
{'name': 'STC8G2K32S2', 'id': 0xF76A, 'flash_size': 32768},
|
|
469
|
+
{'name': 'STC8G2K60S2', 'id': 0xF76B, 'flash_size': 61440},
|
|
470
|
+
{'name': 'STC8G2K64S2', 'id': 0xF76C, 'flash_size': 65024},
|
|
471
|
+
{'name': 'STC8G2K48S2', 'id': 0xF76D, 'flash_size': 49152},
|
|
472
|
+
{'name': 'STC8G1K02T', 'id': 0xF771, 'flash_size': 2048},
|
|
473
|
+
{'name': 'STC8G1K04T', 'id': 0xF772, 'flash_size': 4096},
|
|
474
|
+
{'name': 'STC8G1K06T', 'id': 0xF773, 'flash_size': 6144},
|
|
475
|
+
{'name': 'STC8G1K08T', 'id': 0xF774, 'flash_size': 8192},
|
|
476
|
+
{'name': 'STC8G1K10T', 'id': 0xF775, 'flash_size': 10240},
|
|
477
|
+
{'name': 'STC8G1K12T', 'id': 0xF776, 'flash_size': 12288},
|
|
478
|
+
{'name': 'STC8G1K17T', 'id': 0xF777, 'flash_size': 17408},
|
|
479
|
+
{'name': 'STC8H8K16U', 'id': 0xF781, 'flash_size': 16384},
|
|
480
|
+
{'name': 'STC8H8K32U', 'id': 0xF782, 'flash_size': 32768},
|
|
481
|
+
{'name': 'STC8H8K60U', 'id': 0xF783, 'flash_size': 61440},
|
|
482
|
+
{'name': 'STC8H8K64U', 'id': 0xF784, 'flash_size': 65024},
|
|
483
|
+
{'name': 'STC8H8K48U', 'id': 0xF785, 'flash_size': 49152},
|
|
484
|
+
{'name': 'STC8G1K02A-8P', 'id': 0xF791, 'flash_size': 2048},
|
|
485
|
+
{'name': 'STC8G1K04A-8P', 'id': 0xF792, 'flash_size': 4096},
|
|
486
|
+
{'name': 'STC8G1K06A-8P', 'id': 0xF793, 'flash_size': 6144},
|
|
487
|
+
{'name': 'STC8G1K08A-8P', 'id': 0xF794, 'flash_size': 8192},
|
|
488
|
+
{'name': 'STC8G1K10A-8P', 'id': 0xF795, 'flash_size': 10240},
|
|
489
|
+
{'name': 'STC8G1K12A-8P', 'id': 0xF796, 'flash_size': 12288},
|
|
490
|
+
{'name': 'STC8G1K17A-8P', 'id': 0xF797, 'flash_size': 17408},
|
|
491
|
+
{'name': 'STC8G1K02-8P', 'id': 0xF7A1, 'flash_size': 2048},
|
|
492
|
+
{'name': 'STC8G1K04-8P', 'id': 0xF7A2, 'flash_size': 4096},
|
|
493
|
+
{'name': 'STC8G1K06-8P', 'id': 0xF7A3, 'flash_size': 6144},
|
|
494
|
+
{'name': 'STC8G1K08-8P', 'id': 0xF7A4, 'flash_size': 8192},
|
|
495
|
+
{'name': 'STC8G1K10-8P', 'id': 0xF7A5, 'flash_size': 10240},
|
|
496
|
+
{'name': 'STC8G1K12-8P', 'id': 0xF7A6, 'flash_size': 12288},
|
|
497
|
+
{'name': 'STC8G1K17-8P', 'id': 0xF7A7, 'flash_size': 17408}
|
|
498
|
+
]
|
|
499
|
+
|
|
500
|
+
# ===================================================================================
|
|
501
|
+
|
|
502
|
+
if __name__ == "__main__":
|
|
503
|
+
_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,96 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: stc8isp
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Programming Tool for STC8G/8H 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,STC8G,STC8H,microcontroller
|
|
34
|
+
Classifier: Development Status :: 4 - Beta
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Operating System :: OS Independent
|
|
38
|
+
Classifier: Intended Audience :: Developers
|
|
39
|
+
Classifier: Topic :: Software Development :: Embedded Systems
|
|
40
|
+
Requires-Python: >=3.8
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
License-File: LICENSE
|
|
43
|
+
Requires-Dist: pyserial
|
|
44
|
+
|
|
45
|
+
# stc8isp - Programming Tool for STC8G/8H Microcontrollers
|
|
46
|
+
## Description
|
|
47
|
+
With this tool, STC8G/8H microcontrollers can be flashed via a simple USB-to-serial converter by utilizing the factory built-in embedded 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 stc8isp:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
pip install stc8isp
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Usage
|
|
62
|
+
- Connect your USB-to-serial converter to your MCU as shown below.
|
|
63
|
+
- Run stc8isp.py (see below for arguments).
|
|
64
|
+
- Perform a power cycle of your MCU (reconnect to power) when prompted.
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
USB2SERIAL STC8G/8H
|
|
68
|
+
+--------+ +------+
|
|
69
|
+
| VCC| --/ --> |VCC | interruptible (for power cycle)
|
|
70
|
+
| RXD| --|R|-- |P3.1 | resistor (100R - 1000R)
|
|
71
|
+
| TXD| --|<|-- |P3.0 | diode (e.g. 1N5819)
|
|
72
|
+
| GND| ------- |GND | common ground
|
|
73
|
+
+--------+ +------+
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Usage: stc8isp [-h] [-p PORT] [-t TRIM] [-e] [-f FLASH]
|
|
78
|
+
|
|
79
|
+
Optional arguments:
|
|
80
|
+
-h, --help show this help message and exit
|
|
81
|
+
-p PORT, --port PORT set COM port (default: /dev/ttyUSB0)
|
|
82
|
+
-t TRIM, --trim TRIM trim IRC to frequency in Hz (128000 - 36000000)
|
|
83
|
+
-e, --erase perform chip erase (implied with -f)
|
|
84
|
+
-f FLASH, --flash FLASH write BIN file to flash
|
|
85
|
+
|
|
86
|
+
Example:
|
|
87
|
+
stc8isp -p /dev/ttyUSB0 -t 24000000 -f firmware.bin
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Links
|
|
91
|
+
- [MCU Flash Tools](https://github.com/wagiminator/MCU-Flash-Tools)
|
|
92
|
+
- [MCU Templates](https://github.com/wagiminator/MCU-Templates)
|
|
93
|
+
- [MCU Development Boards](https://github.com/wagiminator/Development-Boards)
|
|
94
|
+
- [AVR Development Boards](https://github.com/wagiminator/AVR-Development-Boards)
|
|
95
|
+
- [AVR Programmers](https://github.com/wagiminator/AVR-Programmer)
|
|
96
|
+
- [SAMD Development Boards](https://github.com/wagiminator/SAMD-Development-Boards)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
stc8isp/__init__.py,sha256=XKv8l5d8-9NePOt0aG6XrBkYhrYiLMvyruNlTw2mw_E,27
|
|
2
|
+
stc8isp/stc8isp.py,sha256=YR_bE0-WgRHF6MLzruyhIQ89EmCtRF6gGAnxWd4Fj24,22004
|
|
3
|
+
stc8isp-0.3.0.dist-info/LICENSE,sha256=kph2e2d1k_-VvrU6YbwdbUJ2GKXsFgBGCSym5wVv2j8,1089
|
|
4
|
+
stc8isp-0.3.0.dist-info/METADATA,sha256=N7rMwy4AeyFlc8WH_nUCjjtF5pJ4uRH9eXdxxIYVTg0,4133
|
|
5
|
+
stc8isp-0.3.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
|
6
|
+
stc8isp-0.3.0.dist-info/entry_points.txt,sha256=ap6OJ7WEYqcNXaPwz_V44AFiiZaPStMRjOIHWIvSA3s,42
|
|
7
|
+
stc8isp-0.3.0.dist-info/top_level.txt,sha256=ISZeYRachG8dOJ63E9Ngjv1gmBusWdtnyXXYrPv0XnA,8
|
|
8
|
+
stc8isp-0.3.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
stc8isp
|