Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
af153a89e7 |
84
README.md
84
README.md
@ -4,16 +4,15 @@ stcgal - STC MCU ISP flash tool
|
||||
stcgal is a command line flash programming tool for STC MCU Ltd. [1]
|
||||
8051 compatible microcontrollers. The name was inspired by avrdude [2].
|
||||
|
||||
STC microcontrollers have an UART/USB based boot strap loader (BSL). It
|
||||
STC microcontrollers have a UART based boot strap loader (BSL). It
|
||||
utilizes a packet-based protocol to flash the code memory and IAP
|
||||
memory over a serial link. This is referred to as in-system programming
|
||||
(ISP). The BSL is also used to configure various (fuse-like) device
|
||||
memory over a serial link. This is referred to as in-system programming (ISP).
|
||||
The BSL is also used to configure various (fuse-like) device
|
||||
options. Unfortunately, this protocol is not publicly documented and
|
||||
STC only provide a (crude) Windows GUI application for programming.
|
||||
|
||||
stcgal is a full-featured Open Source replacement for STC's Windows
|
||||
software; it supports a wide range of MCUs, it is very portable and
|
||||
suitable for automation.
|
||||
stcgal is a full-featured Open Source replacement for STC's Windows software;
|
||||
it supports a wide range of MCUs, it is very portable and suitable for automation.
|
||||
|
||||
[1] http://stcmcu.com/
|
||||
[2] http://www.nongnu.org/avrdude/
|
||||
@ -26,32 +25,23 @@ stcgal should fully support STC 89/90/10/11/12/15 series MCUs.
|
||||
So far, stcgal was tested with the following MCU models:
|
||||
|
||||
* STC89C52RC (BSL version: 4.3C)
|
||||
* STC90C52RC (BSL version: 4.3C)
|
||||
* STC89C54RD+ (BSL version: 4.3C)
|
||||
* STC12C2052 (BSL version: 5.8D)
|
||||
* STC12C2052AD (BSL version: 5.8D)
|
||||
* STC12C5608AD (BSL version: 6.0G)
|
||||
* STC12C5A16S2 (BSL version: 6.2I)
|
||||
* STC12C5A60S2 (BSL version: 6.2I)
|
||||
* STC11F02E (BSL version: 6.5K)
|
||||
* STC10F04XE (BSL version: 6.5J)
|
||||
* STC11F08XE (BSL version: 6.5M)
|
||||
* STC12C5204AD (BSL version: 6.6H)
|
||||
* STC15F104E (BSL version: 6.7Q)
|
||||
* STC15F204EA (BSL version: 6.7R)
|
||||
* STC15L104W (BSL version: 7.1.4Q)
|
||||
* STC15F104W (BSL version: 7.1.4Q)
|
||||
* IAP15F2K61S2 (BSL version: 7.1.4S)
|
||||
* STC15L104W (BSL version: 7.1Q)
|
||||
* IAP15F2K61S2 (BSL version: 7.1S)
|
||||
* STC15L2K16S2 (BSL version: 7.2.4S)
|
||||
* STC15W408AS (BSL version: 7.2.4T)
|
||||
* STC15W4K56S4 (BSL version: 7.3.4T, UART and USB mode)
|
||||
* STC15W4K56S4 (BSL version: 7.3.4T)
|
||||
|
||||
Compatibility reports, both negative and positive, are welcome.
|
||||
More compatibility testing is going to happen soon.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* UART and USB BSL support
|
||||
* Display part info
|
||||
* Determine operating frequency
|
||||
* Program flash memory
|
||||
@ -59,14 +49,11 @@ Features
|
||||
* Set device options
|
||||
* Read unique device ID (STC 10/11/12/15)
|
||||
* Trim RC oscillator frequency (STC 15)
|
||||
* Automatic power-cycling with DTR toggle
|
||||
* Automatic UART protocol detection
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
stcgal requires Python 3.2 (or later) and pySerial. USB support is
|
||||
optional and requires pyusb 1.0.0b2 or later. You can run stcgal
|
||||
stcgal requires Python 3.2 (or later) and pySerial. You can run stcgal
|
||||
directly with the included ```stcgal.py``` script. The recommended
|
||||
method for permanent installation is to use Python's setuptools. Run
|
||||
```./setup.py build``` to build and ```sudo ./setup.py install```
|
||||
@ -79,27 +66,24 @@ Usage
|
||||
Call stcgal with ```-h``` for usage information.
|
||||
|
||||
```
|
||||
usage: stcgal.py [-h] [-a] [-P {stc89,stc12a,stc12,stc15a,stc15,auto}]
|
||||
[-p PORT] [-b BAUD] [-l HANDSHAKE] [-o OPTION] [-t TRIM] [-D]
|
||||
[code_image] [eeprom_image]
|
||||
usage: stcgal.py [-h] [-P {stc89,stc12a,stc12,stc15a,stc15}] [-p PORT]
|
||||
[-b BAUD] [-l HANDSHAKE] [-o OPTION] [-t TRIM] [-D]
|
||||
[code_binary] [eeprom_binary]
|
||||
|
||||
stcgal 1.0 - an STC MCU ISP flash tool
|
||||
(C) 2014-2015 Grigori Goronzy
|
||||
https://github.com/grigorig/stcgal
|
||||
|
||||
positional arguments:
|
||||
code_image code segment file to flash (BIN/HEX)
|
||||
eeprom_image eeprom segment file to flash (BIN/HEX)
|
||||
code_binary code segment binary file to flash
|
||||
eeprom_binary eeprom segment binary file to flash
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-a, --autoreset cycle power automatically by asserting DTR
|
||||
-P {stc89,stc12a,stc12,stc15a,stc15,auto}, --protocol {stc89,stc12a,stc12,stc15a,stc15,auto}
|
||||
-P {stc89,stc12a,stc12,stc15a,stc15}, --protocol {stc89,stc12a,stc12,stc15a,stc15}
|
||||
protocol version
|
||||
-p PORT, --port PORT serial port device
|
||||
-b BAUD, --baud BAUD transfer baud rate (default: 19200)
|
||||
-l HANDSHAKE, --handshake HANDSHAKE
|
||||
handshake baud rate (default: 2400)
|
||||
handshake baud rate (default: 1200)
|
||||
-o OPTION, --option OPTION
|
||||
set option (can be used multiple times)
|
||||
-t TRIM, --trim TRIM RC oscillator frequency in kHz (STC15 series only)
|
||||
@ -111,17 +95,14 @@ Most importantly, ```-p``` sets the serial port to be used for programming.
|
||||
### Protocols
|
||||
|
||||
STC MCUs use a variety of related but incompatible protocols for the
|
||||
BSL. The protocol can be specified with the ```-P``` flag. Optionally,
|
||||
experimental protocol autodetection can be used. The mapping between
|
||||
protocols and MCU series is as follows:
|
||||
BSL. The protocol must be specified with the ```-P``` flag. Here's
|
||||
the general mapping between protocols and MCU series:
|
||||
|
||||
* ```stc89``` STC 89/90 series
|
||||
* ```stc12a``` STC12Cx052AD and possibly others
|
||||
* ```stc12``` Most STC10/11/12 series (default)
|
||||
* ```stc12``` Most STC10/11/12 series
|
||||
* ```stc15a``` STC15x104E and STC15x204E(A) series
|
||||
* ```stc15``` Most STC15 series
|
||||
* ```usb15``` USB support on STC15W4 series
|
||||
* ```auto``` Automatic detection of UART based protocols
|
||||
|
||||
The text files in the doc/ subdirectory provide an overview over
|
||||
the reverse engineered protocols used by the BSLs. For more details,
|
||||
@ -263,31 +244,6 @@ device options. Use the ```-t``` flag to request trimming to a certain
|
||||
value. Generally, frequencies between 4 and 35 MHz can be achieved. If
|
||||
trimming fails, stcgal will abort.
|
||||
|
||||
### Automatic power-cycling
|
||||
|
||||
STC's microcontrollers require a power-on reset to invoke the bootloader,
|
||||
which can be inconvenient. stcgal can use the DTR control signal of a
|
||||
serial interface to automate this. The DTR signal is asserted for
|
||||
approximately 500 ms when the autoreset feature is enabled with the
|
||||
```-a``` flag. This requires external circuitry to actually switch the
|
||||
power. In some cases, when the microcontroller draws only little power,
|
||||
it is possible to directly supply power from the DTR signal, however.
|
||||
|
||||
### Exit status
|
||||
|
||||
The exit status is 0 if no error occured while executing stcgal. Any
|
||||
error, such as a protocol error or I/O error, results in an exit
|
||||
status of 1. If the the user aborted stcgal by pressing CTRL-C,
|
||||
that results in an exit status of 2.
|
||||
|
||||
### USB support
|
||||
|
||||
STC15W4 series have an USB-based BSL that can be optionally
|
||||
used. USB support in stcgal is experimental and might change in the
|
||||
future. USB mode is enabled by using the ```usb15``` protocol. The
|
||||
port (```-p```) flag as well as the baudrate options are ignored for
|
||||
the USB protocol. RC frequency trimming is not supported.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
# This curious script dumps all model info from STC-ISP.
|
||||
# Data is directly read from the binary.
|
||||
# Offsets are for stc-isp-15xx-v6.85K.exe, sha1sum aa66e4c1ab49de27369b83c954a7c202acce0950
|
||||
# Offsets are for STC-ISP 6.85I, sha1sum a1a625d6c491fe98d0286ebac0a8d78b94dca81d
|
||||
|
||||
MCU_TABLE_OFFSET = 0x00064550
|
||||
MCU_TABLE_SIZE = 941
|
||||
MCU_TABLE_OFFSET = 0x00063550
|
||||
MCU_TABLE_SIZE = 914
|
||||
MCU_RECORD_SIZE = 32
|
||||
MCU_NAMES_OFFSET = 0x0007e80c
|
||||
MCU_NAMES_PTR_OFFSET = 0x0047e80c
|
||||
MCU_NAMES_OFFSET = 0x0007d708
|
||||
MCU_NAMES_PTR_OFFSET = 0x0047d708
|
||||
|
||||
import struct
|
||||
import sys
|
||||
|
24
setup.py
24
setup.py
@ -1,25 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 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 stcgal
|
||||
from setuptools import setup, find_packages
|
||||
@ -29,9 +8,6 @@ setup(
|
||||
version = stcgal.__version__,
|
||||
packages = find_packages(exclude=["doc"]),
|
||||
install_requires = ["pyserial"],
|
||||
extras_require = {
|
||||
"usb": ["pyusb>=1.0.0"]
|
||||
},
|
||||
entry_points = {
|
||||
"console_scripts": [
|
||||
"stcgal = stcgal.frontend:cli",
|
||||
|
@ -32,7 +32,6 @@ class StcGal:
|
||||
|
||||
def __init__(self, opts):
|
||||
self.opts = opts
|
||||
|
||||
if opts.protocol == "stc89":
|
||||
self.protocol = Stc89Protocol(opts.port, opts.handshake, opts.baud)
|
||||
elif opts.protocol == "stc12a":
|
||||
@ -42,13 +41,9 @@ class StcGal:
|
||||
elif opts.protocol == "stc15a":
|
||||
self.protocol = Stc15AProtocol(opts.port, opts.handshake, opts.baud,
|
||||
round(opts.trim * 1000))
|
||||
elif opts.protocol == "stc15":
|
||||
else:
|
||||
self.protocol = Stc15Protocol(opts.port, opts.handshake, opts.baud,
|
||||
round(opts.trim * 1000))
|
||||
elif opts.protocol == "usb15":
|
||||
self.protocol = StcUsb15Protocol()
|
||||
else:
|
||||
self.protocol = StcBaseProtocol(opts.port, opts.handshake, opts.baud)
|
||||
|
||||
self.protocol.debug = opts.debug
|
||||
|
||||
@ -122,21 +117,7 @@ class StcGal:
|
||||
self.protocol.disconnect()
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self.protocol.connect(autoreset=self.opts.autoreset)
|
||||
|
||||
if self.opts.protocol == "auto":
|
||||
if not self.protocol.protocol_name:
|
||||
raise StcProtocolException("cannot detect protocol")
|
||||
base_protocol = self.protocol
|
||||
self.opts.protocol = self.protocol.protocol_name
|
||||
print("Protocol detected: %s" % self.opts.protocol)
|
||||
# recreate self.protocol with proper protocol class
|
||||
self.__init__(self.opts)
|
||||
else:
|
||||
base_protocol = None
|
||||
|
||||
self.protocol.initialize(base_protocol)
|
||||
try: self.protocol.connect()
|
||||
except KeyboardInterrupt:
|
||||
sys.stdout.flush();
|
||||
print("interrupted")
|
||||
@ -150,10 +131,6 @@ class StcGal:
|
||||
sys.stdout.flush();
|
||||
print("Serial port error: %s" % e, file=sys.stderr)
|
||||
return 1
|
||||
except IOError as e:
|
||||
sys.stdout.flush();
|
||||
print("I/O error: %s" % e, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
if self.opts.code_image:
|
||||
@ -193,11 +170,10 @@ def cli():
|
||||
description="stcgal %s - an STC MCU ISP flash tool\n(C) 2014-2015 Grigori Goronzy\nhttps://github.com/grigorig/stcgal" %stcgal.__version__)
|
||||
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", "stc12", "stc15a", "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("-l", "--handshake", help="handshake baud rate (default: 1200)", type=BaudType(), default=1200)
|
||||
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 kHz (STC15 series only)", type=float, default=0.0)
|
||||
parser.add_argument("-D", "--debug", help="enable debug output", action="store_true")
|
||||
|
@ -32,38 +32,14 @@ class MCUModelDatabase:
|
||||
MCUModel = collections.namedtuple("MCUModel", ["name", "magic", "total", "code", "eeprom"])
|
||||
|
||||
models = (
|
||||
MCUModel(name='STC8F8K08S4A10', magic=0xf611, total=65536, code=8192, eeprom=57344),
|
||||
MCUModel(name='STC8F8K16S4A10', magic=0xf612, total=65536, code=16384, eeprom=49152),
|
||||
MCUModel(name='STC8F8K24S4A10', magic=0xf613, total=65536, code=24576, eeprom=40960),
|
||||
MCUModel(name='STC8F8K32S4A10', magic=0xf614, total=65536, code=32768, eeprom=32768),
|
||||
MCUModel(name='STC8F8K40S4A10', magic=0xf615, total=65536, code=40960, eeprom=24576),
|
||||
MCUModel(name='STC8F8K48S4A10', magic=0xf616, total=65536, code=49152, eeprom=16384),
|
||||
MCUModel(name='STC8F8K56S4A10', magic=0xf617, total=65536, code=57344, eeprom=8192),
|
||||
MCUModel(name='STC8F8K64S4A10', magic=0xf618, total=65536, code=65024, eeprom=512),
|
||||
MCUModel(name='STC8A8K08S4A12', magic=0xf621, total=65536, code=8192, eeprom=57344),
|
||||
MCUModel(name='STC8A8K16S4A12', magic=0xf622, total=65536, code=16384, eeprom=49152),
|
||||
MCUModel(name='STC8A8K24S4A12', magic=0xf623, total=65536, code=24576, eeprom=40960),
|
||||
MCUModel(name='STC8A8K32S4A12', magic=0xf624, total=65536, code=32768, eeprom=32768),
|
||||
MCUModel(name='STC8A8K40S4A12', magic=0xf625, total=65536, code=40960, eeprom=24576),
|
||||
MCUModel(name='STC8A8K48S4A12', magic=0xf626, total=65536, code=49152, eeprom=16384),
|
||||
MCUModel(name='STC8A8K56S4A12', magic=0xf627, total=65536, code=57344, eeprom=8192),
|
||||
MCUModel(name='STC8A8K64S4A12', magic=0xf628, total=65536, code=65024, eeprom=512),
|
||||
MCUModel(name='STC8F2K08S4', magic=0xf631, total=65536, code=8192, eeprom=57344),
|
||||
MCUModel(name='STC8F2K16S4', magic=0xf632, total=65536, code=16384, eeprom=49152),
|
||||
MCUModel(name='STC8F2K24S4', magic=0xf633, total=65536, code=24576, eeprom=40960),
|
||||
MCUModel(name='STC8F2K32S4', magic=0xf634, total=65536, code=32768, eeprom=32768),
|
||||
MCUModel(name='STC8F2K40S4', magic=0xf635, total=65536, code=40960, eeprom=24576),
|
||||
MCUModel(name='STC8F2K48S4', magic=0xf636, total=65536, code=49152, eeprom=16384),
|
||||
MCUModel(name='STC8F2K56S4', magic=0xf637, total=65536, code=57344, eeprom=8192),
|
||||
MCUModel(name='STC8F2K64S4', magic=0xf638, total=65536, code=65024, eeprom=512),
|
||||
MCUModel(name='STC15H4K08S4', magic=0xf601, total=65536, code=8192, eeprom=57344),
|
||||
MCUModel(name='STC15H4K16S4', magic=0xf602, total=65536, code=16384, eeprom=49152),
|
||||
MCUModel(name='STC15H4K24S4', magic=0xf603, total=65536, code=24576, eeprom=40960),
|
||||
MCUModel(name='STC15H4K32S4', magic=0xf604, total=65536, code=32768, eeprom=32768),
|
||||
MCUModel(name='STC15H4K40S4', magic=0xf605, total=65536, code=40960, eeprom=24576),
|
||||
MCUModel(name='STC15H4K48S4', magic=0xf606, total=65536, code=49152, eeprom=16384),
|
||||
MCUModel(name='STC15H4K56S4', magic=0xf607, total=65536, code=57344, eeprom=8192),
|
||||
MCUModel(name='STC15H4K64S4', magic=0xf608, total=65536, code=65024, eeprom=512),
|
||||
MCUModel(name='STC15H4K08S4', magic=0xf601, total=65536, code=8192, eeprom=0),
|
||||
MCUModel(name='STC15H4K16S4', magic=0xf602, total=65536, code=16384, eeprom=0),
|
||||
MCUModel(name='STC15H4K24S4', magic=0xf603, total=65536, code=24576, eeprom=0),
|
||||
MCUModel(name='STC15H4K32S4', magic=0xf604, total=65536, code=32768, eeprom=0),
|
||||
MCUModel(name='STC15H4K40S4', magic=0xf605, total=65536, code=40960, eeprom=0),
|
||||
MCUModel(name='STC15H4K48S4', magic=0xf606, total=65536, code=49152, eeprom=0),
|
||||
MCUModel(name='STC15H4K56S4', magic=0xf607, total=65536, code=57344, eeprom=0),
|
||||
MCUModel(name='STC15H4K64S4', magic=0xf608, total=65536, code=65024, eeprom=0),
|
||||
MCUModel(name='STC15F2K08S2', magic=0xf401, total=65536, code=8192, eeprom=54272),
|
||||
MCUModel(name='STC15F2K16S2', magic=0xf402, total=65536, code=16384, eeprom=46080),
|
||||
MCUModel(name='STC15F2K24S2', magic=0xf403, total=65536, code=24576, eeprom=37888),
|
||||
@ -233,9 +209,6 @@ class MCUModelDatabase:
|
||||
MCUModel(name='STC15W1K08PWM', magic=0xf52d, total=65536, code=8192, eeprom=52224),
|
||||
MCUModel(name='STC15W1K16PWM', magic=0xf52e, total=65536, code=16384, eeprom=44032),
|
||||
MCUModel(name='STC15W1K20S', magic=0xf52f, total=65536, code=20480, eeprom=39936),
|
||||
MCUModel(name='STC15W1K20AS', magic=0xf534, total=65536, code=20480, eeprom=39936),
|
||||
MCUModel(name='STC15W1K32AS', magic=0xf535, total=65536, code=32768, eeprom=27648),
|
||||
MCUModel(name='STC15W1K48AS', magic=0xf536, total=65536, code=49152, eeprom=11264),
|
||||
MCUModel(name='STC15W2K32S2', magic=0xf530, total=65536, code=32768, eeprom=27648),
|
||||
MCUModel(name='STC15W2K48S2', magic=0xf531, total=65536, code=49152, eeprom=11264),
|
||||
MCUModel(name='STC15W2K32AS', magic=0xf532, total=65536, code=32768, eeprom=27648),
|
||||
|
@ -21,19 +21,11 @@
|
||||
#
|
||||
|
||||
import serial
|
||||
import sys, os, time, struct, re
|
||||
import sys, os, time, struct
|
||||
import argparse
|
||||
import collections
|
||||
from stcgal.models import MCUModelDatabase
|
||||
from stcgal.utils import Utils
|
||||
import functools
|
||||
|
||||
try:
|
||||
import usb.core, usb.util
|
||||
_usb_available = True
|
||||
except ImportError:
|
||||
_usb_available = False
|
||||
|
||||
|
||||
class StcFramingException(Exception):
|
||||
"""Something wrong with packet framing or checksum"""
|
||||
@ -454,13 +446,14 @@ class Stc15AOption(BaseOption):
|
||||
|
||||
class Stc15Option(BaseOption):
|
||||
def __init__(self, msr):
|
||||
assert len(msr) >= 4
|
||||
assert len(msr) == 5
|
||||
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),
|
||||
("cpu_core_voltage", self.get_core_voltage, self.set_core_voltage),
|
||||
("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),
|
||||
@ -475,9 +468,6 @@ class Stc15Option(BaseOption):
|
||||
("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)
|
||||
|
||||
@ -642,8 +632,6 @@ class StcBaseProtocol:
|
||||
"""magic byte for packets sent by host"""
|
||||
PACKET_HOST = bytes([0x6a])
|
||||
|
||||
PARITY = serial.PARITY_NONE
|
||||
|
||||
def __init__(self, port, baud_handshake, baud_transfer):
|
||||
self.port = port
|
||||
self.baud_handshake = baud_handshake
|
||||
@ -656,14 +644,19 @@ class StcBaseProtocol:
|
||||
self.model = None
|
||||
self.uid = None
|
||||
self.debug = False
|
||||
self.status_packet = None
|
||||
self.protocol_name = None
|
||||
|
||||
def dump_packet(self, data, receive=True):
|
||||
if self.debug:
|
||||
print("%s Packet data: %s" % (("<-" if receive else "->"),
|
||||
Utils.hexstr(data, " ")), file=sys.stderr)
|
||||
|
||||
def modular_sum(self, data):
|
||||
"""modular 16-bit sum"""
|
||||
|
||||
s = 0
|
||||
for b in data: s += b
|
||||
return s & 0xffff
|
||||
|
||||
def read_bytes_safe(self, num):
|
||||
"""Read data from serial port with timeout handling
|
||||
|
||||
@ -675,14 +668,127 @@ class StcBaseProtocol:
|
||||
|
||||
return data
|
||||
|
||||
def extract_payload(self, packet):
|
||||
"""Extract the payload of a packet"""
|
||||
def print_mcu_info(self):
|
||||
"""Print MCU status information"""
|
||||
|
||||
if packet[-1] != self.PACKET_END[0]:
|
||||
self.dump_packet(packet)
|
||||
raise StcFramingException("incorrect frame end")
|
||||
MCUModelDatabase.print_model_info(self.model)
|
||||
print("Target frequency: %.3f MHz" % (self.mcu_clock_hz / 1E6))
|
||||
print("Target BSL version: %s" % self.mcu_bsl_version)
|
||||
|
||||
return packet[5:-1]
|
||||
def pulse(self, character=b"\x7f", timeout=0):
|
||||
"""Send a sequence of bytes for synchronization with MCU"""
|
||||
|
||||
duration = 0
|
||||
while True:
|
||||
if timeout > 0 and duration > timeout:
|
||||
raise serial.SerialTimeoutException("pulse timeout")
|
||||
self.ser.write(character)
|
||||
self.ser.flush()
|
||||
time.sleep(0.015)
|
||||
duration += 0.015
|
||||
if self.ser.inWaiting() > 0: break
|
||||
|
||||
def initialize_model(self):
|
||||
"""Initialize model-specific information"""
|
||||
|
||||
try:
|
||||
self.model = MCUModelDatabase.find_model(self.mcu_magic)
|
||||
except NameError:
|
||||
msg = ("WARNING: Unknown model %02X%02X!" %
|
||||
(self.mcu_magic >> 8, self.mcu_magic & 0xff))
|
||||
print(msg, file=sys.stderr)
|
||||
self.model = MCUModelDatabase.MCUModel(name="UNKNOWN",
|
||||
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 StcProtocolException("incorrect magic in status packet")
|
||||
return status_packet
|
||||
|
||||
def get_iap_delay(self, clock_hz):
|
||||
"""IAP wait states for STC12A+ (according to datasheet(s))"""
|
||||
|
||||
iap_wait = 0x80
|
||||
if clock_hz < 1E6: iap_wait = 0x87
|
||||
elif clock_hz < 2E6: iap_wait = 0x86
|
||||
elif clock_hz < 3E6: iap_wait = 0x85
|
||||
elif clock_hz < 6E6: iap_wait = 0x84
|
||||
elif clock_hz < 12E6: iap_wait = 0x83
|
||||
elif clock_hz < 20E6: iap_wait = 0x82
|
||||
elif clock_hz < 24E6: iap_wait = 0x81
|
||||
|
||||
return iap_wait
|
||||
|
||||
def set_option(self, name, value):
|
||||
self.options.set_option(name, value)
|
||||
|
||||
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,
|
||||
parity=self.PARITY)
|
||||
# set baudrate separately to workaround a bug with the CH340 driver
|
||||
# in older Linux kernels
|
||||
self.ser.baudrate = self.baud_handshake
|
||||
|
||||
# fast timeout values to deal with detection errors
|
||||
self.ser.timeout = 0.5
|
||||
self.ser.interCharTimeout = 0.5
|
||||
|
||||
# avoid glitches if there is something in the input buffer
|
||||
self.ser.flushInput()
|
||||
|
||||
print("Waiting for MCU, please cycle power: ", end="")
|
||||
sys.stdout.flush()
|
||||
|
||||
# send sync, and wait for MCU response
|
||||
# ignore errors until we see a valid response
|
||||
status_packet = None
|
||||
while not status_packet:
|
||||
try:
|
||||
self.pulse()
|
||||
status_packet = self.get_status_packet()
|
||||
except (StcFramingException, serial.SerialTimeoutException): pass
|
||||
print("done")
|
||||
|
||||
# conservative timeout values
|
||||
self.ser.timeout = 15.0
|
||||
self.ser.interCharTimeout = 1.0
|
||||
|
||||
self.initialize_status(status_packet)
|
||||
self.initialize_model()
|
||||
self.initialize_options(status_packet)
|
||||
|
||||
def disconnect(self):
|
||||
"""Disconnect from MCU"""
|
||||
|
||||
# reset mcu
|
||||
packet = bytes([0x82])
|
||||
self.write_packet(packet)
|
||||
self.ser.close()
|
||||
print("Disconnected!")
|
||||
|
||||
|
||||
class Stc89Protocol(StcBaseProtocol):
|
||||
"""Protocol handler for STC 89/90 series"""
|
||||
|
||||
"""These don't use any parity"""
|
||||
PARITY = serial.PARITY_NONE
|
||||
|
||||
"""block size for programming flash"""
|
||||
PROGRAM_BLOCKSIZE = 128
|
||||
|
||||
def __init__(self, port, baud_handshake, baud_transfer):
|
||||
StcBaseProtocol.__init__(self, port, baud_handshake, baud_transfer)
|
||||
|
||||
self.cpu_6t = None
|
||||
|
||||
def read_packet(self):
|
||||
"""Read and check packet from MCU.
|
||||
@ -722,205 +828,22 @@ class StcBaseProtocol:
|
||||
packet_len, = struct.unpack(">H", packet[3:5])
|
||||
packet += self.read_bytes_safe(packet_len - 3)
|
||||
|
||||
# verify checksum and extract payload
|
||||
payload = self.extract_payload(packet);
|
||||
# verify end code
|
||||
if packet[packet_len+1] != self.PACKET_END[0]:
|
||||
self.dump_packet(packet)
|
||||
raise StcFramingException("incorrect frame end")
|
||||
|
||||
self.dump_packet(packet, receive=True)
|
||||
|
||||
# payload only is returned
|
||||
return payload
|
||||
|
||||
def print_mcu_info(self):
|
||||
"""Print MCU status information"""
|
||||
|
||||
MCUModelDatabase.print_model_info(self.model)
|
||||
print("Target frequency: %.3f MHz" % (self.mcu_clock_hz / 1E6))
|
||||
print("Target BSL version: %s" % self.mcu_bsl_version)
|
||||
|
||||
def pulse(self, character=b"\x7f", timeout=0):
|
||||
"""Send a sequence of bytes for synchronization with MCU"""
|
||||
|
||||
duration = 0
|
||||
while True:
|
||||
if timeout > 0 and duration > timeout:
|
||||
raise serial.SerialTimeoutException("pulse timeout")
|
||||
self.ser.write(character)
|
||||
self.ser.flush()
|
||||
time.sleep(0.015)
|
||||
duration += 0.015
|
||||
if self.ser.inWaiting() > 0: break
|
||||
|
||||
def initialize_model(self):
|
||||
"""Initialize model-specific information"""
|
||||
|
||||
self.mcu_magic, = struct.unpack(">H", self.status_packet[20:22])
|
||||
try:
|
||||
self.model = MCUModelDatabase.find_model(self.mcu_magic)
|
||||
except NameError:
|
||||
msg = ("WARNING: Unknown model %02X%02X!" %
|
||||
(self.mcu_magic >> 8, self.mcu_magic & 0xff))
|
||||
print(msg, file=sys.stderr)
|
||||
self.model = MCUModelDatabase.MCUModel(name="UNKNOWN",
|
||||
magic=self.mcu_magic, total=63488, code=63488, eeprom=0)
|
||||
|
||||
# special case for duplicated mcu magic,
|
||||
# 0xf294 (STC15F104W, STC15F104E)
|
||||
# 0xf2d4 (STC15L104W, STC15L104E)
|
||||
# duplicated mcu magic can be found using command,
|
||||
# grep -o 'magic=[^,]*' models.py | sort | uniq -d
|
||||
if self.mcu_magic in (0xF294, 0xF2D4):
|
||||
mcu_name = self.model.name[:-1]
|
||||
mcu_name += "E" if self.status_packet[17] < 0x70 else "W"
|
||||
self.model = self.model._replace(name = mcu_name)
|
||||
|
||||
protocol_database = [("stc89", "STC(89|90)(C|LE)\d"),
|
||||
("stc12a", "STC12(C|LE)\d052"),
|
||||
("stc12", "(STC|IAP)(10|11|12)\D"),
|
||||
("stc15a", "(STC|IAP)15[FL][01]0\d(E|EA|)$"),
|
||||
("stc15", "(STC|IAP|IRC)15\D")]
|
||||
|
||||
for protocol_name, pattern in protocol_database:
|
||||
if re.match(pattern, self.model.name):
|
||||
self.protocol_name = protocol_name
|
||||
break
|
||||
else:
|
||||
self.protocol_name = None
|
||||
|
||||
def get_status_packet(self):
|
||||
"""Read and decode status packet"""
|
||||
|
||||
packet = self.read_packet()
|
||||
if packet[0] == 0x80:
|
||||
# need to re-ack
|
||||
self.ser.parity = serial.PARITY_EVEN
|
||||
packet = (self.PACKET_START
|
||||
+ self.PACKET_HOST
|
||||
+ bytes([0x00, 0x07, 0x80, 0x00, 0xF1])
|
||||
+ self.PACKET_END)
|
||||
self.dump_packet(packet, receive=False)
|
||||
self.ser.write(packet)
|
||||
self.ser.flush()
|
||||
self.pulse()
|
||||
packet = self.read_packet()
|
||||
return packet
|
||||
|
||||
def get_iap_delay(self, clock_hz):
|
||||
"""IAP wait states for STC12A+ (according to datasheet(s))"""
|
||||
|
||||
iap_wait = 0x80
|
||||
if clock_hz < 1E6: iap_wait = 0x87
|
||||
elif clock_hz < 2E6: iap_wait = 0x86
|
||||
elif clock_hz < 3E6: iap_wait = 0x85
|
||||
elif clock_hz < 6E6: iap_wait = 0x84
|
||||
elif clock_hz < 12E6: iap_wait = 0x83
|
||||
elif clock_hz < 20E6: iap_wait = 0x82
|
||||
elif clock_hz < 24E6: iap_wait = 0x81
|
||||
|
||||
return iap_wait
|
||||
|
||||
def set_option(self, name, value):
|
||||
self.options.set_option(name, value)
|
||||
|
||||
def connect(self, autoreset=False):
|
||||
"""Connect to MCU and initialize communication.
|
||||
|
||||
Set up serial port, send sync sequence and get part info.
|
||||
"""
|
||||
|
||||
self.ser = serial.Serial(port=self.port, parity=self.PARITY)
|
||||
# set baudrate separately to work around a bug with the CH340 driver
|
||||
# on older Linux kernels
|
||||
self.ser.baudrate = self.baud_handshake
|
||||
|
||||
# fast timeout values to deal with detection errors
|
||||
self.ser.timeout = 0.5
|
||||
self.ser.interCharTimeout = 0.5
|
||||
|
||||
# avoid glitches if there is something in the input buffer
|
||||
self.ser.flushInput()
|
||||
|
||||
if autoreset:
|
||||
print("Cycling power: ", end="")
|
||||
sys.stdout.flush()
|
||||
self.ser.setDTR(True)
|
||||
time.sleep(0.5)
|
||||
self.ser.setDTR(False)
|
||||
print("done")
|
||||
print("Waiting for MCU: ", end="")
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
print("Waiting for MCU, please cycle power: ", end="")
|
||||
sys.stdout.flush()
|
||||
|
||||
# send sync, and wait for MCU response
|
||||
# ignore errors until we see a valid response
|
||||
self.status_packet = None
|
||||
while not self.status_packet:
|
||||
try:
|
||||
self.pulse()
|
||||
self.status_packet = self.get_status_packet()
|
||||
except (StcFramingException, serial.SerialTimeoutException): pass
|
||||
print("done")
|
||||
|
||||
# conservative timeout values
|
||||
self.ser.timeout = 15.0
|
||||
self.ser.interCharTimeout = 1.0
|
||||
|
||||
self.initialize_model()
|
||||
|
||||
def initialize(self, base_protocol = None):
|
||||
if base_protocol:
|
||||
self.ser = base_protocol.ser
|
||||
self.ser.parity = self.PARITY
|
||||
packet = base_protocol.status_packet
|
||||
packet = (self.PACKET_START
|
||||
+ self.PACKET_MCU
|
||||
+ struct.pack(">H", len(packet) + 4)
|
||||
+ packet
|
||||
+ self.PACKET_END)
|
||||
self.status_packet = self.extract_payload(packet)
|
||||
self.mcu_magic = base_protocol.mcu_magic
|
||||
self.model = base_protocol.model
|
||||
|
||||
self.initialize_status(self.status_packet)
|
||||
self.print_mcu_info()
|
||||
self.initialize_options(self.status_packet)
|
||||
|
||||
def disconnect(self):
|
||||
"""Disconnect from MCU"""
|
||||
|
||||
# reset mcu
|
||||
packet = bytes([0x82])
|
||||
self.write_packet(packet)
|
||||
self.ser.close()
|
||||
print("Disconnected!")
|
||||
|
||||
|
||||
class Stc89Protocol(StcBaseProtocol):
|
||||
"""Protocol handler for STC 89/90 series"""
|
||||
|
||||
"""These don't use any parity"""
|
||||
PARITY = serial.PARITY_NONE
|
||||
|
||||
"""block size for programming flash"""
|
||||
PROGRAM_BLOCKSIZE = 128
|
||||
|
||||
def __init__(self, port, baud_handshake, baud_transfer):
|
||||
StcBaseProtocol.__init__(self, port, baud_handshake, baud_transfer)
|
||||
|
||||
self.cpu_6t = None
|
||||
|
||||
def extract_payload(self, packet):
|
||||
"""Verify the checksum of packet and return its payload"""
|
||||
|
||||
packet_csum = packet[-2]
|
||||
calc_csum = sum(packet[2:-2]) & 0xff
|
||||
# verify checksum
|
||||
packet_csum = packet[packet_len]
|
||||
calc_csum = sum(packet[2:packet_len]) & 0xff
|
||||
if packet_csum != calc_csum:
|
||||
self.dump_packet(packet)
|
||||
raise StcFramingException("packet checksum mismatch")
|
||||
|
||||
payload = StcBaseProtocol.extract_payload(self, packet)
|
||||
return payload[:-1]
|
||||
self.dump_packet(packet, receive=True)
|
||||
|
||||
# payload only is returned
|
||||
return packet[5:packet_len]
|
||||
|
||||
def write_packet(self, data):
|
||||
"""Send packet to MCU.
|
||||
@ -991,6 +914,7 @@ class Stc89Protocol(StcBaseProtocol):
|
||||
def initialize_status(self, packet):
|
||||
"""Decode status packet and store basic MCU info"""
|
||||
|
||||
self.mcu_magic, = struct.unpack(">H", packet[20:22])
|
||||
self.cpu_6t = not bool(packet[19] & 1)
|
||||
|
||||
cpu_t = 6.0 if self.cpu_6t else 12.0
|
||||
@ -1120,6 +1044,8 @@ class Stc12AProtocol(Stc89Protocol):
|
||||
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(8):
|
||||
freq_counter += struct.unpack(">H", packet[1+2*i:3+2*i])[0]
|
||||
@ -1166,7 +1092,7 @@ class Stc12AProtocol(Stc89Protocol):
|
||||
def handshake(self):
|
||||
"""Do baudrate handshake
|
||||
|
||||
Initiate and do the (rather complicated) baudrate handshake.
|
||||
Initate and do the (rather complicated) baudrate handshake.
|
||||
"""
|
||||
|
||||
# start baudrate handshake
|
||||
@ -1258,17 +1184,50 @@ class Stc12Protocol(StcBaseProtocol):
|
||||
def __init__(self, port, baud_handshake, baud_transfer):
|
||||
StcBaseProtocol.__init__(self, port, baud_handshake, baud_transfer)
|
||||
|
||||
def extract_payload(self, packet):
|
||||
"""Verify the checksum of packet and return its payload"""
|
||||
def read_packet(self):
|
||||
"""Read and check packet from MCU.
|
||||
|
||||
packet_csum, = struct.unpack(">H", packet[-3:-1])
|
||||
calc_csum = sum(packet[2:-3]) & 0xffff
|
||||
Reads a packet of data from the MCU and and do
|
||||
validity and checksum checks on it.
|
||||
|
||||
Returns packet payload or None in case of an error.
|
||||
"""
|
||||
|
||||
# read and check frame start magic
|
||||
packet = bytes()
|
||||
packet += self.read_bytes_safe(1)
|
||||
if packet[0] != self.PACKET_START[0]:
|
||||
raise StcFramingException("incorrect frame start")
|
||||
packet += self.read_bytes_safe(1)
|
||||
if packet[1] != self.PACKET_START[1]:
|
||||
raise StcFramingException("incorrect frame start")
|
||||
|
||||
# read direction and length
|
||||
packet += self.read_bytes_safe(3)
|
||||
if packet[2] != self.PACKET_MCU[0]:
|
||||
self.dump_packet(packet)
|
||||
raise StcFramingException("incorrect packet direction magic")
|
||||
|
||||
# read packet data
|
||||
packet_len, = struct.unpack(">H", packet[3:5])
|
||||
packet += self.read_bytes_safe(packet_len - 3)
|
||||
|
||||
# verify end code
|
||||
if packet[packet_len+1] != self.PACKET_END[0]:
|
||||
self.dump_packet(packet)
|
||||
raise StcFramingException("incorrect frame end")
|
||||
|
||||
# verify checksum
|
||||
packet_csum, = struct.unpack(">H", packet[packet_len-1:packet_len+1])
|
||||
calc_csum = sum(packet[2:packet_len-1]) & 0xffff
|
||||
if packet_csum != calc_csum:
|
||||
self.dump_packet(packet)
|
||||
raise StcFramingException("packet checksum mismatch")
|
||||
|
||||
payload = StcBaseProtocol.extract_payload(self, packet)
|
||||
return payload[:-2]
|
||||
self.dump_packet(packet, receive=True)
|
||||
|
||||
# payload only is returned
|
||||
return packet[5:packet_len-1]
|
||||
|
||||
def write_packet(self, data):
|
||||
"""Send packet to MCU.
|
||||
@ -1296,6 +1255,8 @@ class Stc12Protocol(StcBaseProtocol):
|
||||
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(8):
|
||||
freq_counter += struct.unpack(">H", packet[1+2*i:3+2*i])[0]
|
||||
@ -1500,6 +1461,8 @@ class Stc15AProtocol(Stc12Protocol):
|
||||
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]
|
||||
@ -1679,7 +1642,6 @@ class Stc15AProtocol(Stc12Protocol):
|
||||
|
||||
print("Target UID: %s" % Utils.hexstr(self.uid))
|
||||
|
||||
|
||||
class Stc15Protocol(Stc15AProtocol):
|
||||
"""Protocol handler for later STC 15 series"""
|
||||
|
||||
@ -1698,6 +1660,8 @@ class Stc15Protocol(Stc15AProtocol):
|
||||
def initialize_status(self, packet):
|
||||
"""Decode status packet and store basic MCU info"""
|
||||
|
||||
self.mcu_magic, = struct.unpack(">H", packet[20:22])
|
||||
|
||||
# check bit that control internal vs. external clock source
|
||||
# get frequency either stored from calibration or from
|
||||
# frequency counter
|
||||
@ -1884,8 +1848,6 @@ class Stc15Protocol(Stc15AProtocol):
|
||||
packet += bytes([0x00, 0x00, 0x5a, 0xa5])
|
||||
self.write_packet(packet)
|
||||
response = self.read_packet()
|
||||
if response[0] == 0x0f:
|
||||
raise StcProtocolException("MCU is locked")
|
||||
if response[0] != 0x05:
|
||||
raise StcProtocolException("incorrect magic in handshake packet")
|
||||
|
||||
@ -1945,12 +1907,15 @@ class Stc15Protocol(Stc15AProtocol):
|
||||
raise StcProtocolException("incorrect magic in finish packet")
|
||||
print("done")
|
||||
|
||||
def build_options(self):
|
||||
"""Build a 64 byte packet of option data from the current
|
||||
configuration."""
|
||||
|
||||
def program_options(self):
|
||||
print("Setting options: ", end="")
|
||||
sys.stdout.flush()
|
||||
msr = self.options.get_msr()
|
||||
packet = bytes([0xff] * 23)
|
||||
|
||||
packet = bytes([0x04, 0x00, 0x00])
|
||||
if self.bsl_version >= 0x72:
|
||||
packet += bytes([0x5a, 0xa5])
|
||||
packet += bytes([0xff] * 23)
|
||||
packet += bytes([(self.trim_frequency >> 24) & 0xff,
|
||||
0xff,
|
||||
(self.trim_frequency >> 16) & 0xff,
|
||||
@ -1961,23 +1926,10 @@ class Stc15Protocol(Stc15AProtocol):
|
||||
0xff])
|
||||
packet += bytes([msr[3]])
|
||||
packet += bytes([0xff] * 23)
|
||||
if len(msr) > 4:
|
||||
packet += bytes([msr[4]])
|
||||
else:
|
||||
packet += bytes([0xff])
|
||||
packet += bytes([0xff] * 3)
|
||||
packet += bytes([self.trim_value[0], self.trim_value[1] + 0x3f])
|
||||
packet += msr[0:3]
|
||||
return packet
|
||||
|
||||
def program_options(self):
|
||||
print("Setting options: ", end="")
|
||||
sys.stdout.flush()
|
||||
|
||||
packet = bytes([0x04, 0x00, 0x00])
|
||||
if self.bsl_version >= 0x72:
|
||||
packet += bytes([0x5a, 0xa5])
|
||||
packet += self.build_options()
|
||||
self.write_packet(packet)
|
||||
response = self.read_packet()
|
||||
if response[0] != 0x04 or response[1] != 0x54:
|
||||
@ -1987,165 +1939,3 @@ class Stc15Protocol(Stc15AProtocol):
|
||||
print("Target UID: %s" % Utils.hexstr(self.uid))
|
||||
|
||||
|
||||
class StcUsb15Protocol(Stc15Protocol):
|
||||
"""USB should use large blocks"""
|
||||
PROGRAM_BLOCKSIZE = 128
|
||||
|
||||
"""VID of STC devices"""
|
||||
USB_VID = 0x5354
|
||||
|
||||
"""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)
|
||||
self.dev = None
|
||||
|
||||
def dump_packet(self, data, request=0, value=0, index=0, receive=True):
|
||||
if self.debug:
|
||||
print("%s bRequest=%02X wValue=%04X wIndex=%04X data: %s" % (("<-" if receive else "->"),
|
||||
request, value, index, Utils.hexstr(data, " ")), file=sys.stderr)
|
||||
|
||||
def read_packet(self):
|
||||
"""Read a packet from the MCU"""
|
||||
|
||||
packet = self.dev.ctrl_transfer(self.USB_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")
|
||||
|
||||
data_len = packet[2]
|
||||
if (data_len) > len(packet) + 3:
|
||||
self.dump_packet(packet)
|
||||
raise StcFramingException("frame length mismatch")
|
||||
|
||||
data = packet[2:-1]
|
||||
csum = functools.reduce(lambda x, y: x - y, data, 0) & 0xff
|
||||
if csum != packet[-1]:
|
||||
self.dump_packet(packet)
|
||||
raise StcFramingException("frame checksum mismatch")
|
||||
|
||||
self.dump_packet(packet, receive=True)
|
||||
return packet[3:3+data_len]
|
||||
|
||||
def write_packet(self, request, value=0, index=0, data=bytes([0])):
|
||||
"""Write USB control packet"""
|
||||
|
||||
# Control transfers are maximum of 8 bytes each, and every
|
||||
# invidual partial transfer is checksummed individually.
|
||||
i = 0
|
||||
chunks = bytes()
|
||||
while i < len(data):
|
||||
c = data[i:i+7]
|
||||
csum = functools.reduce(lambda x, y: x - y, c, 0) & 0xff
|
||||
chunks += c + bytes([csum])
|
||||
i += 7
|
||||
|
||||
self.dump_packet(chunks, request, value, index, receive=False)
|
||||
self.dev.ctrl_transfer(self.USB_HOST2DEV, request, value, index, chunks);
|
||||
|
||||
def connect(self, autoreset=False):
|
||||
"""Connect to USB device and read info packet"""
|
||||
|
||||
# USB support is optional. Provide an error if pyusb is not available.
|
||||
if _usb_available == False:
|
||||
raise StcProtocolException("USB support not available. "
|
||||
+ "pyusb is not installed or not working correctly.")
|
||||
|
||||
print("Waiting for MCU, please cycle power: ", end="")
|
||||
sys.stdout.flush()
|
||||
|
||||
self.status_packet = None
|
||||
while not self.status_packet:
|
||||
try:
|
||||
self.dev = usb.core.find(idVendor=self.USB_VID, idProduct=self.USB_PID)
|
||||
if self.dev:
|
||||
self.dev.set_configuration()
|
||||
self.status_packet = self.read_packet()
|
||||
else:
|
||||
time.sleep(0.5)
|
||||
except (StcFramingException, usb.core.USBError): pass
|
||||
|
||||
self.initialize_model()
|
||||
print("done")
|
||||
|
||||
def handshake(self):
|
||||
print("Initializing: ", end="")
|
||||
sys.stdout.flush()
|
||||
|
||||
# handshake
|
||||
self.write_packet(0x01, 0, 0, bytes([0x03]))
|
||||
response = self.read_packet()
|
||||
if response[0] != 0x01:
|
||||
raise StcProtocolException("incorrect magic in handshake packet")
|
||||
|
||||
# enable/unlock MCU
|
||||
self.write_packet(0x05, 0xa55a, 0)
|
||||
response = self.read_packet()
|
||||
if response[0] == 0x0f:
|
||||
raise StcProtocolException("MCU is locked")
|
||||
if response[0] != 0x05:
|
||||
raise StcProtocolException("incorrect magic in handshake packet")
|
||||
|
||||
print("done")
|
||||
|
||||
def erase_flash(self, code, eeprom):
|
||||
print("Erasing flash: ", end="")
|
||||
sys.stdout.flush()
|
||||
self.write_packet(0x03, 0xa55a, 0)
|
||||
# XXX: better way to detect MCU has finished
|
||||
time.sleep(2)
|
||||
packet = self.read_packet()
|
||||
if packet[0] != 0x03:
|
||||
raise StcProtocolException("incorrect magic in erase packet")
|
||||
self.uid = packet[1:8]
|
||||
print("done")
|
||||
|
||||
def program_flash(self, data):
|
||||
"""Program the MCU's flash memory."""
|
||||
|
||||
print("Writing %d bytes: " % len(data), end="")
|
||||
sys.stdout.flush()
|
||||
for i in range(0, len(data), self.PROGRAM_BLOCKSIZE):
|
||||
packet = data[i:i+self.PROGRAM_BLOCKSIZE]
|
||||
while len(packet) < self.PROGRAM_BLOCKSIZE: packet += b"\x00"
|
||||
self.write_packet(0x22 if i == 0 else 0x02, 0xa55a, i, packet)
|
||||
# XXX: better way to detect MCU has finished
|
||||
time.sleep(0.1)
|
||||
response = self.read_packet()
|
||||
if response[0] != 0x02 or response[1] != 0x54:
|
||||
raise StcProtocolException("incorrect magic in write packet")
|
||||
print(".", end="")
|
||||
sys.stdout.flush()
|
||||
print(" done")
|
||||
|
||||
def program_options(self):
|
||||
print("Setting options: ", end="")
|
||||
sys.stdout.flush()
|
||||
|
||||
# always use 24 MHz pre-tuned value for now
|
||||
self.trim_value = (self.freq_count_24, 0x40)
|
||||
self.trim_frequency = int(24E6)
|
||||
|
||||
packet = self.build_options()
|
||||
self.write_packet(0x04, 0xa55a, 0, packet)
|
||||
# XXX: better way to detect MCU has finished
|
||||
time.sleep(0.5)
|
||||
response = self.read_packet()
|
||||
if response[0] != 0x04 or response[1] != 0x54:
|
||||
raise StcProtocolException("incorrect magic in option packet")
|
||||
print("done")
|
||||
|
||||
print("Target UID: %s" % Utils.hexstr(self.uid))
|
||||
|
||||
def disconnect(self):
|
||||
if self.dev:
|
||||
self.write_packet(0xff)
|
||||
print("Disconnected!")
|
||||
|
Reference in New Issue
Block a user