Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
083242d4f1 |
87
README.md
87
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,19 @@ 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)
|
||||
* STC15L2K16S2 (BSL version: 7.2.4S)
|
||||
* STC15W408AS (BSL version: 7.2.4T)
|
||||
* STC15W4K56S4 (BSL version: 7.3.4T, UART and USB mode)
|
||||
* STC15L104W (BSL version: 7.1Q)
|
||||
* IAP15F2K61S2 (BSL version: 7.1S)
|
||||
|
||||
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 +45,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 +62,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 +91,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,
|
||||
@ -252,7 +229,6 @@ Option key | Possible values | Protocols/Models | Descri
|
||||
```rstout_por_state``` | low/high | STC15+ | RSTOUT pin state after power-on reset
|
||||
```uart2_passthrough``` | true/false | STC15+ | Pass-through UART1 to UART2 pins (for single-wire UART mode)
|
||||
```uart2_pin_mode``` | push-pull/normal | STC15+ | Output mode of UART2 TX pin
|
||||
```cpu_core_voltage``` | low/mid/high | STC15W+ | CPU core voltage (low: ~2.7V, mid: ~3.3V, high: ~3.6V)
|
||||
|
||||
### Frequency trimming
|
||||
|
||||
@ -263,31 +239,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
|
||||
|
@ -5,7 +5,6 @@ MCS3 is like early STC15 MCS1.
|
||||
MCS2 is like early STC15 MCS2.
|
||||
MCS4 is like early STC15 MCS0 but with additions.
|
||||
MCSX is like early STC15 MCS12.
|
||||
MCSY is new in STC15W4 series
|
||||
|
||||
baseline
|
||||
B5 FF F7 BB 9F
|
||||
@ -81,37 +80,3 @@ external oscillator enabled (IAP15F2K61S2)
|
||||
external oscillator enabled + clock gain low (IAP15F2K61S2)
|
||||
9C 7F F7 BB 9C
|
||||
--> MCS 4 bit controls clock gain. high => high clock gain, low => low clock gain.
|
||||
|
||||
|
||||
cpu core supply level (MCSY)
|
||||
|
||||
in status packet:
|
||||
|
||||
2.68v
|
||||
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 7A C0 FD 27 ED 00 00 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 EA 92 FF FF FF 15 09 25 60 14 BD 16
|
||||
|
||||
3.33v
|
||||
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 92 30 FD 25 EA 00 FC 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 F7 92 FF FF FF 15 09 25 60 15 49 16
|
||||
|
||||
3.63v
|
||||
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 7A C0 FD 25 EF 00 00 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 FD 92 FF FF FF 15 09 25 60 14 D0 16
|
||||
|
||||
3.73v
|
||||
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 92 30 FD 25 EA 00 00 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 FF 92 FF FF FF 15 09 25 60 14 55 16
|
||||
^^
|
||||
MCSY
|
||||
|
||||
voltage: ff -> 3.73v
|
||||
fd -> 3.63v
|
||||
f7 -> 3.33v
|
||||
ea -> 2.68v
|
||||
|
||||
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
|
||||
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
|
||||
|
@ -58,11 +58,6 @@ info packet
|
||||
MCS2-4 MCSX
|
||||
^^
|
||||
factory calibration adjust for 24 MHz (range 0x40)?
|
||||
|
||||
STC15W4K56S4:
|
||||
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 7A C0 FD 27 ED 00 00 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 EA 92 FF FF FF 15 09 25 60 14 BD 16
|
||||
^^
|
||||
core voltage (MCSY)
|
||||
|
||||
IAP15F2K61S2:
|
||||
external osc:
|
||||
@ -145,9 +140,8 @@ option packet
|
||||
|
||||
FF FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF B5 FF F7 BB 9F 3A 48 16
|
||||
^ ^^^^^^^^^^^^^^
|
||||
MCSX ^^ MCS0-4
|
||||
MCSY
|
||||
(STC15W4)
|
||||
MCSX MCS0-4
|
||||
|
||||
|
||||
MCS bytes
|
||||
---------
|
||||
@ -160,7 +154,7 @@ RC calibration adjust
|
||||
|
||||
0x3f + RC calibration range (0x00, 0x40, 0x80, 0xc0)
|
||||
|
||||
### MCS2 - MCS4, MCSX and MCSY
|
||||
### MCS2 - MCS4 and MCSX
|
||||
|
||||
See stc15-options.txt
|
||||
|
||||
|
@ -1,128 +0,0 @@
|
||||
2015-12-10 23:47:44.198341: PC
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
2015-12-10 23:47:48.400692: MCU
|
||||
46 B9 68
|
||||
2015-12-10 23:47:48.411946: PC
|
||||
7F
|
||||
2015-12-10 23:47:48.414811: MCU
|
||||
00 34 50
|
||||
2015-12-10 23:47:48.427644: PC
|
||||
7F
|
||||
2015-12-10 23:47:48.428894: MCU
|
||||
8D FF 73 96 F5 7B 9F FF FF FF FF FF 27 ED 00 00
|
||||
73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00
|
||||
EC E0 04 D7 F8 73 BF FF FF 15 09 25 60 16 92 16
|
||||
2015-12-10 23:47:48.725370: PC
|
||||
46 B9 6A 00 20 00 0B 00 C0 80 C0 FF C0 00 80 80
|
||||
80 FF 80 00 40 80 40 FF 40 00 00 80 00 00 00 0A
|
||||
12 16 FE FE FE FE FE FE FE FE FE FE FE FE FE
|
||||
2015-12-10 23:47:49.088353: MCU
|
||||
46 B9 68
|
||||
2015-12-10 23:47:49.099586: PC
|
||||
FE
|
||||
2015-12-10 23:47:49.102589: MCU
|
||||
00 20 00
|
||||
2015-12-10 23:47:49.115089: PC
|
||||
FE
|
||||
2015-12-10 23:47:49.116479: MCU
|
||||
0B 0D 21 12 BC 18 3E 1A 05 24 FA 2F B3 34 D1 4A
|
||||
52 5E C0 52 DB 73 1A 00 00 08 7D 16
|
||||
2015-12-10 23:47:49.266317: PC
|
||||
46 B9 6A 00 20 00 0C 71 80 72 80 73 80 74 80 75
|
||||
80 76 80 6F 40 70 40 71 40 72 40 73 40 74 40 0A
|
||||
74 16 FE FE FE FE FE FE FE FE FE FE FE FE FE FE
|
||||
2015-12-10 23:47:49.650397: MCU
|
||||
46 B9 68
|
||||
2015-12-10 23:47:49.661888: PC
|
||||
FE
|
||||
2015-12-10 23:47:49.664523: MCU
|
||||
00 20 00
|
||||
2015-12-10 23:47:49.677636: PC
|
||||
FE
|
||||
2015-12-10 23:47:49.678633: MCU
|
||||
0C 23 BF 23 D3 23 E7 23 F6 24 0F 24 23 47 73 47
|
||||
B9 47 E1 48 09 48 36 48 59 09 5B 16
|
||||
2015-12-10 23:47:49.944529: PC
|
||||
46 B9 6A 00 0E 01 72 40 F6 FF 80 73 81 04 94 16
|
||||
2015-12-10 23:47:50.045100: MCU
|
||||
46 B9 68 00 07 01 00 70 16
|
||||
2015-12-10 23:47:50.116096: PC
|
||||
46 B9 6A 00 0B 05 00 00 5A A5 01 79 16
|
||||
2015-12-10 23:47:50.190036: MCU
|
||||
46 B9 68 00 07 05 00 74 16
|
||||
2015-12-10 23:47:50.255407: PC
|
||||
46 B9 6A 00 0B 03 00 00 5A A5 01 77 16
|
||||
2015-12-10 23:47:53.130695: MCU
|
||||
46 B9 68 00 0E 03 F5 28 00 A5 03 27 49 02 AE 16
|
||||
2015-12-10 23:47:53.210814: PC
|
||||
46 B9 6A 00 8B 22 00 00 5A A5 01 04 01 36 75 81
|
||||
07 12 00 6A E5 82 60 03 02 00 02 E4 78 FF F6 D8
|
||||
FD 01 02 AF 82 8F 06 1F EE 60 0F 7D 90 7E 01 1D
|
||||
BD FF 01 1E ED 4E 70 F7 80 EB 22 AF 82 DF FE 22
|
||||
E5 B0 F4 F5 B0 75 82 05 11 31 75 82 D0 11 19 E5
|
||||
B0 F4 F5 B0 75 82 64 11 19 E5 B0 F4 F5 B0 75 82
|
||||
64 11 19 E5 B0 F4 F5 B0 75 82 64 11 19 E5 B0 F4
|
||||
F5 B0 80 D6 75 82 00 22 FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF 49 E8 16
|
||||
2015-12-10 23:47:54.003906: MCU
|
||||
46 B9 68 00 08 02 54 00 C6 16
|
||||
2015-12-10 23:47:54.068777: PC
|
||||
46 B9 6A 00 8B 02 00 80 5A A5 FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF 81 F6 16
|
||||
2015-12-10 23:47:54.867956: MCU
|
||||
46 B9 68 00 08 02 54 00 C6 16
|
||||
2015-12-10 23:47:54.932281: PC
|
||||
46 B9 6A 00 8B 02 01 00 5A A5 FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF 81 77 16
|
||||
2015-12-10 23:47:55.732519: MCU
|
||||
46 B9 68 00 08 02 54 00 C6 16
|
||||
2015-12-10 23:47:55.796791: PC
|
||||
46 B9 6A 00 8B 02 01 80 5A A5 FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF 81 F7 16
|
||||
2015-12-10 23:47:56.536325: MCU
|
||||
46 B9 68 00 08 02 54 00 C6 16
|
||||
2015-12-10 23:47:56.616743: PC
|
||||
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 91 FF 20 FF FD 03 FF FF FF FF FF
|
||||
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
FF EC FF FF FF 74 BF F7 BC 9F 39 51 16
|
||||
2015-12-10 23:47:57.070169: MCU
|
||||
46 B9 68 00 08 04 54 00 C8 16
|
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":
|
||||
@ -41,14 +40,10 @@ class StcGal:
|
||||
self.protocol = Stc12Protocol(opts.port, opts.handshake, opts.baud)
|
||||
elif opts.protocol == "stc15a":
|
||||
self.protocol = Stc15AProtocol(opts.port, opts.handshake, opts.baud,
|
||||
round(opts.trim * 1000))
|
||||
elif opts.protocol == "stc15":
|
||||
round(opts.trim * 1000))
|
||||
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
|
||||
|
||||
@ -85,27 +80,27 @@ class StcGal:
|
||||
|
||||
print("Loading flash: ", end="")
|
||||
sys.stdout.flush()
|
||||
bindata = self.load_file_auto(self.opts.code_image)
|
||||
bindata = self.load_file_auto(self.opts.code_binary)
|
||||
|
||||
# warn if it overflows
|
||||
if len(bindata) > code_size:
|
||||
print("WARNING: code_image overflows into eeprom segment!", file=sys.stderr)
|
||||
print("WARNING: code_binary overflows into eeprom segment!", file=sys.stderr)
|
||||
if len(bindata) > (code_size + ee_size):
|
||||
print("WARNING: code_image truncated!", file=sys.stderr)
|
||||
print("WARNING: code_binary truncated!", file=sys.stderr)
|
||||
bindata = bindata[0:code_size + ee_size]
|
||||
|
||||
# add eeprom data if supplied
|
||||
if self.opts.eeprom_image:
|
||||
if self.opts.eeprom_binary:
|
||||
print("Loading EEPROM: ", end="")
|
||||
sys.stdout.flush()
|
||||
eedata = self.load_file_auto(self.opts.eeprom_image)
|
||||
eedata = self.load_file_auto(self.opts.eeprom_binary)
|
||||
if len(eedata) > ee_size:
|
||||
print("WARNING: eeprom_image truncated!", file=sys.stderr)
|
||||
print("WARNING: eeprom_binary truncated!", file=sys.stderr)
|
||||
eedata = eedata[0:ee_size]
|
||||
if len(bindata) < code_size:
|
||||
bindata += bytes(code_size - len(bindata))
|
||||
elif len(bindata) > code_size:
|
||||
print("WARNING: eeprom_image overlaps code_image!", file=sys.stderr)
|
||||
print("WARNING: eeprom_binary overlaps code_binary!", file=sys.stderr)
|
||||
bindata = bindata[0:code_size]
|
||||
bindata += eedata
|
||||
|
||||
@ -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,13 +131,9 @@ 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:
|
||||
if self.opts.code_binary:
|
||||
self.program_mcu()
|
||||
return 0
|
||||
else:
|
||||
@ -189,20 +166,18 @@ class StcGal:
|
||||
|
||||
def cli():
|
||||
# check arguments
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
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 = argparse.ArgumentParser(description="stcgal %s - an STC MCU ISP flash tool" %stcgal.__version__)
|
||||
parser.add_argument("code_binary", help="code segment binary file to flash", type=argparse.FileType("rb"), nargs='?')
|
||||
parser.add_argument("eeprom_binary", help="eeprom segment binary file to flash", type=argparse.FileType("rb"), nargs='?')
|
||||
parser.add_argument("-P", "--protocol", help="protocol version", choices=["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")
|
||||
opts = parser.parse_args()
|
||||
|
||||
|
||||
# run programmer
|
||||
gal = StcGal(opts)
|
||||
return gal.run()
|
||||
|
@ -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,7 +446,7 @@ class Stc15AOption(BaseOption):
|
||||
|
||||
class Stc15Option(BaseOption):
|
||||
def __init__(self, msr):
|
||||
assert len(msr) >= 4
|
||||
assert len(msr) == 4
|
||||
self.msr = bytearray(msr)
|
||||
|
||||
self.options = (
|
||||
@ -475,9 +467,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)
|
||||
|
||||
@ -614,18 +603,6 @@ class Stc15Option(BaseOption):
|
||||
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"""
|
||||
@ -642,8 +619,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 +631,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 +655,113 @@ 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):
|
||||
"""Send a sequence of 0x7f bytes for synchronization"""
|
||||
|
||||
while True:
|
||||
self.ser.write(b"\x7f")
|
||||
self.ser.flush()
|
||||
time.sleep(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, baudrate=self.baud_handshake,
|
||||
parity=self.PARITY)
|
||||
|
||||
# conservative timeout values
|
||||
self.ser.timeout = 10.0
|
||||
self.ser.interCharTimeout = 1.0
|
||||
|
||||
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")
|
||||
|
||||
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 +801,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 +887,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 +1017,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 +1065,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 +1157,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.
|
||||
|
||||
Reads a packet of data from the MCU and and do
|
||||
validity and checksum checks on it.
|
||||
|
||||
packet_csum, = struct.unpack(">H", packet[-3:-1])
|
||||
calc_csum = sum(packet[2:-3]) & 0xffff
|
||||
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 +1228,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]
|
||||
@ -1331,7 +1265,7 @@ class Stc12Protocol(StcBaseProtocol):
|
||||
delay = 0x80
|
||||
|
||||
return brt, brt_csum, iap_wait, delay
|
||||
|
||||
|
||||
def initialize_options(self, status_packet):
|
||||
"""Initialize options"""
|
||||
|
||||
@ -1500,6 +1434,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]
|
||||
@ -1588,7 +1524,7 @@ class Stc15AProtocol(Stc12Protocol):
|
||||
packet += bytes([0x98, 0x00, 0x02, 0x00])
|
||||
packet += bytes([0x98, 0x80, 0x02, 0x00])
|
||||
self.write_packet(packet)
|
||||
self.pulse(timeout=1.0)
|
||||
self.pulse()
|
||||
response = self.read_packet()
|
||||
if response[0] != 0x65:
|
||||
raise StcProtocolException("incorrect magic in handshake packet")
|
||||
@ -1630,7 +1566,7 @@ class Stc15AProtocol(Stc12Protocol):
|
||||
packet += struct.pack(">H", target_trim_start + i)
|
||||
packet += bytes([0x02, 0x00])
|
||||
self.write_packet(packet)
|
||||
self.pulse(timeout=1.0)
|
||||
self.pulse()
|
||||
response = self.read_packet()
|
||||
if response[0] != 0x65:
|
||||
raise StcProtocolException("incorrect magic in handshake packet")
|
||||
@ -1679,7 +1615,6 @@ class Stc15AProtocol(Stc12Protocol):
|
||||
|
||||
print("Target UID: %s" % Utils.hexstr(self.uid))
|
||||
|
||||
|
||||
class Stc15Protocol(Stc15AProtocol):
|
||||
"""Protocol handler for later STC 15 series"""
|
||||
|
||||
@ -1692,12 +1627,14 @@ class Stc15Protocol(Stc15AProtocol):
|
||||
"""Initialize options"""
|
||||
|
||||
# create option state
|
||||
self.options = Stc15Option(status_packet[5:8] + status_packet[12:13] + status_packet[37:38])
|
||||
self.options = Stc15Option(status_packet[5:8] + status_packet[12:13])
|
||||
self.options.print()
|
||||
|
||||
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
|
||||
@ -1794,7 +1731,8 @@ class Stc15Protocol(Stc15AProtocol):
|
||||
packet += bytes([0x00, 0x40, 0x80, 0x40, 0xff, 0x40])
|
||||
packet += bytes([0x00, 0x00, 0x80, 0x00, 0xc0, 0x00])
|
||||
self.write_packet(packet)
|
||||
self.pulse(b"\xfe", timeout=1.0)
|
||||
self.ser.write(bytes([0x92, 0x92, 0x92, 0x92]))
|
||||
self.ser.flush()
|
||||
response = self.read_packet()
|
||||
if response[0] != 0x00:
|
||||
raise StcProtocolException("incorrect magic in handshake packet")
|
||||
@ -1813,7 +1751,8 @@ class Stc15Protocol(Stc15AProtocol):
|
||||
for i in range(prog_trim[0] - 3, prog_trim[0] + 3):
|
||||
packet += bytes([i & 0xff, prog_trim[1]])
|
||||
self.write_packet(packet)
|
||||
self.pulse(b"\xfe", timeout=1.0)
|
||||
self.ser.write(bytes([0x92, 0x92, 0x92, 0x92]))
|
||||
self.ser.flush()
|
||||
response = self.read_packet()
|
||||
if response[0] != 0x00:
|
||||
raise StcProtocolException("incorrect magic in handshake packet")
|
||||
@ -1884,8 +1823,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")
|
||||
|
||||
@ -1943,14 +1880,17 @@ class Stc15Protocol(Stc15AProtocol):
|
||||
response = self.read_packet()
|
||||
if response[0] != 0x07 or response[1] != 0x54:
|
||||
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."""
|
||||
print(" done")
|
||||
|
||||
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,
|
||||
@ -1960,24 +1900,9 @@ class Stc15Protocol(Stc15AProtocol):
|
||||
(self.trim_frequency >> 0) & 0xff,
|
||||
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([0xff] * 27)
|
||||
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 +1912,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