12 Commits

Author SHA1 Message Date
b070346e70 WIP: refactor and add STC12B support
This adds support for a new protocol variant called STC12B for
STC12xx52/56 and possibly others. It is STC12 but with a different
option packet. The current implementation uses mix-ins, but I am not
sure yet if I like the modified architecture.
2016-05-19 08:23:44 +02:00
979d7f513f Get rid of USB bmRequestType constants
These constants were calculated on class loading, which didn't work
without pyusb. USB support is going to remain optional.
2016-05-18 16:40:09 +02:00
fce2f01232 Extract option classes into separate file 2016-05-18 02:38:13 +02:00
854f36100b stc12: fix option handling
MCS3 index was wrong. Also, write MCS3 to two possible indices in
the option set packet.

Addresses grigorig/stcgal#14.
2016-05-18 02:14:02 +02:00
92f4def11a stc12a: revamp option handling
Completely revamp option handling. This fixes a wrong index of MCS4,
which is now renamed to MCS3. Now programming should be exactly
similar to STC-ISP 6.85M.

This also renames the values of the low_voltage_reset option for
clarity.

Also update the documentation and clarity the meaning of the option
according to protocol family.

Addresses grigorig/stcgal#14.
2016-05-18 01:40:08 +02:00
6c0af88551 frontend: always pad to 512 bytes, fill with 0xff
This seems to be the default of STC-ISP, so let's use it for possibly
improved compatibility.
2016-05-18 00:56:16 +02:00
366a3a5bd3 Fix EEPROM size of STC12x54 series in MCU database 2016-05-15 02:39:51 +02:00
c046e886e3 usb15: add protocol notes 2016-05-15 02:31:36 +02:00
7ba95eab68 stc15/usb15: add password feature notes
I'm not going to implement this right now as it is rather dangerous.
2016-05-15 02:30:25 +02:00
61a4fa0e4f stc89: add missing output flush 2016-05-14 21:37:27 +02:00
da5f6678c5 usb15: sanity check on status packet reads
If a previous stcgal invocation is aborted, we can be in a bad state
upon connect. Add a simple sanity check based on packet length to
detect this and drop unsuitable packets.
2016-05-14 21:03:07 +02:00
a8f141584d Merge branch 'usbisp'
It is still experimental, but the changes are not very invasive, so why
not include it right now. Closes grigorig/stcgal#10.
2016-05-14 13:26:57 +02:00
9 changed files with 779 additions and 655 deletions

View File

@ -117,6 +117,7 @@ protocols and MCU series is as follows:
* ```stc89``` STC 89/90 series
* ```stc12a``` STC12Cx052AD and possibly others
* ```stc12b``` STC12x52xx series, STC12x56xx series and possibly others
* ```stc12``` Most STC10/11/12 series (default)
* ```stc15a``` STC15x104E and STC15x204E(A) series
* ```stc15``` Most STC15 series
@ -240,7 +241,9 @@ Option key | Possible values | Protocols/Models | Descri
```ale_enabled``` | true/false | STC89 only | ALE pin enabled if true, normal GPIO if false
```xram_enabled``` | true/false | STC89 only | Use internal XRAM (STC89 only)
```watchdog_por_enabled``` | true/false | All | Watchdog state after power-on reset (POR)
```low_voltage_reset ``` | true/false | STC12A+ | Low-voltage reset (brownout)
```low_voltage_reset``` | low/high | STC12A/STC12 | Low-voltage reset level (low: ~3.3V, high: ~3.7V)
```low_voltage_reset``` | true/false | STC12 | Enable RESET2 pin low voltage detect
```low_voltage_reset``` | true/false | STC15A | Enable low-voltage reset (brownout)
```clock_source``` | internal/external | STC12A+ with XTAL | Use internal (RC) or external (crystal) clock
```watchdog_stop_idle``` | true/false | STC12A+ | Stop watchdog in IDLE mode
```watchdog_prescale``` | 2,4,8,...,256 | STC12A+ | Watchdog timer prescaler, must be a power of two.

View File

@ -25,12 +25,12 @@ for i in range(MCU_TABLE_SIZE):
inp.seek(mcu_name_offset)
name_str = inp.read(16).split(b'\00')[0].decode("ascii")
# XXX: 1 KB are reserved one *some* MCUs for some reason
#if ee_size > 0 and not name_str.startswith("IAP"):
# ee_size -= 1024
# TODO: With some MCUs, the amount of available EEPROM depends on the BSL version.
# Generally, newer BSLs free up a KB of additional EEPROM. Currently, always the
# maximum amount (with newer BSL) is reported.
# STC12C54xx always have 12 KB eeprom
if name_str.startswith("STC12C54"):
# STC12x54xx always have 12 KB eeprom
if name_str.startswith("STC12C54") or name_str.startswith("STC12LE54"):
ee_size = 12 * 1024
print("MCUModel(name='%s', magic=0x%02x%02x, total=%d, code=%d, eeprom=%d)," %

View File

@ -4,7 +4,7 @@ Placement of configuration values
"~" means the bit is a negated boolean. Sometimes values overlap,
depending on MCU model.
In STC12A series, the first 4 MCS bytes have active
In STC12A series, the first 7 MCS bytes have active
values. Generally, unused bits should be set to 1.
MCS0
@ -47,14 +47,9 @@ MSB 7 6 5 4 3 2 1 0 LSB
(or others, depends on MCU model) are held low on POR.
MCS3
----
Unused.
MCS4
----
MCS3 (at index 6!)
------------------
MSB 7 6 5 4 3 2 1 0 LSB
LVD

View File

@ -111,7 +111,31 @@ in set options packet:
46 B9 6A 00 4B 04 00 00 5A A5 FF FF FF 00 FF FF
00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
00 00 FF A8 FF EE FF E0 FF FD 03 FF FF FF FF FF
^^
MCSP
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FD FF FF FF 75 BF F7 BC 9F 3A 80 16
^^
MCSY
password setting
the password is sent with packet type 0x07 and checked before erase with packet type 0x05. setting the password uses two fields.
index 22 of the option block encodes the password length in bytes (MCSP, see above). bit 3 in MCS3 decides whether the password
will be checked. if the bit is set, no password check occurs. if it is reset, a password check occurs.
quick dump from USB-ISP packets:
set: foobar
0000 ff ff ff 00 ff ff 00 05 ff ff ff ff ff ff ff 07 ................
0010 ff ff ff ff ff ff ff 07 ff 06 01 ff 6e ff 36 58 ............n.6X
0020 ff 00 ff f5 03 ff ff 0c ff ff ff ff ff ff ff 07 ................
0030 ff ff ff ff ff ff ff 07 ff ff ff ff ff ff ec 1a ................
0040 ff ff ff 99 7f f7 bc 38 9f 61 .......8.a
reset:
0000 ff ff ff 00 ff ff 00 05 ff ff ff ff ff ff ff 07 ................
0010 ff ff ff ff ff ff ff 07 ff 00 01 ff 6e ff 36 5e ............n.6^
0020 ff 00 ff fd 03 ff ff 04 ff ff ff ff ff ff ff 07 ................
0030 ff ff ff ff ff ff ff 07 ff ff ff ff ff ff ec 1a ................
0040 ff ff ff 99 7f f7 bc 38 9f 61 .......8.a

35
doc/usb15-protocol.txt Normal file
View File

@ -0,0 +1,35 @@
STC15 series USB ISP protocol
=============================
- host does OUT and IN control transfers for write and read
- IN transfer with wLength = 132, wValue = 0, wIndex = 0, bRequest = 0 are used for all reads
- OUT transfers with arbitrary size are used for writes
- packets from MCU
always start with 0x46 0xb9, similar to serial protocols
third byte is packet length
followed by data bytes
8 bit checksum at the end, looks like 8 bit modular subtraction
- packet types
most likely derived from the serial protocol, at least partially
info packet
- same as with serial protocol
option packet
- generally same as with serial protocol, some header stuff omitted
- flash data
wIndex specifies write address
wValue is 0xa55a
bRequest is 0x22 for first packet, 0x02 for the following ones
unusually encoded: a total of 128 bytes per packet, with every 7 byte checksummed in some way, for a total of 18x7 byte segments and a final 2 byte segment
checksum: 8 bit inverted modular sum
- option packet
wIndex is 0
wValue is 0xa55a
bRequest is 4
seems to use the same checksumming scheme

View File

@ -37,6 +37,8 @@ class StcGal:
self.protocol = Stc89Protocol(opts.port, opts.handshake, opts.baud)
elif opts.protocol == "stc12a":
self.protocol = Stc12AProtocol(opts.port, opts.handshake, opts.baud)
elif opts.protocol == "stc12b":
self.protocol = Stc12BProtocol(opts.port, opts.handshake, opts.baud)
elif opts.protocol == "stc12":
self.protocol = Stc12Protocol(opts.port, opts.handshake, opts.baud)
elif opts.protocol == "stc15a":
@ -109,9 +111,9 @@ class StcGal:
bindata = bindata[0:code_size]
bindata += eedata
# pad to 256 byte boundary
if len(bindata) % 256:
bindata += bytes(256 - len(bindata) % 256)
# pad to 512 byte boundary
if len(bindata) % 512:
bindata += b'\xff' * (512 - len(bindata) % 512)
if self.opts.option: self.emit_options(self.opts.option)
@ -194,7 +196,7 @@ def cli():
parser.add_argument("code_image", help="code segment file to flash (BIN/HEX)", type=argparse.FileType("rb"), nargs='?')
parser.add_argument("eeprom_image", help="eeprom segment file to flash (BIN/HEX)", type=argparse.FileType("rb"), nargs='?')
parser.add_argument("-a", "--autoreset", help="cycle power automatically by asserting DTR", action="store_true")
parser.add_argument("-P", "--protocol", help="protocol version", choices=["stc89", "stc12a", "stc12", "stc15a", "stc15", "usb15", "auto"], default="stc12")
parser.add_argument("-P", "--protocol", help="protocol version", choices=["stc89", "stc12a", "stc12b", "stc12", "stc15a", "stc15", "usb15", "auto"], 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)

View File

@ -839,28 +839,28 @@ class MCUModelDatabase:
MCUModel(name='STC12C5420', magic=0xe014, total=32768, code=20480, eeprom=12288),
MCUModel(name='STC12C5424', magic=0xe018, total=32768, code=24576, eeprom=12288),
MCUModel(name='STC12C5428', magic=0xe01c, total=32768, code=28672, eeprom=12288),
MCUModel(name='STC12LE5401AD', magic=0xe0e1, total=32768, code=1024, eeprom=22016),
MCUModel(name='STC12LE5402AD', magic=0xe0e2, total=32768, code=2048, eeprom=20992),
MCUModel(name='STC12LE5404AD', magic=0xe0e4, total=32768, code=4096, eeprom=18944),
MCUModel(name='STC12LE5406AD', magic=0xe0e6, total=32768, code=6144, eeprom=16896),
MCUModel(name='STC12LE5408AD', magic=0xe0e8, total=32768, code=8192, eeprom=10752),
MCUModel(name='STC12LE5410AD', magic=0xe0ea, total=32768, code=10240, eeprom=4608),
MCUModel(name='STC12LE5412AD', magic=0xe0ec, total=32768, code=12288, eeprom=11776),
MCUModel(name='STC12LE5401AD', magic=0xe0e1, total=32768, code=1024, eeprom=12288),
MCUModel(name='STC12LE5402AD', magic=0xe0e2, total=32768, code=2048, eeprom=12288),
MCUModel(name='STC12LE5404AD', magic=0xe0e4, total=32768, code=4096, eeprom=12288),
MCUModel(name='STC12LE5406AD', magic=0xe0e6, total=32768, code=6144, eeprom=12288),
MCUModel(name='STC12LE5408AD', magic=0xe0e8, total=32768, code=8192, eeprom=12288),
MCUModel(name='STC12LE5410AD', magic=0xe0ea, total=32768, code=10240, eeprom=12288),
MCUModel(name='STC12LE5412AD', magic=0xe0ec, total=32768, code=12288, eeprom=12288),
MCUModel(name='STC12LE5416AD', magic=0xe0f0, total=32768, code=16384, eeprom=12288),
MCUModel(name='STC12LE5420AD', magic=0xe0f4, total=32768, code=20480, eeprom=8192),
MCUModel(name='STC12LE5424AD', magic=0xe0f8, total=32768, code=24576, eeprom=4096),
MCUModel(name='STC12LE5428AD', magic=0xe0fc, total=32768, code=28672, eeprom=0),
MCUModel(name='STC12LE5401', magic=0xe081, total=32768, code=1024, eeprom=22016),
MCUModel(name='STC12LE5402', magic=0xe082, total=32768, code=2048, eeprom=20992),
MCUModel(name='STC12LE5404', magic=0xe084, total=32768, code=4096, eeprom=18944),
MCUModel(name='STC12LE5406', magic=0xe086, total=32768, code=6144, eeprom=16896),
MCUModel(name='STC12LE5408', magic=0xe088, total=32768, code=8192, eeprom=10752),
MCUModel(name='STC12LE5410', magic=0xe08a, total=32768, code=10240, eeprom=4608),
MCUModel(name='STC12LE5412', magic=0xe08c, total=32768, code=12288, eeprom=11776),
MCUModel(name='STC12LE5420AD', magic=0xe0f4, total=32768, code=20480, eeprom=12288),
MCUModel(name='STC12LE5424AD', magic=0xe0f8, total=32768, code=24576, eeprom=12288),
MCUModel(name='STC12LE5428AD', magic=0xe0fc, total=32768, code=28672, eeprom=12288),
MCUModel(name='STC12LE5401', magic=0xe081, total=32768, code=1024, eeprom=12288),
MCUModel(name='STC12LE5402', magic=0xe082, total=32768, code=2048, eeprom=12288),
MCUModel(name='STC12LE5404', magic=0xe084, total=32768, code=4096, eeprom=12288),
MCUModel(name='STC12LE5406', magic=0xe086, total=32768, code=6144, eeprom=12288),
MCUModel(name='STC12LE5408', magic=0xe088, total=32768, code=8192, eeprom=12288),
MCUModel(name='STC12LE5410', magic=0xe08a, total=32768, code=10240, eeprom=12288),
MCUModel(name='STC12LE5412', magic=0xe08c, total=32768, code=12288, eeprom=12288),
MCUModel(name='STC12LE5416', magic=0xe090, total=32768, code=16384, eeprom=12288),
MCUModel(name='STC12LE5420', magic=0xe094, total=32768, code=20480, eeprom=8192),
MCUModel(name='STC12LE5424', magic=0xe098, total=32768, code=24576, eeprom=4096),
MCUModel(name='STC12LE5428', magic=0xe09c, total=32768, code=28672, eeprom=0),
MCUModel(name='STC12LE5420', magic=0xe094, total=32768, code=20480, eeprom=12288),
MCUModel(name='STC12LE5424', magic=0xe098, total=32768, code=24576, eeprom=12288),
MCUModel(name='STC12LE5428', magic=0xe09c, total=32768, code=28672, eeprom=12288),
MCUModel(name='STC12C1052AD', magic=0xf211, total=8192, code=1024, eeprom=5120),
MCUModel(name='STC12C2052AD', magic=0xf212, total=8192, code=2048, eeprom=4096),
MCUModel(name='STC12C3052AD', magic=0xf213, total=8192, code=3072, eeprom=3072),

608
stcgal/options.py Normal file
View File

@ -0,0 +1,608 @@
#
# Copyright (c) 2013-2016 Grigori Goronzy <greg@chown.ath.cx>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
import struct
from stcgal.utils import Utils
class BaseOption:
def print(self):
print("Target options:")
for name, get_func, _ in self.options:
print(" %s=%s" % (name, get_func()))
def set_option(self, name, value):
for opt, _, set_func in self.options:
if opt == name:
print("Option %s=%s" % (name, value))
set_func(value)
return
raise ValueError("unknown")
def get_option(self, name):
for opt, get_func, _ in self.options:
if opt == name:
return get_func(name)
raise ValueError("unknown")
def get_msr(self):
return bytes(self.msr)
class Stc89Option(BaseOption):
"""Manipulation STC89 series option byte"""
def __init__(self, msr):
self.msr = msr
self.options = (
("cpu_6t_enabled", self.get_t6, self.set_t6),
("bsl_pindetect_enabled", self.get_pindetect, self.set_pindetect),
("eeprom_erase_enabled", self.get_ee_erase, self.set_ee_erase),
("clock_gain", self.get_clock_gain, self.set_clock_gain),
("ale_enabled", self.get_ale, self.set_ale),
("xram_enabled", self.get_xram, self.set_xram),
("watchdog_por_enabled", self.get_watchdog, self.set_watchdog),
)
def get_msr(self):
return self.msr
def get_t6(self):
return not bool(self.msr & 1)
def set_t6(self, val):
val = Utils.to_bool(val);
self.msr &= 0xfe
self.msr |= 0x01 if not bool(val) else 0x00
def get_pindetect(self):
return not bool(self.msr & 4)
def set_pindetect(self, val):
val = Utils.to_bool(val);
self.msr &= 0xfb
self.msr |= 0x04 if not bool(val) else 0x00
def get_ee_erase(self):
return not bool(self.msr & 8)
def set_ee_erase(self, val):
val = Utils.to_bool(val);
self.msr &= 0xf7
self.msr |= 0x08 if not bool(val) else 0x00
def get_clock_gain(self):
gain = bool(self.msr & 16)
return "high" if gain else "low"
def set_clock_gain(self, val):
gains = {"low": 0, "high": 0x10}
if val not in gains.keys():
raise ValueError("must be one of %s" % list(gains.keys()))
self.msr &= 0xef
self.msr |= gains[val]
def get_ale(self):
return bool(self.msr & 32)
def set_ale(self, val):
val = Utils.to_bool(val);
self.msr &= 0xdf
self.msr |= 0x20 if bool(val) else 0x00
def get_xram(self):
return bool(self.msr & 64)
def set_xram(self, val):
val = Utils.to_bool(val);
self.msr &= 0xbf
self.msr |= 0x40 if bool(val) else 0x00
def get_watchdog(self):
return not bool(self.msr & 128)
def set_watchdog(self, val):
val = Utils.to_bool(val);
self.msr &= 0x7f
self.msr |= 0x80 if not bool(val) else 0x00
class Stc12AOption(BaseOption):
"""Manipulate STC12A series option bytes"""
def __init__(self, msr):
assert len(msr) == 4
self.msr = bytearray(msr)
"""list of options and their handlers"""
self.options = (
("low_voltage_reset", self.get_low_voltage_detect, self.set_low_voltage_detect),
("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_low_voltage_detect(self):
lvd = bool(self.msr[3] & 64)
return "high" if not lvd else "low"
def set_low_voltage_detect(self, val):
lvds = {"low": 1, "high": 0}
if val not in lvds.keys():
raise ValueError("must be one of %s" % list(sources.keys()))
self.msr[3] &= 0xbf
self.msr[3] |= lvds[val] << 6
def get_clock_source(self):
source = bool(self.msr[0] & 2)
return "external" if source else "internal"
def set_clock_source(self, val):
sources = {"internal": 0, "external": 1}
if val not in sources.keys():
raise ValueError("must be one of %s" % list(sources.keys()))
self.msr[0] &= 0xfd
self.msr[0] |= sources[val] << 1
def get_watchdog(self):
return not bool(self.msr[1] & 32)
def set_watchdog(self, val):
val = Utils.to_bool(val);
self.msr[1] &= 0xdf
self.msr[1] |= 0x20 if not val else 0x00
def get_watchdog_idle(self):
return not bool(self.msr[1] & 8)
def set_watchdog_idle(self, val):
val = Utils.to_bool(val);
self.msr[1] &= 0xf7
self.msr[1] |= 0x08 if not val else 0x00
def get_watchdog_prescale(self):
return 2 ** (((self.msr[1]) & 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[1] &= 0xf8
self.msr[1] |= wd_vals[val]
def get_ee_erase(self):
return not bool(self.msr[2] & 2)
def set_ee_erase(self, val):
val = Utils.to_bool(val);
self.msr[2] &= 0xfd
self.msr[2] |= 0x02 if not val else 0x00
def get_pindetect(self):
return not bool(self.msr[2] & 1)
def set_pindetect(self, val):
val = Utils.to_bool(val);
self.msr[2] &= 0xfe
self.msr[2] |= 0x01 if not val else 0x00
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_reset", self.get_low_voltage_detect, self.set_low_voltage_detect),
("oscillator_stable_delay", self.get_osc_stable_delay, self.set_osc_stable_delay),
("por_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)
def set_reset_pin_enabled(self, val):
val = Utils.to_bool(val);
self.msr[0] &= 0xfe
self.msr[0] |= 0x01 if bool(val) else 0x00
def get_low_voltage_detect(self):
return not bool(self.msr[0] & 64)
def set_low_voltage_detect(self, val):
val = Utils.to_bool(val);
self.msr[0] &= 0xbf
self.msr[0] |= 0x40 if not val else 0x00
def get_osc_stable_delay(self):
return 2 ** (((self.msr[0] >> 4) & 0x03) + 12)
def set_osc_stable_delay(self, val):
val = Utils.to_int(val)
osc_vals = {4096: 0, 8192: 1, 16384: 2, 32768: 3}
if val not in osc_vals.keys():
raise ValueError("must be one of %s" % list(osc_vals.keys()))
self.msr[0] &= 0xcf
self.msr[0] |= osc_vals[val] << 4
def get_por_delay(self):
delay = not bool(self.msr[1] & 128)
return "long" if delay else "short"
def set_por_delay(self, val):
delays = {"short": 1, "long": 0}
if val not in delays.keys():
raise ValueError("must be one of %s" % list(delays.keys()))
self.msr[1] &= 0x7f
self.msr[1] |= delays[val] << 7
def get_clock_gain(self):
gain = bool(self.msr[1] & 64)
return "high" if gain else "low"
def set_clock_gain(self, val):
gains = {"low": 0, "high": 1}
if val not in gains.keys():
raise ValueError("must be one of %s" % list(gains.keys()))
self.msr[1] &= 0xbf
self.msr[1] |= gains[val] << 6
def get_clock_source(self):
source = bool(self.msr[1] & 2)
return "external" if source else "internal"
def set_clock_source(self, val):
sources = {"internal": 0, "external": 1}
if val not in sources.keys():
raise ValueError("must be one of %s" % list(sources.keys()))
self.msr[1] &= 0xfd
self.msr[1] |= sources[val] << 1
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_ee_erase(self):
return not bool(self.msr[3] & 2)
def set_ee_erase(self, val):
val = Utils.to_bool(val);
self.msr[3] &= 0xfd
self.msr[3] |= 0x02 if not val else 0x00
def get_pindetect(self):
return not bool(self.msr[3] & 1)
def set_pindetect(self, val):
val = Utils.to_bool(val);
self.msr[3] &= 0xfe
self.msr[3] |= 0x01 if not val else 0x00
class Stc15AOption(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 Stc15Option(BaseOption):
def __init__(self, msr):
assert len(msr) >= 4
self.msr = bytearray(msr)
self.options = (
("reset_pin_enabled", self.get_reset_pin_enabled, self.set_reset_pin_enabled),
("clock_source", self.get_clock_source, self.set_clock_source),
("clock_gain", self.get_clock_gain, self.set_clock_gain),
("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),
("por_reset_delay", self.get_por_delay, self.set_por_delay),
("rstout_por_state", self.get_p33_state, self.set_p33_state),
("uart2_passthrough", self.get_uart_passthrough, self.set_uart_passthrough),
("uart2_pin_mode", self.get_uart_pin_mode, self.set_uart_pin_mode),
)
if len(msr) > 4:
self.options += ("cpu_core_voltage", self.get_core_voltage, self.set_core_voltage),
def get_reset_pin_enabled(self):
return not bool(self.msr[2] & 16)
def set_reset_pin_enabled(self, val):
val = Utils.to_bool(val);
self.msr[2] &= 0xef
self.msr[2] |= 0x10 if not bool(val) else 0x00
def get_clock_source(self):
source = bool(self.msr[2] & 0x01)
return "internal" if source else "external"
def set_clock_source(self, val):
sources = {"internal": 1, "external": 0}
if val not in sources.keys():
raise ValueError("must be one of %s" % list(sources.keys()))
self.msr[2] &= 0xfe
self.msr[2] |= sources[val]
def get_clock_gain(self):
gain = bool(self.msr[2] & 0x02)
return "high" if gain else "low"
def set_clock_gain(self, val):
gains = {"low": 0, "high": 1}
if val not in gains.keys():
raise ValueError("must be one of %s" % list(gains.keys()))
self.msr[2] &= 0xfd
self.msr[2] |= gains[val] << 1
def get_watchdog(self):
return not bool(self.msr[0] & 32)
def set_watchdog(self, val):
val = Utils.to_bool(val);
self.msr[0] &= 0xdf
self.msr[0] |= 0x20 if not val else 0x00
def get_watchdog_idle(self):
return not bool(self.msr[0] & 8)
def set_watchdog_idle(self, val):
val = Utils.to_bool(val);
self.msr[0] &= 0xf7
self.msr[0] |= 0x08 if not val else 0x00
def get_watchdog_prescale(self):
return 2 ** (((self.msr[0]) & 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[0] &= 0xf8
self.msr[0] |= wd_vals[val]
def get_lvrs(self):
return not bool(self.msr[1] & 64)
def set_lvrs(self, val):
val = Utils.to_bool(val);
self.msr[1] &= 0xbf
self.msr[1] |= 0x40 if not 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 bool(self.msr[3] & 2)
def set_ee_erase(self, val):
val = Utils.to_bool(val);
self.msr[3] &= 0xfd
self.msr[3] |= 0x02 if val else 0x00
def get_pindetect(self):
return not bool(self.msr[3] & 1)
def set_pindetect(self, val):
val = Utils.to_bool(val);
self.msr[3] &= 0xfe
self.msr[3] |= 0x01 if not val else 0x00
def get_por_delay(self):
delay = bool(self.msr[2] & 128)
return "long" if delay else "short"
def set_por_delay(self, val):
delays = {"short": 0, "long": 1}
if val not in delays.keys():
raise ValueError("must be one of %s" % list(delays.keys()))
self.msr[2] &= 0x7f
self.msr[2] |= delays[val] << 7
def get_p33_state(self):
return "high" if self.msr[2] & 0x08 else "low"
def set_p33_state(self, val):
val = Utils.to_bool(val)
self.msr[2] &= 0xf7
self.msr[2] |= 0x08 if val else 0x00
def get_uart_passthrough(self):
return bool(self.msr[2] & 0x40)
def set_uart_passthrough(self, val):
val = Utils.to_bool(val)
self.msr[2] &= 0xbf
self.msr[2] |= 0x40 if val else 0x00
def get_uart_pin_mode(self):
return "push-pull" if bool(self.msr[2] & 0x20) else "normal"
def set_uart_pin_mode(self, val):
delays = {"normal": 0, "push-pull": 1}
if val not in delays.keys():
raise ValueError("must be one of %s" % list(delays.keys()))
self.msr[2] &= 0xdf
self.msr[2] |= 0x20 if val else 0x00
def get_core_voltage(self):
if self.msr[4] == 0xea: return "low"
elif self.msr[4] == 0xf7: return "mid"
elif self.msr[4] == 0xfd: return "high"
else: return "unknown"
def set_core_voltage(self, val):
volt_vals = {"low": 0xea, "mid": 0xf7, "high": 0xfd}
if val not in volt_vals.keys():
raise ValueError("must be one of %s" % list(volt_vals.keys()))
self.msr[4] = volt_vals[val]

View File

@ -26,6 +26,7 @@ import argparse
import collections
from stcgal.models import MCUModelDatabase
from stcgal.utils import Utils
from stcgal.options import *
import functools
try:
@ -45,588 +46,6 @@ class StcProtocolException(Exception):
pass
class BaseOption:
def print(self):
print("Target options:")
for name, get_func, _ in self.options:
print(" %s=%s" % (name, get_func()))
def set_option(self, name, value):
for opt, _, set_func in self.options:
if opt == name:
print("Option %s=%s" % (name, value))
set_func(value)
return
raise ValueError("unknown")
def get_option(self, name):
for opt, get_func, _ in self.options:
if opt == name:
return get_func(name)
raise ValueError("unknown")
def get_msr(self):
return bytes(self.msr)
class Stc89Option(BaseOption):
"""Manipulation STC89 series option byte"""
def __init__(self, msr):
self.msr = msr
self.options = (
("cpu_6t_enabled", self.get_t6, self.set_t6),
("bsl_pindetect_enabled", self.get_pindetect, self.set_pindetect),
("eeprom_erase_enabled", self.get_ee_erase, self.set_ee_erase),
("clock_gain", self.get_clock_gain, self.set_clock_gain),
("ale_enabled", self.get_ale, self.set_ale),
("xram_enabled", self.get_xram, self.set_xram),
("watchdog_por_enabled", self.get_watchdog, self.set_watchdog),
)
def get_msr(self):
return self.msr
def get_t6(self):
return not bool(self.msr & 1)
def set_t6(self, val):
val = Utils.to_bool(val);
self.msr &= 0xfe
self.msr |= 0x01 if not bool(val) else 0x00
def get_pindetect(self):
return not bool(self.msr & 4)
def set_pindetect(self, val):
val = Utils.to_bool(val);
self.msr &= 0xfb
self.msr |= 0x04 if not bool(val) else 0x00
def get_ee_erase(self):
return not bool(self.msr & 8)
def set_ee_erase(self, val):
val = Utils.to_bool(val);
self.msr &= 0xf7
self.msr |= 0x08 if not bool(val) else 0x00
def get_clock_gain(self):
gain = bool(self.msr & 16)
return "high" if gain else "low"
def set_clock_gain(self, val):
gains = {"low": 0, "high": 0x10}
if val not in gains.keys():
raise ValueError("must be one of %s" % list(gains.keys()))
self.msr &= 0xef
self.msr |= gains[val]
def get_ale(self):
return bool(self.msr & 32)
def set_ale(self, val):
val = Utils.to_bool(val);
self.msr &= 0xdf
self.msr |= 0x20 if bool(val) else 0x00
def get_xram(self):
return bool(self.msr & 64)
def set_xram(self, val):
val = Utils.to_bool(val);
self.msr &= 0xbf
self.msr |= 0x40 if bool(val) else 0x00
def get_watchdog(self):
return not bool(self.msr & 128)
def set_watchdog(self, val):
val = Utils.to_bool(val);
self.msr &= 0x7f
self.msr |= 0x80 if not bool(val) else 0x00
class Stc12AOption(BaseOption):
"""Manipulate STC12A series option bytes"""
def __init__(self, msr):
assert len(msr) == 5
self.msr = bytearray(msr)
"""list of options and their handlers"""
self.options = (
("low_voltage_reset", self.get_low_voltage_detect, self.set_low_voltage_detect),
("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_low_voltage_detect(self):
return not bool(self.msr[4] & 64)
def set_low_voltage_detect(self, val):
val = Utils.to_bool(val);
self.msr[4] &= 0xbf
self.msr[4] |= 0x40 if not val else 0x00
def get_clock_source(self):
source = bool(self.msr[0] & 2)
return "external" if source else "internal"
def set_clock_source(self, val):
sources = {"internal": 0, "external": 1}
if val not in sources.keys():
raise ValueError("must be one of %s" % list(sources.keys()))
self.msr[0] &= 0xfd
self.msr[0] |= sources[val] << 1
def get_watchdog(self):
return not bool(self.msr[1] & 32)
def set_watchdog(self, val):
val = Utils.to_bool(val);
self.msr[1] &= 0xdf
self.msr[1] |= 0x20 if not val else 0x00
def get_watchdog_idle(self):
return not bool(self.msr[1] & 8)
def set_watchdog_idle(self, val):
val = Utils.to_bool(val);
self.msr[1] &= 0xf7
self.msr[1] |= 0x08 if not val else 0x00
def get_watchdog_prescale(self):
return 2 ** (((self.msr[1]) & 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[1] &= 0xf8
self.msr[1] |= wd_vals[val]
def get_ee_erase(self):
return not bool(self.msr[2] & 2)
def set_ee_erase(self, val):
val = Utils.to_bool(val);
self.msr[2] &= 0xfd
self.msr[2] |= 0x02 if not val else 0x00
def get_pindetect(self):
return not bool(self.msr[2] & 1)
def set_pindetect(self, val):
val = Utils.to_bool(val);
self.msr[2] &= 0xfe
self.msr[2] |= 0x01 if not val else 0x00
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_reset", self.get_low_voltage_detect, self.set_low_voltage_detect),
("oscillator_stable_delay", self.get_osc_stable_delay, self.set_osc_stable_delay),
("por_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)
def set_reset_pin_enabled(self, val):
val = Utils.to_bool(val);
self.msr[0] &= 0xfe
self.msr[0] |= 0x01 if bool(val) else 0x00
def get_low_voltage_detect(self):
return not bool(self.msr[0] & 64)
def set_low_voltage_detect(self, val):
val = Utils.to_bool(val);
self.msr[0] &= 0xbf
self.msr[0] |= 0x40 if not val else 0x00
def get_osc_stable_delay(self):
return 2 ** (((self.msr[0] >> 4) & 0x03) + 12)
def set_osc_stable_delay(self, val):
val = Utils.to_int(val)
osc_vals = {4096: 0, 8192: 1, 16384: 2, 32768: 3}
if val not in osc_vals.keys():
raise ValueError("must be one of %s" % list(osc_vals.keys()))
self.msr[0] &= 0xcf
self.msr[0] |= osc_vals[val] << 4
def get_por_delay(self):
delay = not bool(self.msr[1] & 128)
return "long" if delay else "short"
def set_por_delay(self, val):
delays = {"short": 1, "long": 0}
if val not in delays.keys():
raise ValueError("must be one of %s" % list(delays.keys()))
self.msr[1] &= 0x7f
self.msr[1] |= delays[val] << 7
def get_clock_gain(self):
gain = bool(self.msr[1] & 64)
return "high" if gain else "low"
def set_clock_gain(self, val):
gains = {"low": 0, "high": 1}
if val not in gains.keys():
raise ValueError("must be one of %s" % list(gains.keys()))
self.msr[1] &= 0xbf
self.msr[1] |= gains[val] << 6
def get_clock_source(self):
source = bool(self.msr[1] & 2)
return "external" if source else "internal"
def set_clock_source(self, val):
sources = {"internal": 0, "external": 1}
if val not in sources.keys():
raise ValueError("must be one of %s" % list(sources.keys()))
self.msr[1] &= 0xfd
self.msr[1] |= sources[val] << 1
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_ee_erase(self):
return not bool(self.msr[3] & 2)
def set_ee_erase(self, val):
val = Utils.to_bool(val);
self.msr[3] &= 0xfd
self.msr[3] |= 0x02 if not val else 0x00
def get_pindetect(self):
return not bool(self.msr[3] & 1)
def set_pindetect(self, val):
val = Utils.to_bool(val);
self.msr[3] &= 0xfe
self.msr[3] |= 0x01 if not val else 0x00
class Stc15AOption(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 Stc15Option(BaseOption):
def __init__(self, msr):
assert len(msr) >= 4
self.msr = bytearray(msr)
self.options = (
("reset_pin_enabled", self.get_reset_pin_enabled, self.set_reset_pin_enabled),
("clock_source", self.get_clock_source, self.set_clock_source),
("clock_gain", self.get_clock_gain, self.set_clock_gain),
("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),
("por_reset_delay", self.get_por_delay, self.set_por_delay),
("rstout_por_state", self.get_p33_state, self.set_p33_state),
("uart2_passthrough", self.get_uart_passthrough, self.set_uart_passthrough),
("uart2_pin_mode", self.get_uart_pin_mode, self.set_uart_pin_mode),
)
if len(msr) > 4:
self.options += ("cpu_core_voltage", self.get_core_voltage, self.set_core_voltage),
def get_reset_pin_enabled(self):
return not bool(self.msr[2] & 16)
def set_reset_pin_enabled(self, val):
val = Utils.to_bool(val);
self.msr[2] &= 0xef
self.msr[2] |= 0x10 if not bool(val) else 0x00
def get_clock_source(self):
source = bool(self.msr[2] & 0x01)
return "internal" if source else "external"
def set_clock_source(self, val):
sources = {"internal": 1, "external": 0}
if val not in sources.keys():
raise ValueError("must be one of %s" % list(sources.keys()))
self.msr[2] &= 0xfe
self.msr[2] |= sources[val]
def get_clock_gain(self):
gain = bool(self.msr[2] & 0x02)
return "high" if gain else "low"
def set_clock_gain(self, val):
gains = {"low": 0, "high": 1}
if val not in gains.keys():
raise ValueError("must be one of %s" % list(gains.keys()))
self.msr[2] &= 0xfd
self.msr[2] |= gains[val] << 1
def get_watchdog(self):
return not bool(self.msr[0] & 32)
def set_watchdog(self, val):
val = Utils.to_bool(val);
self.msr[0] &= 0xdf
self.msr[0] |= 0x20 if not val else 0x00
def get_watchdog_idle(self):
return not bool(self.msr[0] & 8)
def set_watchdog_idle(self, val):
val = Utils.to_bool(val);
self.msr[0] &= 0xf7
self.msr[0] |= 0x08 if not val else 0x00
def get_watchdog_prescale(self):
return 2 ** (((self.msr[0]) & 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[0] &= 0xf8
self.msr[0] |= wd_vals[val]
def get_lvrs(self):
return not bool(self.msr[1] & 64)
def set_lvrs(self, val):
val = Utils.to_bool(val);
self.msr[1] &= 0xbf
self.msr[1] |= 0x40 if not 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 bool(self.msr[3] & 2)
def set_ee_erase(self, val):
val = Utils.to_bool(val);
self.msr[3] &= 0xfd
self.msr[3] |= 0x02 if val else 0x00
def get_pindetect(self):
return not bool(self.msr[3] & 1)
def set_pindetect(self, val):
val = Utils.to_bool(val);
self.msr[3] &= 0xfe
self.msr[3] |= 0x01 if not val else 0x00
def get_por_delay(self):
delay = bool(self.msr[2] & 128)
return "long" if delay else "short"
def set_por_delay(self, val):
delays = {"short": 0, "long": 1}
if val not in delays.keys():
raise ValueError("must be one of %s" % list(delays.keys()))
self.msr[2] &= 0x7f
self.msr[2] |= delays[val] << 7
def get_p33_state(self):
return "high" if self.msr[2] & 0x08 else "low"
def set_p33_state(self, val):
val = Utils.to_bool(val)
self.msr[2] &= 0xf7
self.msr[2] |= 0x08 if val else 0x00
def get_uart_passthrough(self):
return bool(self.msr[2] & 0x40)
def set_uart_passthrough(self, val):
val = Utils.to_bool(val)
self.msr[2] &= 0xbf
self.msr[2] |= 0x40 if val else 0x00
def get_uart_pin_mode(self):
return "push-pull" if bool(self.msr[2] & 0x20) else "normal"
def set_uart_pin_mode(self, val):
delays = {"normal": 0, "push-pull": 1}
if val not in delays.keys():
raise ValueError("must be one of %s" % list(delays.keys()))
self.msr[2] &= 0xdf
self.msr[2] |= 0x20 if val else 0x00
def get_core_voltage(self):
if self.msr[4] == 0xea: return "low"
elif self.msr[4] == 0xf7: return "mid"
elif self.msr[4] == 0xfd: return "high"
else: return "unknown"
def set_core_voltage(self, val):
volt_vals = {"low": 0xea, "mid": 0xf7, "high": 0xfd}
if val not in volt_vals.keys():
raise ValueError("must be one of %s" % list(volt_vals.keys()))
self.msr[4] = volt_vals[val]
class StcBaseProtocol:
"""Basic functionality for STC BSL protocols"""
@ -775,6 +194,7 @@ class StcBaseProtocol:
protocol_database = [("stc89", "STC(89|90)(C|LE)\d"),
("stc12a", "STC12(C|LE)\d052"),
("stc12b", "STC12(C|LE)(52|56)"),
("stc12", "(STC|IAP)(10|11|12)\D"),
("stc15a", "(STC|IAP)15[FL][01]0\d(E|EA|)$"),
("stc15", "(STC|IAP|IRC)15\D")]
@ -1012,6 +432,7 @@ class Stc89Protocol(StcBaseProtocol):
# check new baudrate
print("Switching to %d baud: " % self.baud_transfer, end="")
sys.stdout.flush()
brt, brt_csum, iap, delay = self.calculate_baud()
print("checking ", end="")
sys.stdout.flush()
@ -1109,7 +530,37 @@ class Stc89Protocol(StcBaseProtocol):
print("done")
class Stc12AProtocol(Stc89Protocol):
class Stc12AOptionsMixIn:
def program_options(self):
print("Setting options: ", end="")
sys.stdout.flush()
msr = self.options.get_msr()
packet = bytes([0x8d, msr[0], msr[1], msr[2], 0xff, msr[3]])
packet += struct.pack(">I", int(self.mcu_clock_hz))
packet += bytes([msr[3]])
packet += bytes([0xff, msr[0], msr[1], 0xff, 0xff, 0xff, 0xff, msr[2]])
packet += bytes([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
packet += struct.pack(">I", int(self.mcu_clock_hz))
packet += bytes([0xff, 0xff, 0xff])
self.write_packet(packet)
response = self.read_packet()
if response[0] != 0x80:
raise StcProtocolException("incorrect magic in option packet")
# XXX: this is done by STC-ISP on newer parts. not sure why, but let's
# just replicate it, just to be sure.
if self.bsl_version >= 0x66:
packet = bytes([0x50])
self.write_packet(packet)
response = self.read_packet()
if response[0] != 0x10:
raise StcProtocolException("incorrect magic in option packet")
print("done")
class Stc12AProtocol(Stc12AOptionsMixIn, Stc89Protocol):
"""countdown value for flash erase"""
ERASE_COUNTDOWN = 0x0d
@ -1130,6 +581,8 @@ class Stc12AProtocol(Stc89Protocol):
self.mcu_bsl_version = "%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
chr(bl_stepping))
self.bsl_version = bl_version
def calculate_baud(self):
"""Calculate MCU baudrate setting.
@ -1160,7 +613,7 @@ class Stc12AProtocol(Stc89Protocol):
"""Initialize options"""
# create option state
self.options = Stc12AOption(status_packet[23:28])
self.options = Stc12AOption(status_packet[23:26] + status_packet[29:30])
self.options.print()
def handshake(self):
@ -1228,23 +681,34 @@ class Stc12AProtocol(Stc89Protocol):
raise StcProtocolException("incorrect magic in erase packet")
print("done")
class Stc12OptionsMixIn:
def program_options(self):
print("Setting options: ", end="")
sys.stdout.flush()
msr = self.options.get_msr()
# XXX: it's not 100% clear if the index of msr[3] is consistent
# between devices, so write it to both indices.
packet = bytes([0x8d, msr[0], msr[1], msr[2], msr[3],
msr[4]])
0xff, 0xff, 0xff, 0xff, msr[3], 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
packet += struct.pack(">I", int(self.mcu_clock_hz))
self.write_packet(packet)
response = self.read_packet()
if response[0] != 0x80:
if response[0] != 0x50:
raise StcProtocolException("incorrect magic in option packet")
print("done")
# If UID wasn't sent with erase acknowledge, it should be in this packet
if not self.uid:
self.uid = response[18:25]
class Stc12Protocol(StcBaseProtocol):
"""Protocol handler for STC 10/11/12 series"""
print("Target UID: %s" % Utils.hexstr(self.uid))
class Stc12BaseProtocol(StcBaseProtocol):
"""Base class for STC 10/11/12 series protocol handlers"""
"""block size for programming flash"""
PROGRAM_BLOCKSIZE = 128
@ -1306,6 +770,8 @@ class Stc12Protocol(StcBaseProtocol):
self.mcu_bsl_version = "%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
chr(bl_stepping))
self.bsl_version = bl_version
def calculate_baud(self):
"""Calculate MCU baudrate setting.
@ -1336,7 +802,7 @@ class Stc12Protocol(StcBaseProtocol):
"""Initialize options"""
# create option state
self.options = Stc12Option(status_packet[23:27])
self.options = Stc12Option(status_packet[23:26] + status_packet[27:28])
self.options.print()
def handshake(self):
@ -1441,26 +907,19 @@ class Stc12Protocol(StcBaseProtocol):
raise StcProtocolException("incorrect magic in finish packet")
print("done")
def program_options(self):
print("Setting options: ", end="")
sys.stdout.flush()
msr = self.options.get_msr()
packet = bytes([0x8d, msr[0], msr[1], msr[2], msr[3],
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
packet += struct.pack(">I", int(self.mcu_clock_hz))
self.write_packet(packet)
response = self.read_packet()
if response[0] != 0x50:
raise StcProtocolException("incorrect magic in option packet")
print("done")
class Stc12Protocol(Stc12OptionsMixIn, Stc12BaseProtocol):
"""STC 10/11/12 series protocol handler"""
# If UID wasn't sent with erase acknowledge, it should be in this packet
if not self.uid:
self.uid = response[18:25]
def __init__(self, port, handshake, baud):
Stc12BaseProtocol.__init__(self, port, handshake, baud)
print("Target UID: %s" % Utils.hexstr(self.uid))
class Stc12BProtocol(Stc12AOptionsMixIn, Stc12BaseProtocol):
"""STC 10/11/12 variant protocol handler"""
def __init__(self, port, handshake, baud):
Stc12BaseProtocol.__init__(self, port, handshake, baud)
class Stc15AProtocol(Stc12Protocol):
@ -1997,12 +1456,6 @@ class StcUsb15Protocol(Stc15Protocol):
"""PID of STC devices"""
USB_PID = 0x4312
"""Control transfer from host to device"""
USB_HOST2DEV = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_RECIPIENT_DEVICE | usb.util.CTRL_OUT
"""Control transfer from device to host"""
USB_DEV2HOST = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_RECIPIENT_DEVICE | usb.util.CTRL_IN
def __init__(self):
# XXX: this is really ugly!
Stc15Protocol.__init__(self, "", 0, 0, 0)
@ -2016,7 +1469,8 @@ class StcUsb15Protocol(Stc15Protocol):
def read_packet(self):
"""Read a packet from the MCU"""
packet = self.dev.ctrl_transfer(self.USB_DEV2HOST, 0, 0, 0, 132).tobytes()
dev2host = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_RECIPIENT_DEVICE | usb.util.CTRL_IN
packet = self.dev.ctrl_transfer(dev2host, 0, 0, 0, 132).tobytes()
if len(packet) < 5 or packet[0] != 0x46 or packet[1] != 0xb9:
self.dump_packet(packet)
raise StcFramingException("incorrect frame start")
@ -2049,7 +1503,8 @@ class StcUsb15Protocol(Stc15Protocol):
i += 7
self.dump_packet(chunks, request, value, index, receive=False)
self.dev.ctrl_transfer(self.USB_HOST2DEV, request, value, index, chunks);
host2dev = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_RECIPIENT_DEVICE | usb.util.CTRL_OUT
self.dev.ctrl_transfer(host2dev, request, value, index, chunks);
def connect(self, autoreset=False):
"""Connect to USB device and read info packet"""
@ -2069,9 +1524,11 @@ class StcUsb15Protocol(Stc15Protocol):
if self.dev:
self.dev.set_configuration()
self.status_packet = self.read_packet()
else:
time.sleep(0.5)
except (StcFramingException, usb.core.USBError): pass
if len(self.status_packet) < 38:
self.status_packet = None
raise StcFramingException
else: raise StcFramingException
except (StcFramingException, usb.core.USBError): time.sleep(0.5)
self.initialize_model()
print("done")