Add preliminary STC8 support
What works: * Frequency calibration of internal RC oscillator * Flash/EEPROM programming What doesn't work yet: * Everything else
This commit is contained in:
parent
b47092093e
commit
8bc9d89257
133
doc/stc8-protocol.txt
Normal file
133
doc/stc8-protocol.txt
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
Overview of changes
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The following changes have been observed compared to STC15:
|
||||||
|
|
||||||
|
- Many differences in the status packet
|
||||||
|
- At least some differences in MCS
|
||||||
|
- Different challenge
|
||||||
|
- no separate program speed
|
||||||
|
- clock division was introduced; calibration always in the ~20-30 MHz range, lower clocks
|
||||||
|
use division
|
||||||
|
- the meaning of the calibration ranges and trim has changed
|
||||||
|
|
||||||
|
The good:
|
||||||
|
|
||||||
|
- Erase, Program, etc. operations are apparently unchanged. :)
|
||||||
|
|
||||||
|
|
||||||
|
Status packet
|
||||||
|
-------------
|
||||||
|
|
||||||
|
46 B9 68 00 30 50 00 54 62 58 5D 00 04 FF FD 8B BF FF 27 4A F7 FE 73 55 00 F6 28 09 85 E3 5F 80 07 20 20 20 01 00 00 FE 05 3A 17 05 25 91 FF 10 AE 16
|
||||||
|
^^^^^ wakeup clock
|
||||||
|
|
||||||
|
Clock set to 20 MHz by STC-ISP (encoding is different compared to STC15):
|
||||||
|
|
||||||
|
46 B9 68 00 30 50 01 31 2E 90 38 01 01 FF FD 8B BF FF 27 35 F7 FE 73 55 00 F6 28 09 85 E3 5F 80 07 20 20 20 01 00 00 FE 05 3A 17 05 25 91 FF 10 54 16
|
||||||
|
46 B9 68 00 30 50 01 31 2E 90 38 01 01 FF FD 8B BF FF 27 3B F7 FE 73 55 00 F6 28 09 85 E3 5F 80 07 20 20 20 01 00 00 FE 05 3A 17 05 25 91 FF 10 5A 16
|
||||||
|
^^^^^ some 24 MHz reference or other clk measurement?
|
||||||
|
^^^^^ trim/adjust?
|
||||||
|
^^ clkdiv
|
||||||
|
^^^^^^^^^^^ clk
|
||||||
|
|
||||||
|
|
||||||
|
Disconnect
|
||||||
|
----------
|
||||||
|
|
||||||
|
Uses FF command byte.
|
||||||
|
|
||||||
|
|
||||||
|
Basic challenge operation
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Host sends a challenge of some kind, followed by 0xfe pulsing
|
||||||
|
|
||||||
|
46 B9 6A 00 0C 00 02 00 00 80 00 00 F8 16
|
||||||
|
|
||||||
|
Much simpler than in STC15
|
||||||
|
|
||||||
|
MCU sends back some response:
|
||||||
|
|
||||||
|
46 B9 68 00 0C 00 02 36 AD 4E 83 02 2A 16
|
||||||
|
|
||||||
|
Host now sends some longer challenge, followed by more pulses:
|
||||||
|
|
||||||
|
46 B9 6A 00 20 00 0C 7C 00 7C 01 7C 02 7C 03 7D 00 7D 01 7D 02 7D 03 7E 00 7E 01 7E 02 7E 03 06 84 16
|
||||||
|
|
||||||
|
MCU sends back some response:
|
||||||
|
|
||||||
|
46 B9 68 00 20 00 0C 4D C6 4D DB 4D E7 4D F3 4D F6 4E 0E 4E 11 4E 26 4E 26 4E 32 4E 41 4E 56 09 DC 16
|
||||||
|
|
||||||
|
Host now seems to initiate a baud switch or something like that
|
||||||
|
|
||||||
|
46 B9 6A 00 0E 01 00 00 FF CC 01 7C 80 03 41 16
|
||||||
|
|
||||||
|
MCU acknowlegdes it:
|
||||||
|
|
||||||
|
46 B9 68 00 07 01 00 70 16
|
||||||
|
|
||||||
|
Now the MCU switches to the new baud rate.
|
||||||
|
|
||||||
|
|
||||||
|
Challenges observed
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
6 MHz:
|
||||||
|
|
||||||
|
46B96A0020000C 1400 1401 1402 1403 1500 1501 1502 1503 1600 1601 1602 1603 01A416
|
||||||
|
|
||||||
|
5.5 MHz:
|
||||||
|
|
||||||
|
46B96A0020000C 5C00 5C01 5C02 5C03 5D00 5D01 5D02 5D03 5E00 5E01 5E02 5E03 050416
|
||||||
|
|
||||||
|
|
||||||
|
11 MHz:
|
||||||
|
|
||||||
|
46B96A0020000C 5B00 5B01 5B02 5B03 5C00 5C01 5C02 5C03 5D00 5D01 5D02 5D03 04F816
|
||||||
|
|
||||||
|
20 MHz:
|
||||||
|
|
||||||
|
46B96A0020000C 3600 3601 3602 3603 3700 3701 3702 3703 3800 3801 3802 3803 033C16
|
||||||
|
|
||||||
|
24 MHz:
|
||||||
|
|
||||||
|
46B96A0020000C 7C00 7C01 7C02 7C03 7D00 7D01 7D02 7D03 7E00 7E01 7E02 7E03 068416
|
||||||
|
|
||||||
|
27 MHz:
|
||||||
|
|
||||||
|
46B96A0020000C B000 B001 B002 B003 B100 B101 B102 B103 B200 B201 B202 B203 08F416
|
||||||
|
|
||||||
|
|
||||||
|
Ranges vs trim value
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
46 B9 6A 00 20 00 0C 00 00 80 00 FF 00 00 01 80 01 FF 01 00 02 80 02 FF 02 00 03 80 03 FF 03 06 A4 16
|
||||||
|
46 B9 68 00 20 00 0C 36 9B 4E 92 65 E4 36 CB 4E 7D 66 29 36 D1 4E 83 66 05 36 CB 4E C2 66 47 0A EA 16
|
||||||
|
|
||||||
|
first byte determines general trim value... range of ~16 to ~30 MHz, the second byte (00..03) is a fine adjustment.
|
||||||
|
|
||||||
|
|
||||||
|
Clock division?
|
||||||
|
---------------
|
||||||
|
|
||||||
|
5.5 MHz vs 11 Mhz: challenge is about the same. it's likely some kind of clock divider is used!
|
||||||
|
|
||||||
|
5.5 Mhz switch: 01 00 00 FF CC 01 5C 80 clkdiv = 4?
|
||||||
|
11 MHz switch: 01 00 00 FF CC 01 5B 80 clkdiv = 2?
|
||||||
|
22 MHz switch: 01 00 00 FF CC 01 5C 80 clkdiv = 1?
|
||||||
|
|
||||||
|
22 Mhz option packet: 0400005AA5FFFFFF00FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF01516D405D0201FFFDFFFFFF8BBFF7FE
|
||||||
|
11 MHz option packet: 0400005AA5FFFFFF00FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF00A8AF985D0102FFFDFFFFFF8BBFF7FE
|
||||||
|
5.5 MHz option packet: 0400005AA5FFFFFF00FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF005462585D0004FFFDFFFFFF8BBFF7FE
|
||||||
|
^^ clkdiv?
|
||||||
|
^^^^^^^^ clkspeed
|
||||||
|
|
||||||
|
Always 24 MHz for programming
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Calibration for anything but 24 Mhz (and around that) fails when switching baud. Another observation is that there is no
|
||||||
|
programming speed being calibrated anymore. This may suggest that a fixed speed is used for programming.
|
||||||
|
|
||||||
|
Adjusting BRT calculation to 24 MHz in the switch packet seems to work. So it is really using 24 MHz by default;
|
||||||
|
probably some pre-calibrated value.
|
@ -32,6 +32,7 @@ from stcgal.protocols import Stc12Protocol
|
|||||||
from stcgal.protocols import Stc15Protocol
|
from stcgal.protocols import Stc15Protocol
|
||||||
from stcgal.protocols import Stc15AProtocol
|
from stcgal.protocols import Stc15AProtocol
|
||||||
from stcgal.protocols import StcUsb15Protocol
|
from stcgal.protocols import StcUsb15Protocol
|
||||||
|
from stcgal.protocols import Stc8Protocol
|
||||||
from stcgal.protocols import StcAutoProtocol
|
from stcgal.protocols import StcAutoProtocol
|
||||||
from stcgal.protocols import StcProtocolException
|
from stcgal.protocols import StcProtocolException
|
||||||
from stcgal.protocols import StcFramingException
|
from stcgal.protocols import StcFramingException
|
||||||
@ -60,6 +61,9 @@ class StcGal:
|
|||||||
elif opts.protocol == "stc15":
|
elif opts.protocol == "stc15":
|
||||||
self.protocol = Stc15Protocol(opts.port, opts.handshake, opts.baud,
|
self.protocol = Stc15Protocol(opts.port, opts.handshake, opts.baud,
|
||||||
round(opts.trim * 1000))
|
round(opts.trim * 1000))
|
||||||
|
elif opts.protocol == "stc8":
|
||||||
|
self.protocol = Stc8Protocol(opts.port, opts.handshake, opts.baud,
|
||||||
|
round(opts.trim * 1000))
|
||||||
elif opts.protocol == "usb15":
|
elif opts.protocol == "usb15":
|
||||||
self.protocol = StcUsb15Protocol()
|
self.protocol = StcUsb15Protocol()
|
||||||
else:
|
else:
|
||||||
@ -216,7 +220,7 @@ def cli():
|
|||||||
parser.add_argument("-a", "--autoreset", help="cycle power automatically by asserting DTR", action="store_true")
|
parser.add_argument("-a", "--autoreset", help="cycle power automatically by asserting DTR", action="store_true")
|
||||||
parser.add_argument("-r", "--resetcmd", help="Use this shell command for board power-cycling (instead of DTR assertion)", action="store")
|
parser.add_argument("-r", "--resetcmd", help="Use this shell command for board power-cycling (instead of DTR assertion)", action="store")
|
||||||
parser.add_argument("-P", "--protocol", help="protocol version (default: auto)",
|
parser.add_argument("-P", "--protocol", help="protocol version (default: auto)",
|
||||||
choices=["stc89", "stc12a", "stc12b", "stc12", "stc15a", "stc15", "usb15", "auto"], default="auto")
|
choices=["stc89", "stc12a", "stc12b", "stc12", "stc15a", "stc15", "stc8", "usb15", "auto"], default="auto")
|
||||||
parser.add_argument("-p", "--port", help="serial port device", default="/dev/ttyUSB0")
|
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("-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("-l", "--handshake", help="handshake baud rate (default: 2400)", type=BaudType(), default=2400)
|
||||||
|
@ -372,7 +372,8 @@ class StcAutoProtocol(StcBaseProtocol):
|
|||||||
("stc12b", r"STC12(C|LE)(52|56)"),
|
("stc12b", r"STC12(C|LE)(52|56)"),
|
||||||
("stc12", r"(STC|IAP)(10|11|12)\D"),
|
("stc12", r"(STC|IAP)(10|11|12)\D"),
|
||||||
("stc15a", r"(STC|IAP)15[FL][012]0\d(E|EA|)$"),
|
("stc15a", r"(STC|IAP)15[FL][012]0\d(E|EA|)$"),
|
||||||
("stc15", r"(STC|IAP|IRC)15\D")]
|
("stc15", r"(STC|IAP|IRC)15\D"),
|
||||||
|
("stc8", r"(STC|IAP|IRC)8")]
|
||||||
|
|
||||||
for protocol_name, pattern in protocol_database:
|
for protocol_name, pattern in protocol_database:
|
||||||
if re.match(pattern, self.model.name):
|
if re.match(pattern, self.model.name):
|
||||||
@ -1546,6 +1547,123 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
print("Target UID: %s" % Utils.hexstr(self.uid))
|
print("Target UID: %s" % Utils.hexstr(self.uid))
|
||||||
|
|
||||||
|
|
||||||
|
class Stc8Protocol(Stc15Protocol):
|
||||||
|
"""Protocol handler for STC8 series"""
|
||||||
|
|
||||||
|
def __init__(self, port, handshake, baud, trim):
|
||||||
|
Stc15Protocol.__init__(self, port, handshake, baud, trim)
|
||||||
|
|
||||||
|
def program_options(self):
|
||||||
|
# XXX: not yet implemented
|
||||||
|
pass
|
||||||
|
|
||||||
|
def initialize_status(self, packet):
|
||||||
|
"""Decode status packet and store basic MCU info"""
|
||||||
|
|
||||||
|
self.mcu_clock_hz, = struct.unpack(">I", packet[1:5])
|
||||||
|
# XXX: external clock not supported nor tested
|
||||||
|
self.external_clock = False
|
||||||
|
# all ones means no calibration
|
||||||
|
# new chips are shipped without any calibration
|
||||||
|
# XXX: somehow check if that still holds
|
||||||
|
if self.mcu_clock_hz == 0xffffffff: self.mcu_clock_hz = 0
|
||||||
|
|
||||||
|
# pre-calibrated trim adjust for 24 MHz, range 0x40
|
||||||
|
self.freq_count_24 = packet[4]
|
||||||
|
|
||||||
|
# wakeup timer factory value
|
||||||
|
self.wakeup_freq, = struct.unpack(">H", packet[23:25])
|
||||||
|
|
||||||
|
bl_version, bl_stepping = struct.unpack("BB", packet[17:19])
|
||||||
|
bl_minor = packet[22] & 0x0f
|
||||||
|
self.mcu_bsl_version = "%d.%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
||||||
|
bl_minor, chr(bl_stepping))
|
||||||
|
self.bsl_version = bl_version
|
||||||
|
|
||||||
|
def calibrate(self):
|
||||||
|
"""Calibrate selected user frequency frequency and switch to selected baudrate."""
|
||||||
|
|
||||||
|
# handle uncalibrated chips
|
||||||
|
if self.mcu_clock_hz == 0 and self.trim_frequency <= 0:
|
||||||
|
raise StcProtocolException("uncalibrated, please provide a trim value")
|
||||||
|
|
||||||
|
# determine target counter
|
||||||
|
user_speed = self.trim_frequency
|
||||||
|
if user_speed <= 0: user_speed = self.mcu_clock_hz
|
||||||
|
target_user_count = round(user_speed / (self.baud_handshake/2))
|
||||||
|
|
||||||
|
# calibration, round 1
|
||||||
|
# XXX: challenges need work. the ranges and how they related to clock frequency
|
||||||
|
# is different. A clock divider is used for lower frequencies.
|
||||||
|
print("Trimming frequency: ", end="")
|
||||||
|
sys.stdout.flush()
|
||||||
|
packet = bytes([0x00])
|
||||||
|
packet += struct.pack(">B", 12)
|
||||||
|
packet += bytes([11, 0x00, 11*2, 0x00, 11*3, 0x00])
|
||||||
|
packet += bytes([11*4, 0x00, 11*5, 0x00, 11*6, 0x00])
|
||||||
|
packet += bytes([11*7, 0x00, 11*8, 0x00, 11*9, 0x00])
|
||||||
|
packet += bytes([11*10, 0x00, 11*11, 0x00, 0x80, 0x00])
|
||||||
|
self.write_packet(packet)
|
||||||
|
self.pulse(b"\xfe", timeout=1.0)
|
||||||
|
response = self.read_packet()
|
||||||
|
if len(response) < 2 or response[0] != 0x00:
|
||||||
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
|
|
||||||
|
# select ranges and trim values
|
||||||
|
user_trim = self.choose_range(packet, response, target_user_count)
|
||||||
|
if user_trim == None:
|
||||||
|
raise StcProtocolException("frequency trimming unsuccessful")
|
||||||
|
|
||||||
|
# calibration, round 2
|
||||||
|
packet = bytes([0x00])
|
||||||
|
packet += struct.pack(">B", 12)
|
||||||
|
for i in range(user_trim[0] - 2, user_trim[0] + 2):
|
||||||
|
packet += bytes([i & 0xff, 0x00])
|
||||||
|
for i in range(user_trim[0] - 2, user_trim[0] + 2):
|
||||||
|
packet += bytes([i & 0xff, 0x01])
|
||||||
|
for i in range(user_trim[0] - 2, user_trim[0] + 2):
|
||||||
|
packet += bytes([i & 0xff, 0x02])
|
||||||
|
self.write_packet(packet)
|
||||||
|
self.pulse(b"\xfe", timeout=1.0)
|
||||||
|
response = self.read_packet()
|
||||||
|
if len(response) < 2 or response[0] != 0x00:
|
||||||
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
|
|
||||||
|
# select final values
|
||||||
|
user_trim, user_count = self.choose_trim(packet, response, target_user_count)
|
||||||
|
self.trim_value = user_trim
|
||||||
|
self.trim_frequency = round(user_count * (self.baud_handshake / 2))
|
||||||
|
print("%.03f MHz" % (self.trim_frequency / 1E6))
|
||||||
|
|
||||||
|
# switch to programming frequency
|
||||||
|
print("Switching to %d baud: " % self.baud_transfer, end="")
|
||||||
|
sys.stdout.flush()
|
||||||
|
packet = bytes([0x01, 0x00, 0x00])
|
||||||
|
bauds = self.baud_transfer * 4
|
||||||
|
packet += struct.pack(">H", int(65535 - 24E6 / bauds))
|
||||||
|
packet += bytes([user_trim[1], user_trim[0]])
|
||||||
|
iap_wait = self.get_iap_delay(user_speed)
|
||||||
|
packet += bytes([iap_wait])
|
||||||
|
self.write_packet(packet)
|
||||||
|
response = self.read_packet()
|
||||||
|
if len(response) < 1 or response[0] != 0x01:
|
||||||
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
|
self.ser.baudrate = self.baud_transfer
|
||||||
|
|
||||||
|
def initialize_options(self, status_packet):
|
||||||
|
"""Initialize options"""
|
||||||
|
# XXX: not implemented yet
|
||||||
|
pass
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
"""Disconnect from MCU"""
|
||||||
|
|
||||||
|
# reset mcu
|
||||||
|
packet = bytes([0xff])
|
||||||
|
self.write_packet(packet)
|
||||||
|
self.ser.close()
|
||||||
|
print("Disconnected!")
|
||||||
|
|
||||||
class StcUsb15Protocol(Stc15Protocol):
|
class StcUsb15Protocol(Stc15Protocol):
|
||||||
"""USB should use large blocks"""
|
"""USB should use large blocks"""
|
||||||
PROGRAM_BLOCKSIZE = 128
|
PROGRAM_BLOCKSIZE = 128
|
||||||
|
Loading…
Reference in New Issue
Block a user