Add STC15 series support

So far this is only based on reverse engineering what's needed
for programming STC15F104E. It works, but it is incomplete.
This commit is contained in:
Grigori Goronzy 2014-01-11 16:43:37 +01:00
parent 903f6ca451
commit ba8d26059c
3 changed files with 562 additions and 54 deletions

81
doc/stc15-options.txt Normal file
View File

@ -0,0 +1,81 @@
Model-specific configuration registers
Placement of configuration values
"~" means the bit is a negated boolean. Sometimes values overlap,
depending on MCU model.
In STC15 series, the first 13 MCS bytes have active values. Generally,
unused bits should be set to 1.
MCS0
----
MSB 7 6 5 4 3 2 1 0 LSB
RSPEN
RSPEN := RESET pin enable
MCS1
----
MSB 7 6 5 4 3 2 1 0 LSB
EEIH LVRS LVD2 LVD1 LVD0
EEIH := inhibit EEPROM writes in low-voltage conditions enable
LVRS := low-voltage reset enable
LVD2...LVD0 := low voltage detection threshold
LVD2 LVD1 LVD0 value
0 0 0 setting 0 (e.g. 3.14V)
0 0 1 setting 1 (e.g. 3.28V)
0 1 0 setting 2 (e.g. 3.43V)
0 1 1 setting 3 (e.g. 3.61V)
1 0 0 setting 4 (e.g. 3.82V)
1 0 1 setting 5 (e.g. 4.05V)
1 1 0 unknown
1 1 1 unknown
The exact voltages depend on MCU model.
MCS2
----
MSB 7 6 5 4 3 2 1 0 LSB
~WDEN ~WDSTP WDPS2 WDPS1 WDPS0
~WDEN := watchdog enable after power-on-reset
~WDSTP := stop watchdog counter in idle mode
WDPS2...WDPS0 := watchdog counter prescaler
WDPS2 WDPS1 WDPS0 divisior
0 0 0 2
0 0 1 4
0 1 0 8
0 1 1 16
1 0 0 32
1 0 1 64
1 1 0 128
1 1 1 256
This is completely similar to STC12.
MCS3...MCS11
------------
All bytes set to 0xff.
MCS12
-----
MSB 7 6 5 4 3 2 1 0 LSB
~EREE ~BSLD
~EREE := enable eeprom erase next time MCU is programmed
~BSLD := enable BSL pin detect; i.e. BSL is only enabled if P1.0/P1.1
(or others, depends on MCU model) are held low on POR.
This is like MCS3 of STC12.

92
doc/stc15-protocol.txt Normal file
View File

@ -0,0 +1,92 @@
STC15 reverse engineering
Note: so far only based on STC15F104E!
Basic differences between STC12 and STC15
* Initial MCU response is an ack (0x80) packet. Host needs to respond
with the same ack and pulse 0x7f again, then MCU sends the info
packet.
* Frequency timings sent with info packet are different; the calculation
is the same but only four timings are sent, followed by two other
unknown timings and two zero words.
* A new handshake is used to tune the RC oscillator for a given
frequency.
* The baudrate isn't changed with a complicated handshake, it is just
switched to with a 0x8e type packet.
This may be different on other MCUs that have a hardware UART.
* Transfers use 64 bytes block size.
Possibly that's because the 15F104E only has 128 bytes RAM. It
might use bigger blocks on MCUs with more RAM.
* Position of many option bits has changed, and more bits are used.
The RC oscillator calibration
Theory of operation:
* Host sends a sequence of challenges. These are values to be
programmed into an internal RC oscillator calibration register.
* Host sends 0x7f pulses
* MCU sends back responses, which are the runtime of the baudrate
timing counter (similar to the info packet)
* Host repeats this with finer trimmed challenge values.
* Host determines calibration value with the lowest error.
* Host sends baudrate switch packet
* Host sends option packet to program frequency after flash programming
The STC software uses a fixed set of coarse grained trim values to
try. These are:
sequence clock (MHz)
0x1800 0x1880 0x1880 0x18ff [4, 7.5]
0x1880 0x18ff 0x5800 0x5880 (7.5, 10]
0x5800 0x5880 0x5880 0x58ff (10, 15]
0x5880 0x58ff 0x9800 0x9880 (15, 21]
0x9800 0x9880 0x9880 0x98ff (21, 31]
0xd800 0xd880 0xd880 0xd8b4 (31, 40]
In addition it sends a sequence for the programming speed:
0x5800 0x5880 for normal speed and 0x9800 0x9880 for high
speed programming.
Then, by linear interpolation, it choses a suitable range of
fine-tuning trim values to try according to the counter values sent
by the MCU.
The programming speed trim value is only determined by linear
interpolation of the two trim challenges sent in the first round of
calibration. This seems to be good enough.
New packets host2mcu
--------------------
1. RC calibration challenge
Payload: 0x65, T0, .., T6, 0xff, 0xff, 0x06, CNT,
TR00, TR01, 0x02, 0x00,
TR10, TR11, 0x02, 0x00,
...
T0...T6 := trim constants, from info packet
CNT := number of calibration challenges (max 11)
TRxx := calibration challenge trim values
2. Baudrate switch
Payload: 0x8e, TR0, TR1, BDIV, 0xa1, 0x64, FC,
0x00, IAP, 0x20, 0xff, 0x00
TR0, TR1 := trim value for programming frequency
(normal = 11.0592 MHz, highspeed = 22.1184 MHz)
BDIV := baud rate divider (normal: baud = 115200 / BDIV, highspeed: baud = 230400 / BDIV)
FC := some frequency constant, normal: 0xdc, highspeed: 0xb8
IAP := IAP delay, normal: 0x83, highspeed: 0x81

443
stcgal.py
View File

@ -27,8 +27,6 @@
TODO:
- some more documentation / comments
- private member naming, other style issues
- Prepare for STC89/STC15 protocols
"""
import serial
@ -734,28 +732,7 @@ class MCUModelDatabase:
print(" Code flash: %.1f KB" % (model.code / 1024.0))
print(" EEPROM flash: %.1f KB" % (model.eeprom / 1024.0))
class Stc12Option:
"""Manipulate STC10/11/12 series option bytes"""
def __init__(self, msr):
self.msr = bytearray(msr)
"""list of options and their handlers"""
self.options = (
("reset_pin_enabled", self.get_reset_pin_enabled, self.set_reset_pin_enabled),
("low_voltage_detect", self.get_low_voltage_detect, self.set_low_voltage_detect),
("oscillator_stable_delay", self.get_osc_stable_delay, self.set_osc_stable_delay),
("power_on_reset_delay", self.get_por_delay, self.set_por_delay),
("clock_gain", self.get_clock_gain, self.set_clock_gain),
("clock_source", self.get_clock_source, self.set_clock_source),
("watchdog_por_enabled", self.get_watchdog, self.set_watchdog),
("watchdog_stop_idle", self.get_watchdog_idle, self.set_watchdog_idle),
("watchdog_prescale", self.get_watchdog_prescale, self.set_watchdog_prescale),
("eeprom_erase_enabled", self.get_ee_erase, self.set_ee_erase),
("bsl_pindetect_enabled", self.get_pindetect, self.set_pindetect),
)
class BaseOption:
def print(self):
print("Target options:")
for name, get_func, _ in self.options:
@ -778,6 +755,29 @@ class Stc12Option:
def get_msr(self):
return bytes(self.msr)
class Stc12Option(BaseOption):
"""Manipulate STC10/11/12 series option bytes"""
def __init__(self, msr):
assert len(msr) == 4
self.msr = bytearray(msr)
"""list of options and their handlers"""
self.options = (
("reset_pin_enabled", self.get_reset_pin_enabled, self.set_reset_pin_enabled),
("low_voltage_detect", self.get_low_voltage_detect, self.set_low_voltage_detect),
("oscillator_stable_delay", self.get_osc_stable_delay, self.set_osc_stable_delay),
("power_on_reset_delay", self.get_por_delay, self.set_por_delay),
("clock_gain", self.get_clock_gain, self.set_clock_gain),
("clock_source", self.get_clock_source, self.set_clock_source),
("watchdog_por_enabled", self.get_watchdog, self.set_watchdog),
("watchdog_stop_idle", self.get_watchdog_idle, self.set_watchdog_idle),
("watchdog_prescale", self.get_watchdog_prescale, self.set_watchdog_prescale),
("eeprom_erase_enabled", self.get_ee_erase, self.set_ee_erase),
("bsl_pindetect_enabled", self.get_pindetect, self.set_pindetect),
)
def get_reset_pin_enabled(self):
return bool(self.msr[0] & 1)
@ -882,6 +882,104 @@ class Stc12Option:
self.msr[3] |= 0x01 if not val else 0x00
class Stc15Option(BaseOption):
def __init__(self, msr):
assert len(msr) == 13
self.msr = bytearray(msr)
self.options = (
("reset_pin_enabled", self.get_reset_pin_enabled, self.set_reset_pin_enabled),
("watchdog_por_enabled", self.get_watchdog, self.set_watchdog),
("watchdog_stop_idle", self.get_watchdog_idle, self.set_watchdog_idle),
("watchdog_prescale", self.get_watchdog_prescale, self.set_watchdog_prescale),
("low_voltage_reset", self.get_lvrs, self.set_lvrs),
("low_voltage_threshold", self.get_low_voltage, self.set_low_voltage),
("eeprom_lvd_inhibit", self.get_eeprom_lvd, self.set_eeprom_lvd),
("eeprom_erase_enabled", self.get_ee_erase, self.set_ee_erase),
("bsl_pindetect_enabled", self.get_pindetect, self.set_pindetect),
)
def set_trim(self, val):
self.msr[3:5] = struct.pack(">H", val)
def get_reset_pin_enabled(self):
return bool(self.msr[0] & 16)
def set_reset_pin_enabled(self, val):
val = Utils.to_bool(val);
self.msr[0] &= 0xef
self.msr[0] |= 0x10 if bool(val) else 0x00
def get_watchdog(self):
return not bool(self.msr[2] & 32)
def set_watchdog(self, val):
val = Utils.to_bool(val);
self.msr[2] &= 0xdf
self.msr[2] |= 0x20 if not val else 0x00
def get_watchdog_idle(self):
return not bool(self.msr[2] & 8)
def set_watchdog_idle(self, val):
val = Utils.to_bool(val);
self.msr[2] &= 0xf7
self.msr[2] |= 0x08 if not val else 0x00
def get_watchdog_prescale(self):
return 2 ** (((self.msr[2]) & 0x07) + 1)
def set_watchdog_prescale(self, val):
val = Utils.to_int(val)
wd_vals = {2: 0, 4: 1, 8: 2, 16: 3, 32: 4, 64: 5, 128: 6, 256: 7}
if val not in wd_vals.keys():
raise ValueError("must be one of %s" % list(wd_vals.keys()))
self.msr[2] &= 0xf8
self.msr[2] |= wd_vals[val]
def get_lvrs(self):
return bool(self.msr[1] & 64)
def set_lvrs(self, val):
val = Utils.to_bool(val);
self.msr[1] &= 0xbf
self.msr[1] |= 0x40 if val else 0x00
def get_eeprom_lvd(self):
return bool(self.msr[1] & 128)
def set_eeprom_lvd(self, val):
val = Utils.to_bool(val);
self.msr[1] &= 0x7f
self.msr[1] |= 0x80 if val else 0x00
def get_low_voltage(self):
return self.msr[1] & 0x07
def set_low_voltage(self, val):
val = Utils.to_int(val)
if val not in range(0, 8):
raise ValueError("must be one of %s" % list(range(0, 8)))
self.msr[1] &= 0xf8
self.msr[1] |= val
def get_ee_erase(self):
return not bool(self.msr[12] & 2)
def set_ee_erase(self, val):
val = Utils.to_bool(val);
self.msr[12] &= 0xfd
self.msr[12] |= 0x02 if not val else 0x00
def get_pindetect(self):
return not bool(self.msr[12] & 1)
def set_pindetect(self, val):
val = Utils.to_bool(val);
self.msr[12] &= 0xfe
self.msr[12] |= 0x01 if not val else 0x00
class Stc12Protocol:
"""Protocol handler for STC 10/11/12 series"""
@ -900,6 +998,9 @@ class Stc12Protocol:
"""block size for programming flash"""
PROGRAM_BLOCKSIZE = 128
"""countdown value for flash erase"""
ERASE_COUNTDOWN = 0x0d
def __init__(self, port, baud_handshake, baud_transfer):
self.port = port
self.baud_handshake = baud_handshake
@ -989,8 +1090,8 @@ class Stc12Protocol:
self.ser.write(packet)
self.ser.flush()
def decode_status_packet(self, packet):
"""Decode status packet"""
def initialize_status(self, packet):
"""Decode status packet and store basic MCU info"""
self.mcu_magic, = struct.unpack(">H", packet[20:22])
@ -1043,32 +1144,18 @@ class Stc12Protocol:
print("Target frequency: %.3f MHz" % (self.mcu_clock_hz / 1E6))
print("Target bootloader version: %s" % self.mcu_bsl_version)
def connect(self):
"""Connect to MCU and initialize communication.
def pulse(self):
"""Send a sequence of 0x7f bytes for synchronization"""
Set up serial port, send sync sequence and get part info.
"""
self.ser = serial.Serial(port=self.port, baudrate=self.baud_handshake,
parity=serial.PARITY_EVEN)
# send sync, and wait for MCU response
print("Waiting for MCU, please cycle power...", end="")
sys.stdout.flush()
while True:
self.ser.write(b"\x7f")
self.ser.flush()
time.sleep(0.015)
if self.ser.inWaiting() > 0: break
print("done")
# read status packet
status_packet = self.read_packet()
if status_packet[0] != 0x50:
raise RuntimeError("wrong magic in status packet")
self.decode_status_packet(status_packet)
def initialize_model(self):
"""Initialize model-specific information"""
# get model info
try:
self.model = MCUModelDatabase.find_model(self.mcu_magic)
except NameError:
@ -1079,10 +1166,41 @@ class Stc12Protocol:
magic=self.mcu_magic, total=63488, code=63488, eeprom=0)
self.print_mcu_info()
def get_status_packet(self):
"""Read and decode status packet"""
status_packet = self.read_packet()
if status_packet[0] != 0x50:
raise RuntimeError("wrong magic in status packet")
return status_packet
def initialize_options(self, status_packet):
"""Initialize options"""
# create option state
self.options = Stc12Option(status_packet[23:27])
self.options.print()
def connect(self):
"""Connect to MCU and initialize communication.
Set up serial port, send sync sequence and get part info.
"""
self.ser = serial.Serial(port=self.port, baudrate=self.baud_handshake,
parity=serial.PARITY_EVEN)
# send sync, and wait for MCU response
print("Waiting for MCU, please cycle power...", end="")
sys.stdout.flush()
self.pulse()
print("done")
status_packet = self.get_status_packet()
self.initialize_status(status_packet)
self.initialize_model()
self.initialize_options(status_packet)
def handshake(self):
"""Do baudrate handshake
@ -1134,29 +1252,29 @@ class Stc12Protocol:
blks = (erase_size + 255) // 256
size = (flash_size + 255) // 256
print("Erasing %d blocks..." % blks)
packet = bytes([0x84, 0x00, 0x00, blks, 0x00, 0x00, size,
packet = bytes([0x84, 0xff, 0x00, blks, 0x00, 0x00, size,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00])
for i in range(0x80, 0x0d, -1): packet += bytes([i])
for i in range(0x80, self.ERASE_COUNTDOWN, -1): packet += bytes([i])
self.write_packet(packet)
response = self.read_packet()
if response[0] != 0x00:
raise RuntimeError("wrong magic in erase packet")
def program_flash(self, addr, data):
def program_flash(self, data):
"""Program the MCU's flash memory.
Write data into flash memory, starting at the given address. The address
should be 128 byte aligned.
Write data into flash memory, using the PROGRAM_BLOCKSIZE
as the block size (depends on MCU's RAM size).
"""
print("Writing %d bytes..." % len(data), end="")
sys.stdout.flush()
for i in range(addr, addr+len(data), 128):
for i in range(0, len(data), self.PROGRAM_BLOCKSIZE):
packet = bytes(3)
packet += struct.pack(">H", i)
packet += struct.pack(">H", self.PROGRAM_BLOCKSIZE)
packet += data[i-addr:i-addr+128]
packet += data[i:i+self.PROGRAM_BLOCKSIZE]
while len(packet) < self.PROGRAM_BLOCKSIZE + 7: packet += b"\x00"
csum = sum(packet[7:]) & 0xff
self.write_packet(packet)
@ -1181,7 +1299,6 @@ class Stc12Protocol:
self.options.set_option(name, value)
def program_options(self):
#self.options.print()
print("Setting options...")
msr = self.options.get_msr()
packet = bytes([0x8d, msr[0], msr[1], msr[2], msr[3],
@ -1207,12 +1324,227 @@ class Stc12Protocol:
self.ser.close()
print("Disconnected!")
class Stc15Protocol(Stc12Protocol):
ERASE_COUNTDOWN = 0x5e
PROGRAM_BLOCKSIZE = 64
def __init__(self, port, handshake, baud, trim):
Stc12Protocol.__init__(self, port, handshake, baud)
self.trim_frequency = trim
self.trim_data = None
self.frequency_counter = 0
def initialize_options(self, status_packet):
"""Initialize options"""
# create option state
self.options = Stc15Option(status_packet[23:36])
self.options.print()
def get_status_packet(self):
"""Read and decode status packet"""
status_packet = self.read_packet()
if status_packet[0] == 0x80:
# need to re-ack
packet = bytes([0x80])
self.write_packet(packet)
self.pulse()
status_packet = self.read_packet()
if status_packet[0] != 0x50:
raise RuntimeError("wrong magic in status packet")
return status_packet
def initialize_status(self, packet):
"""Decode status packet and store basic MCU info"""
self.mcu_magic, = struct.unpack(">H", packet[20:22])
freq_counter = 0
for i in range(4):
freq_counter += struct.unpack(">H", packet[1+2*i:3+2*i])[0]
freq_counter /= 4.0
self.mcu_clock_hz = (self.baud_handshake * freq_counter * 12.0) / 7.0
bl_version, bl_stepping = struct.unpack("BB", packet[17:19])
self.mcu_bsl_version = "%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
chr(bl_stepping))
self.trim_data = packet[51:58]
self.freq_counter = freq_counter
def get_trim_sequence(self, frequency):
"""Return frequency-specific coarse trim sequence"""
packet = bytes()
if frequency < 7.5E6:
packet += bytes([0x18, 0x00, 0x02, 0x00])
packet += bytes([0x18, 0x80, 0x02, 0x00])
packet += bytes([0x18, 0x80, 0x02, 0x00])
packet += bytes([0x18, 0xff, 0x02, 0x00])
elif frequency < 10E6:
packet += bytes([0x18, 0x80, 0x02, 0x00])
packet += bytes([0x18, 0xff, 0x02, 0x00])
packet += bytes([0x58, 0x00, 0x02, 0x00])
packet += bytes([0x58, 0xff, 0x02, 0x00])
elif frequency < 15E6:
packet += bytes([0x58, 0x00, 0x02, 0x00])
packet += bytes([0x58, 0x80, 0x02, 0x00])
packet += bytes([0x58, 0x80, 0x02, 0x00])
packet += bytes([0x58, 0xff, 0x02, 0x00])
elif frequency < 21E6:
packet += bytes([0x58, 0x80, 0x02, 0x00])
packet += bytes([0x58, 0xff, 0x02, 0x00])
packet += bytes([0x98, 0x00, 0x02, 0x00])
packet += bytes([0x98, 0x80, 0x02, 0x00])
elif frequency < 31E6:
packet += bytes([0x98, 0x00, 0x02, 0x00])
packet += bytes([0x98, 0x80, 0x02, 0x00])
packet += bytes([0x98, 0x80, 0x02, 0x00])
packet += bytes([0x98, 0xff, 0x02, 0x00])
else:
packet += bytes([0xd8, 0x00, 0x02, 0x00])
packet += bytes([0xd8, 0x80, 0x02, 0x00])
packet += bytes([0xd8, 0x80, 0x02, 0x00])
packet += bytes([0xd8, 0xb4, 0x02, 0x00])
return packet
def handshake(self):
"""Initiate and do the frequency adjustment and baudrate
switch handshake.
This rather complicated handshake trims the MCU's calibrated RC
frequency and switches the baud rate at the same time.
Flash programming uses a fixed frequency and that frequency is
calibrated along with the frequency specified by the user.
"""
user_speed = self.trim_frequency
if user_speed <= 0: user_speed = self.mcu_clock_hz
program_speed = 11059200
user_count = int(self.freq_counter * (user_speed / self.mcu_clock_hz))
program_count = int(self.freq_counter * (program_speed / self.mcu_clock_hz))
# Initiate handshake
print("Trimming frequency...")
packet = bytes([0x50, 0x00, 0x00, 0x36, 0x01])
packet += struct.pack(">H", self.mcu_magic)
self.write_packet(packet)
response = self.read_packet()
if response[0] != 0x8f:
raise RuntimeError("wrong magic in handshake packet")
# trim challenge-response, first round
packet = bytes([0x65])
packet += self.trim_data
packet += bytes([0xff, 0xff, 0x06, 0x06])
# add trim challenges for target frequency
packet += self.get_trim_sequence(user_speed)
# add trim challenge for program frequency
# TODO: high program frequency
packet += bytes([0x58, 0x00, 0x02, 0x00])
packet += bytes([0x58, 0x80, 0x02, 0x00])
self.write_packet(packet)
self.pulse()
response = self.read_packet()
if response[0] != 0x65:
raise RuntimeError("wrong magic in handshake packet")
# determine programming speed trim value
target_trim_a, target_count_a = struct.unpack(">HH", response[28:32])
target_trim_b, target_count_b = struct.unpack(">HH", response[32:36])
m = (target_trim_b - target_trim_a) / (target_count_b - target_count_a)
n = target_trim_a - m * target_count_a
program_trim = round(m * program_count + n)
# determine trim trials for second round
trim_a, count_a = struct.unpack(">HH", response[12:16])
trim_b, count_b = struct.unpack(">HH", response[16:20])
trim_c, count_c = struct.unpack(">HH", response[20:24])
trim_d, count_d = struct.unpack(">HH", response[24:28])
# select suitable coarse trim range
if count_c <= user_count and count_d >= user_count:
target_trim_a = trim_c
target_trim_b = trim_d
target_count_a = count_c
target_count_b = count_d
else:
target_trim_a = trim_a
target_trim_b = trim_b
target_count_a = count_a
target_count_b = count_b
# linear interpolate to find range to try next
m = (target_trim_b - target_trim_a) / (target_count_b - target_count_a)
n = target_trim_a - m * target_count_a
target_trim = round(m * user_count + n)
target_trim_start = min(max(target_trim - 5, target_trim_a), target_trim_b)
# trim challenge-response, second round
packet = bytes([0x65])
packet += self.trim_data
packet += bytes([0xff, 0xff, 0x06, 0x0B])
for i in range(11):
packet += struct.pack(">H", target_trim_start + i)
packet += bytes([0x02, 0x00])
self.write_packet(packet)
self.pulse()
response = self.read_packet()
if response[0] != 0x65:
raise RuntimeError("wrong magic in handshake packet")
# determine best trim value
best_trim = 0
best_count = 65535
for i in range(11):
trim, count = struct.unpack(">HH", response[12+4*i:16+4*i])
if abs(count - user_count) < abs(best_count - user_count):
best_trim = trim
best_count = count
final_freq = (best_count / self.freq_counter) * self.mcu_clock_hz
print("Trimmed to %.03f MHz!" % (final_freq / 1E6))
self.options.set_trim(best_trim)
# finally, switch baudrate
print("Switching to %d baud..." % self.baud_transfer)
packet = bytes([0x8e])
packet += struct.pack(">H", program_trim)
packet += struct.pack(">B", 115200 // self.baud_transfer)
packet += bytes([0xa1, 0x64, 0xdc, 0x00, 0x83, 0x20, 0xff, 0x00])
self.write_packet(packet)
time.sleep(0.2)
self.ser.baudrate = self.baud_transfer
response = self.read_packet()
if response[0] != 0x84:
raise RuntimeError("wrong magic in handshake packet")
def program_options(self):
print("Setting options...")
msr = self.options.get_msr()
packet = bytes([0x8d])
packet += msr
packet += bytes([0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
self.write_packet(packet)
response = self.read_packet()
if response[0] != 0x50:
raise RuntimeError("wrong magic in option packet")
class StcGal:
"""STC ISP flash tool frontend"""
def __init__(self, opts):
self.opts = opts
self.protocol = Stc12Protocol(opts.port, opts.handshake, opts.baud)
if opts.protocol == "stc12":
self.protocol = Stc12Protocol(opts.port, opts.handshake, opts.baud)
else:
self.protocol = Stc15Protocol(opts.port, opts.handshake, opts.baud, opts.trim)
def emit_options(self, options):
for o in options:
@ -1229,6 +1561,7 @@ class StcGal:
return 2
except RuntimeError as e:
print("Communication error: %s" % e, file=sys.stderr)
self.protocol.disconnect()
return 1
except serial.serialutil.SerialException as e:
print("Serial communication error: %s" % e, file=sys.stderr)
@ -1266,7 +1599,7 @@ class StcGal:
self.protocol.handshake()
self.protocol.erase_flash(len(bindata), code_size)
self.protocol.program_flash(0, bindata)
self.protocol.program_flash(bindata)
self.protocol.program_options()
self.protocol.disconnect()
return 0
@ -1292,10 +1625,12 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser(description="STC10/11/12 series MCU ISP flash tool")
parser.add_argument("code_binary", help="code segment binary file to flash", type=argparse.FileType("rb"), nargs='?')
parser.add_argument("eeprom_binary", help="eeprom segment binary file to flash", type=argparse.FileType("rb"), nargs='?')
parser.add_argument("-P", "--protocol", help="protocol version", choices=["stc12", "stc15"], default="stc12")
parser.add_argument("-p", "--port", help="serial port device", default="/dev/ttyUSB0")
parser.add_argument("-b", "--baud", help="transfer baud rate (default: 19200)", type=BaudType(), default=19200)
parser.add_argument("-l", "--handshake", help="handshake baud rate (default: 2400)", type=BaudType(), default=2400)
parser.add_argument("-o", "--option", help="set option (can be used multiple times)", action="append")
parser.add_argument("-t", "--trim", help="RC oscillator frequency in Hz (STC15 series only)", type=int, default=-1)
opts = parser.parse_args()
# run programmer