1 Commits

Author SHA1 Message Date
af153a89e7 Fix initialization with CH340 UARTs
Initialization is messed up with older Linux kernels and that
results in 9600 baud being used unconditionally. Setting the baud
rate separately seems to work around this successfully.
2015-12-15 16:43:37 +01:00
55 changed files with 1390 additions and 3350 deletions

7
.gitignore vendored
View File

@ -1,12 +1,7 @@
*~
*.pyc
*.egg-info
*.eggs/
*.pybuild/
__pycache__/
__pycache__
/build
/dist
/deb_dist
/debian/stcgal*
/debian/files
/.vscode

View File

@ -1,33 +0,0 @@
sudo: required
dist: trusty
language: python
cache:
- pip
python:
- "3.4"
- "3.5"
- "3.6"
- "pypy3"
before_install:
- sudo apt install rpm dpkg-dev debhelper dh-python python3-setuptools fakeroot python3-serial python3-yaml
install:
- pip install pyserial pyusb tqdm
script:
- python setup.py build
- python setup.py test
before_deploy:
- deactivate
- python3 setup.py bdist_rpm
- dpkg-buildpackage -uc -us
- cp ../*.deb dist/
deploy:
provider: releases
api_key: $GH_TOKEN
file_glob: true
file:
- dist/stcgal*_all.deb
- dist/stcgal*.noarch.rpm
skip_cleanup: true
on:
tags: true
python: "3.4"

245
README.md
View File

@ -1,47 +1,248 @@
[![Build Status](https://travis-ci.org/grigorig/stcgal.svg)](https://travis-ci.org/grigorig/stcgal)
stcgal - STC MCU ISP flash tool
===============================
stcgal is a command line flash programming tool for [STC MCU Ltd](http://stcmcu.com/).
8051 compatible microcontrollers.
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/
Supported MCU models
--------------------
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)
* STC12C2052AD (BSL version: 5.8D)
* STC12C5A60S2 (BSL version: 6.2I)
* STC11F02E (BSL version: 6.5K)
* STC11F08XE (BSL version: 6.5M)
* STC15F104E (BSL version: 6.7Q)
* STC15F204EA (BSL version: 6.7R)
* 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)
More compatibility testing is going to happen soon.
Features
--------
* Support for STC 89/90/10/11/12/15/8 series
* UART and USB BSL support
* Display part info
* Determine operating frequency
* Program flash memory
* Program IAP/EEPROM
* Set device options
* Read unique device ID (STC 10/11/12/15/8)
* Trim RC oscillator frequency (STC 15/8)
* Automatic power-cycling with DTR toggle or a custom shell command
* Automatic UART protocol detection
* Read unique device ID (STC 10/11/12/15)
* Trim RC oscillator frequency (STC 15)
Further information
-------------------
Installation
------------
[Installation](doc/INSTALL.md)
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```
to install stcgal. A permanent installation provides the ```stcgal```
command.
[How to use stcgal](doc/USAGE.md)
Usage
-----
[Frequently Asked Questions](doc/FAQ.md)
Call stcgal with ```-h``` for usage information.
[List of tested MCU models](doc/MODELS.md)
```
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
positional arguments:
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
-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: 1200)
-o OPTION, --option OPTION
set option (can be used multiple times)
-t TRIM, --trim TRIM RC oscillator frequency in kHz (STC15 series only)
-D, --debug enable debug output
```
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 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
* ```stc15a``` STC15x104E and STC15x204E(A) series
* ```stc15``` Most STC15 series
The text files in the doc/ subdirectory provide an overview over
the reverse engineered protocols used by the BSLs. For more details,
please read the source code.
### Getting MCU information
Call stcgal without any file to program. It will dump information
about the MCU, e.g.:
```
$ ./stcgal.py -P stc15
Waiting for MCU, please cycle power: done
Target model:
Name: IAP15F2K61S2
Magic: F449
Code flash: 61.0 KB
EEPROM flash: 0.0 KB
Target frequency: 10.046 MHz
Target BSL version: 7.1S
Target wakeup frequency: 34.771 KHz
Target options:
reset_pin_enabled=False
clock_source=internal
clock_gain=high
watchdog_por_enabled=False
watchdog_stop_idle=True
watchdog_prescale=256
low_voltage_reset=True
low_voltage_threshold=3
eeprom_lvd_inhibit=True
eeprom_erase_enabled=False
bsl_pindetect_enabled=False
por_reset_delay=long
rstout_por_state=high
uart2_passthrough=False
uart2_pin_mode=normal
Disconnected!
```
### Program the flash memory
stcgal supports Intel HEX encoded files as well as binary files. Intel
HEX is autodetected by file extension (.hex, .ihx or .ihex).
Call stcgal just like before, but provide the path to the code image:
```
$ ./stcgal.py -P stc15 hello.hex
Waiting for MCU, please cycle power: done
Target model:
Name: IAP15F2K61S2
Magic: F449
Code flash: 61.0 KB
EEPROM flash: 0.0 KB
Target frequency: 10.046 MHz
Target BSL version: 7.1S
Target wakeup frequency: 34.771 KHz
Target options:
reset_pin_enabled=False
clock_source=internal
clock_gain=high
watchdog_por_enabled=False
watchdog_stop_idle=True
watchdog_prescale=256
low_voltage_reset=True
low_voltage_threshold=3
eeprom_lvd_inhibit=True
eeprom_erase_enabled=False
bsl_pindetect_enabled=False
por_reset_delay=long
rstout_por_state=high
uart2_passthrough=False
uart2_pin_mode=normal
Loading flash: 80 bytes (Intel HEX)
Trimming frequency: 10.046 MHz
Switching to 19200 baud: done
Erasing flash: done
Writing 256 bytes: .... done
Setting options: done
Target UID: 0D000021022632
Disconnected!
```
You can also program the EEPROM part of the memory, if applicable. Add
the EEPROM image path to the commandline after the flash image path.
stcgal uses a conservative baud rate of 19200 bps by
default. Programming can be sped up by choosing a faster baud rate
with the flag ```-b```.
### Device options
stcgal dumps a number of target options. These can be modified as
well. Provide one (or more) ```-o``` flags followed by a key-value
pair on the commandline to adjust these settings. For instance, you can
enable the external crystal as clock source:
```
$ ./stcgal.py -P stc15 -o clock_source=external hello.bin
```
Please note that device options can only be set when flash memory is
programmed!
#### Option keys
Not all parts support all options. The protocols or parts that support each option are listed in the description.
Option key | Possible values | Protocols/Models | Description
------------------------------|-------------------|---------------------|------------
```cpu_6t_enabled``` | true/false | STC89 only | 6T fast mode
```bsl_pindetect_enabled``` | true/false | All | BSL only enabled when P3.2/P3.3 or P1.0/P1.1 (depends on model) are low
```eeprom_erase_enabled``` | true/false | All | Erase EEPROM with next programming cycle
```clock_gain``` | low/high | All with XTAL pins | Clock gain for external crystal
```ale_enabled``` | true/false | STC89 only | ALE pin enabled if true, normal GPIO if false
```xram_enabled``` | true/false | STC89 only | Use internal XRAM (STC89 only)
```watchdog_por_enabled``` | true/false | All | Watchdog state after power-on reset (POR)
```low_voltage_reset ``` | true/false | STC12A+ | Low-voltage reset (brownout)
```clock_source``` | internal/external | STC12A+ with XTAL | Use internal (RC) or external (crystal) clock
```watchdog_stop_idle``` | true/false | STC12A+ | Stop watchdog in IDLE mode
```watchdog_prescale``` | 2,4,8,...,256 | STC12A+ | Watchdog timer prescaler, must be a power of two.
```reset_pin_enabled``` | true/false | STC12+ | RESET pin enabled if true, normal GPIO if false
```oscillator_stable_delay``` | 4096,...,32768 | STC11F series only | Crystal stabilization delay in clocks. Must be a power of two.
```por_reset_delay``` | short/long | STC12+ | Power-on reset (POR) delay
```low_voltage_threshold``` | 0...7 | STC15A+ | Low-voltage detection threshold. Model specific.
```eeprom_lvd_inhibit``` | true/false | STC15A+ | Ignore EEPROM writes in low-voltage situations
```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
If the internal RC oscillator is used (```clock_source=internal```),
stcgal can execute a trim procedure to adjust it to a given value. This
is only supported by STC15 series. The trim values are stored with
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.
License
-------

10
TODO.md Normal file
View File

@ -0,0 +1,10 @@
TODO
====
- some more documentation / comments
- private member naming, other style issues
- sensible default serial port (e.g. on windows)
- automatic protocol detection
- verify stc12a/stc12 options (e.g. low_voltage_threshold)
- also verify low_voltage_threshold on stc15
- check if stc15 handles 64 byte blocks correctly

19
debian/changelog vendored
View File

@ -1,22 +1,3 @@
stcgal (1.4) unstable; urgency=low
* Update to 1.4
-- Grigori <greg@chown.ath.cx> Tue, 19 Sep 2017 17:57:11 +0200
stcgal (1.3) unstable; urgency=low
* Update to 1.3
-- Grigori Goronzy <greg@chown.ath.cx> Sat, 10 Jun 2017 10:01:07 +0200
stcgal (1.2) unstable; urgency=low
* Update to 1.2
* Add optional python3-usb dependency
-- Grigori Goronzy <greg@chown.ath.cx> Fri, 20 May 2016 03:21:25 +0200
stcgal (1.0git) unstable; urgency=low
* Initial Debianized Release

22
debian/control vendored
View File

@ -2,25 +2,25 @@ Source: stcgal
Section: electronics
Priority: optional
Maintainer: Andrew Andrianov <andrew@ncrmnt.org>
Build-Depends: debhelper (>= 9), python3, python3-setuptools, dh-python, python3-serial, python3-tqdm, python3-yaml
Build-Depends: debhelper (>= 9), python3, python3-setuptools, dh-python
Standards-Version: 3.9.5
Homepage: https://github.com/grigorig/stcgal
X-Python3-Version: >= 3.2
Package: stcgal
Architecture: all
Depends: ${misc:Depends}, python3, python3-serial, python3-tqdm
Recommends: python3-usb (>= 1.0.0~b2)
Depends: ${misc:Depends}, python3, python3-serial
Description: STC MCU ISP flash tool
stcgal is a command line flash programming tool for STC MCU Ltd.
8051 compatible microcontrollers. The name was inspired by avrdude.
stcgal is a command line flash programming tool for STC MCU Ltd. 8051
compatible microcontrollers. The name was inspired by avrdude.
.
STC microcontrollers have an UART/USB 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
options. Unfortunately, this protocol is not publicly documented and
STC only provide a (crude) Windows GUI application for programming.
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 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

View File

@ -1,68 +0,0 @@
Frequently Asked Questions
==========================
### Is it possible to read code (or EEPROM) memory out of a chip?
By design, this is not possible with STC's bootloader protocols. This is considered a security feature by STC. There is no known workaround at this time. See issue #7 for more details and discussion.
### Which serial interfaces have been tested with stcgal?
The following USB-based UART interface chips have been successfully tested with stcgal:
* FT232 family (OS: Linux, Windows)
* CH340/CH341 (OS: Windows, Linux requires Kernel 4.10)
* PL2303 (OS: Windows, Linux)
* CP2102 (OS: Windows, Linux, macOS)
Interfaces that are known to not work:
* Raspberry Pi Mini UART (lacks parity support, enable the PL011 UART instead)
In general, stcgal requires accurate baud rate timings and parity support.
### stcgal fails to recognize the MCU and is stuck at "Waiting for MCU"
There are a number of issues that can result in this symptom:
* Electrical issues and wrong connections. Make sure that RX/TX, GND and VCC are connected correctly. If you do not use the autoreset feature, also make sure to connect power only after stcgal starts, as the bootloader is only invoked on power-on reset.
* Parasitic powering through I/O pins. The MCU can be powered through I/O pins (such as RX/TX) even if VCC is not connected. In this case, the power-on reset logic does not work. See next question.
* Serial interface incompatibilities. Some USB-based UARTs have bad compatibility with STC MCUs for various reasons. You can try to lower the handshake baudrate from the standard 2400 baud to 1200 baud with the option `-l 1200`, which works around these issues in some cases.
### How can I avoid parasitic powering?
Various remedies are possible to avoid parasitic powering.
* You can try to connect a resistor (< 1k) between MCU VCC and GND to short-circuit injected power and hopefully drop the voltage below the brown-out value.
* Another option is to insert series resistor on I/O lines that might inject power. Try a value like 1k on the RX/TX lines, for instance.
* Yet another possibility is to switch GND instead of VCC. This should be a fairly reliable solution in most cases.
### RC frequency trimming fails
First, make sure that the frequency specified uses the correct unit. The frequency is specified in kHz and the safe range is approximately 5000 kHz - 30000 kHz. Furthermore, frequency trimming uses the UART clock as the clock reference, so UART incompatibilities or clock inaccuracies can also result in issues with frequency trimming. If possible, try another UART chip.
### Baud rate switching fails
This can especially happen at high programming baud rates, e.g. 115200 baud. Try a lower baudrate, or stick to the default of 19200 baud. Some USB UARTs are known to cause problems due to inaccurate timing as well, which can lead to various issues.
### How can I use the autoreset feature?
The standard autoreset feature works somewhat similarly to Arduino. DTR is an active low signal, and is asserted on startup of stcgal for 500 ms and then deasserted for the rest of the programming sequence. On a standard USB UART, this results in 500 ms low pulse, followed by a high phase. The stcgal author recommends the following circuit:
```
VCC --o o-- MCU GND
| |
.-. |
| | 1k |
| | |
'_' |
| |
| ||-+
DTR --o --||<- BS170/BSS138
||-| (N-CH MOSFET)
|
|
GND ---------o
```
This circuit uses an N-channel MOSFET as a low-side switch to switch the MCU's GND. VCC is directly connected. This avoids parasitic powering issues. The pull-up resistor ensures that the MCU is switched on when the DTR input is floating.

View File

@ -1,10 +0,0 @@
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
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```
to install stcgal. A permanent installation provides the ```stcgal```
command.

View File

@ -1,32 +0,0 @@
Supported MCU models
====================
stcgal should fully support STC 89/90/10/11/12/15 series MCUs. Support for STC8 series MCUs is work in progress.
So far, stcgal was tested with the following MCU models:
* STC89C52RC (BSL version: 4.3C/6.6C)
* 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/7.1I)
* 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)
* IAP15L2K61S2 (BSL version: 7.2.5S)
* STC15W408AS (BSL version: 7.2.4T)
* STC15W4K56S4 (BSL version: 7.3.4T, UART and USB mode)
* STC8A8K64S4A12 (BSL version: 7.3.9U)
* STC8F2K08S2 (BSL version: 7.3.10U)
Compatibility reports, both negative and positive, are welcome.

View File

@ -1,239 +0,0 @@
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]
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)
optional arguments:
-h, --help show this help message and exit
-a, --autoreset cycle power automatically by asserting DTR
-r RESETCMD, --resetcmd RESETCMD
Use this shell command for board power-cycling
(instead of DTR assertion)
-P {stc89,stc12a,stc12,stc15a,stc15,auto}, --protocol {stc89,stc12a,stc12,stc15a,stc15,auto}
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)
-o OPTION, --option OPTION
set option (can be used multiple times)
-t TRIM, --trim TRIM RC oscillator frequency in kHz (STC15 series only)
-D, --debug enable debug output
```
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. By default
UART protocol autodetection is used. The mapping between protocols
and MCU series is as follows:
* ```stc89``` STC89/90 series
* ```stc12a``` STC12x052 series and possibly others
* ```stc12b``` STC12x52 series, STC12x56 series and possibly others
* ```stc12``` Most STC10/11/12 series
* ```stc15a``` STC15x104E and STC15x204E(A) series
* ```stc15``` Most STC15 series
* ```stc8``` STC8 series
* ```usb15``` USB support on STC15W4 series
* ```auto``` Automatic detection of UART based protocols (default)
The text files in the doc/ subdirectory provide an overview over
the reverse engineered protocols used by the BSLs. For more details,
please read the source code.
### Getting MCU information
Call stcgal without any file to program. It will dump information
about the MCU, e.g.:
```
$ ./stcgal.py -P stc15
Waiting for MCU, please cycle power: done
Target model:
Name: IAP15F2K61S2
Magic: F449
Code flash: 61.0 KB
EEPROM flash: 0.0 KB
Target frequency: 10.046 MHz
Target BSL version: 7.1S
Target wakeup frequency: 34.771 KHz
Target options:
reset_pin_enabled=False
clock_source=internal
clock_gain=high
watchdog_por_enabled=False
watchdog_stop_idle=True
watchdog_prescale=256
low_voltage_reset=True
low_voltage_threshold=3
eeprom_lvd_inhibit=True
eeprom_erase_enabled=False
bsl_pindetect_enabled=False
por_reset_delay=long
rstout_por_state=high
uart2_passthrough=False
uart2_pin_mode=normal
Disconnected!
```
### Program the flash memory
stcgal supports Intel HEX encoded files as well as binary files. Intel
HEX is autodetected by file extension (.hex, .ihx or .ihex).
Call stcgal just like before, but provide the path to the code image:
```
$ ./stcgal.py -P stc15 hello.hex
Waiting for MCU, please cycle power: done
Target model:
Name: IAP15F2K61S2
Magic: F449
Code flash: 61.0 KB
EEPROM flash: 0.0 KB
Target frequency: 10.046 MHz
Target BSL version: 7.1S
Target wakeup frequency: 34.771 KHz
Target options:
reset_pin_enabled=False
clock_source=internal
clock_gain=high
watchdog_por_enabled=False
watchdog_stop_idle=True
watchdog_prescale=256
low_voltage_reset=True
low_voltage_threshold=3
eeprom_lvd_inhibit=True
eeprom_erase_enabled=False
bsl_pindetect_enabled=False
por_reset_delay=long
rstout_por_state=high
uart2_passthrough=False
uart2_pin_mode=normal
Loading flash: 80 bytes (Intel HEX)
Trimming frequency: 10.046 MHz
Switching to 19200 baud: done
Erasing flash: done
Writing 256 bytes: .... done
Setting options: done
Target UID: 0D000021022632
Disconnected!
```
You can also program the EEPROM part of the memory, if applicable. Add
the EEPROM image path to the commandline after the flash image path.
stcgal uses a conservative baud rate of 19200 bps by
default. Programming can be sped up by choosing a faster baud rate
with the flag ```-b```.
### Device options
stcgal dumps a number of target options. These can be modified as
well. Provide one (or more) ```-o``` flags followed by a key-value
pair on the commandline to adjust these settings. For instance, you can
enable the external crystal as clock source:
```
$ ./stcgal.py -P stc15 -o clock_source=external hello.bin
```
Please note that device options can only be set when flash memory is
programmed!
#### Option keys
Not all parts support all options. The protocols or parts that support each option are listed in the description.
Option key | Possible values | Protocols/Models | Description
------------------------------|-------------------|---------------------|------------
```cpu_6t_enabled``` | true/false | STC89 only | 6T fast mode
```bsl_pindetect_enabled``` | true/false | All | BSL only enabled when P3.2/P3.3 or P1.0/P1.1 (depends on model) are low
```eeprom_erase_enabled``` | true/false | All | Erase EEPROM with next programming cycle
```clock_gain``` | low/high | All with XTAL pins | Clock gain for external crystal
```ale_enabled``` | true/false | STC89 only | ALE pin enabled if true, normal GPIO if false
```xram_enabled``` | true/false | STC89 only | Use internal XRAM (STC89 only)
```watchdog_por_enabled``` | true/false | All | Watchdog state after power-on reset (POR)
```low_voltage_reset``` | low/high | STC12A/STC12 | Low-voltage reset level (low: ~3.3V, high: ~3.7V)
```low_voltage_reset``` | true/false | STC12 | Enable RESET2 pin low voltage detect
```low_voltage_reset``` | true/false | STC15A | Enable low-voltage reset (brownout)
```clock_source``` | internal/external | STC12A+ with XTAL | Use internal (RC) or external (crystal) clock
```watchdog_stop_idle``` | true/false | STC12A+ | Stop watchdog in IDLE mode
```watchdog_prescale``` | 2,4,8,...,256 | STC12A+ | Watchdog timer prescaler, must be a power of two.
```reset_pin_enabled``` | true/false | STC12+ | RESET pin enabled if true, normal GPIO if false
```oscillator_stable_delay``` | 4096,...,32768 | STC11F series only | Crystal stabilization delay in clocks. Must be a power of two.
```por_reset_delay``` | short/long | STC12+ | Power-on reset (POR) delay
```low_voltage_threshold``` | 0...7 | STC15A+ | Low-voltage detection threshold. Model specific.
```eeprom_lvd_inhibit``` | true/false | STC15A+ | Ignore EEPROM writes in low-voltage situations
```rstout_por_state``` | low/high | STC15+ | RSTOUT/RSTSV pin state after power-on reset
```uart1_remap``` | true/false | STC8 | Remap UART1 pins (P3.0/P3.1) to UART2 pins (P3.6/P3.7)
```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)
```epwm_open_drain``` | true/false | STC8 | Use open-drain pin mode for EPWM pins after power-on reset
```program_eeprom_split``` | 512 - 65024 | STC8A8 w/ 64 KB | Select split between code flash and EEPROM flash (in 512 byte blocks)
### Frequency trimming
If the internal RC oscillator is used (```clock_source=internal```),
stcgal can execute a trim procedure to adjust it to a given value. This
is only supported by STC15 series and newer. The trim values are stored
with 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.
As an alternative to DTR, you can use a custom shell command or an external
script (via -r option) to reset the device. You should specify the command
along with -a option. Do not forget the quotes!
Example:
```
$ ./stcgal.py -P stc15 -a -r "echo 1 > /sys/class/gpio/gpio666/value"
```
or
```
$ ./stcgal.py -P stc15 -a -r "./powercycle.sh"
```
### 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.

View File

@ -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.86O.exe, sha1sum f70e317d758ef8c942613a8b0540147d7170589b
# Offsets are for STC-ISP 6.85I, sha1sum a1a625d6c491fe98d0286ebac0a8d78b94dca81d
MCU_TABLE_OFFSET = 0x0006ac80
MCU_TABLE_SIZE = 984
MCU_TABLE_OFFSET = 0x00063550
MCU_TABLE_SIZE = 914
MCU_RECORD_SIZE = 32
MCU_NAMES_OFFSET = 0x00087810
MCU_NAMES_PTR_OFFSET = 0x00487810
MCU_NAMES_OFFSET = 0x0007d708
MCU_NAMES_PTR_OFFSET = 0x0047d708
import struct
import sys
@ -25,12 +25,12 @@ for i in range(MCU_TABLE_SIZE):
inp.seek(mcu_name_offset)
name_str = inp.read(16).split(b'\00')[0].decode("ascii")
# TODO: With some MCUs, the amount of available EEPROM depends on the BSL version.
# Generally, newer BSLs free up a KB of additional EEPROM. Currently, always the
# maximum amount (with newer BSL) is reported.
# XXX: 1 KB are reserved one *some* MCUs for some reason
#if ee_size > 0 and not name_str.startswith("IAP"):
# ee_size -= 1024
# STC12x54xx always have 12 KB eeprom
if name_str.startswith("STC12C54") or name_str.startswith("STC12LE54"):
# STC12C54xx always have 12 KB eeprom
if name_str.startswith("STC12C54"):
ee_size = 12 * 1024
print("MCUModel(name='%s', magic=0x%02x%02x, total=%d, code=%d, eeprom=%d)," %

View File

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

View File

@ -1,71 +0,0 @@
MCS bytes
=========
46 b9 6a 00 33 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 ff 01 31 20 80 34 00 01 ff ff ff ff ff 8b bf
^^^^^^^^^^^ ^^ ^^ ^^ ^^
frequency clkdiv 5) 1) 3)
^^^^^
trim?
f7 fe 1f cc 16
^^ ^^
4) 2)
1) not stricty related to some register
aka MCS1
bit 0: ? always 1
bit 1: oscillator high gain
bit 2: EPWM push-pull enabled
bit 3: p2.0 state after boot
bit 4: TXD signal source from RXD
bit 5: p3.7 push-pull enabled
bit 6: UART1 remap enabled
bit 7: long power-on reset delay
2) not strictly related to some register
aka MCS4
eeprom size / code space upper limit (in pages)
only seems to apply to devices with max. flash size
e.g. fe -> 63.5K, e0 -> 56K
3) like RSTCFG? inverted?
aka MCS2
bit 0: LVD0
bit 1: LVD1
bit 2: ? always 1
bit 3: ? always 1
bit 4: ~reset pin enabled
bit 5: ? always 1
bit 6: ~enable lvd reset
bit 7: ? always 1
LVD:
2.20V -> 0xbf
2.40V -> 0xbe
2.70V -> 0xbd
3.00V -> 0xbc
4) like WDT_CONTR
aka MCS3
bit 0: WDPS0
bit 1: WDPS1
bit 2: WDPS2
bit 3: ~stop wdt in idle
bit 4: ? always 1
bit 5: ~enable wdt on por
bit 6: ? always 1
bit 7: ? always 1
WDPS like in datasheet
5)
aka MCS0
bit 0: ? ~BSLD / bootloader enabled
bit 1: erase eeprom enabled
bit 2: ?
bit 3: ?
bit 4: ?
bit 5: ?
bit 6: ?
bit 7: ?

View File

@ -1,138 +0,0 @@
Overview of changes
-------------------
The following changes have been observed compared to STC15:
- Many differences in the status packet
- At least some differences in MCS
- Different challenge
- no separate program speed
- clock division was introduced; calibration always in the ~20-30 MHz range, lower clocks
use division
- the meaning of the calibration ranges and trim has changed
The good:
- Erase, Program, etc. operations are apparently unchanged. :)
Status packet
-------------
46 B9 68 00 30 50 00 54 62 58 5D 00 04 FF FD 8B BF FF 27 4A F7 FE 73 55 00 F6 28 09 85 E3 5F 80 07 20 20 20 01 00 00 FE 05 3A 17 05 25 91 FF 10 AE 16
^^^^^ wakeup clock ^^^^^ reference voltage
^^^^^^^^ mfg. date
Clock set to 20 MHz by STC-ISP (encoding is different compared to STC15):
46 B9 68 00 30 50 01 31 2E 90 38 01 01 FF FD 8B BF FF 27 35 F7 FE 73 55 00 F6 28 09 85 E3 5F 80 07 20 20 20 01 00 00 FE 05 3A 17 05 25 91 FF 10 54 16
46 B9 68 00 30 50 01 31 2E 90 38 01 01 FF FD 8B BF FF 27 3B F7 FE 73 55 00 F6 28 09 85 E3 5F 80 07 20 20 20 01 00 00 FE 05 3A 17 05 25 91 FF 10 5A 16
^^^^^ some 24 MHz reference or other clk measurement?
^^^^^ trim/adjust?
^^ clkdiv
^^^^^^^^^^^ clk
MCS bytes
46 B9 68 00 30 50 01 31 2E 90 38 01 01 FF FD 8B BF FF 27 35 F7 FE 73 55 00 F6 28 09 85 E3 5F 80 07 20 20 20 01 00 00 FE 05 3A 17 05 25 91 FF 10 54 16
^^^^^^^^ ^^^^^
Disconnect
----------
Uses FF command byte.
Basic challenge operation
-------------------------
Host sends a challenge of some kind, followed by 0xfe pulsing
46 B9 6A 00 0C 00 02 00 00 80 00 00 F8 16
Much simpler than in STC15
MCU sends back some response:
46 B9 68 00 0C 00 02 36 AD 4E 83 02 2A 16
Host now sends some longer challenge, followed by more pulses:
46 B9 6A 00 20 00 0C 7C 00 7C 01 7C 02 7C 03 7D 00 7D 01 7D 02 7D 03 7E 00 7E 01 7E 02 7E 03 06 84 16
MCU sends back some response:
46 B9 68 00 20 00 0C 4D C6 4D DB 4D E7 4D F3 4D F6 4E 0E 4E 11 4E 26 4E 26 4E 32 4E 41 4E 56 09 DC 16
Host now seems to initiate a baud switch or something like that
46 B9 6A 00 0E 01 00 00 FF CC 01 7C 80 03 41 16
MCU acknowlegdes it:
46 B9 68 00 07 01 00 70 16
Now the MCU switches to the new baud rate.
Challenges observed
-------------------
6 MHz:
46B96A0020000C 1400 1401 1402 1403 1500 1501 1502 1503 1600 1601 1602 1603 01A416
5.5 MHz:
46B96A0020000C 5C00 5C01 5C02 5C03 5D00 5D01 5D02 5D03 5E00 5E01 5E02 5E03 050416
11 MHz:
46B96A0020000C 5B00 5B01 5B02 5B03 5C00 5C01 5C02 5C03 5D00 5D01 5D02 5D03 04F816
20 MHz:
46B96A0020000C 3600 3601 3602 3603 3700 3701 3702 3703 3800 3801 3802 3803 033C16
24 MHz:
46B96A0020000C 7C00 7C01 7C02 7C03 7D00 7D01 7D02 7D03 7E00 7E01 7E02 7E03 068416
27 MHz:
46B96A0020000C B000 B001 B002 B003 B100 B101 B102 B103 B200 B201 B202 B203 08F416
Ranges vs trim value
--------------------
46 B9 6A 00 20 00 0C 00 00 80 00 FF 00 00 01 80 01 FF 01 00 02 80 02 FF 02 00 03 80 03 FF 03 06 A4 16
46 B9 68 00 20 00 0C 36 9B 4E 92 65 E4 36 CB 4E 7D 66 29 36 D1 4E 83 66 05 36 CB 4E C2 66 47 0A EA 16
first byte determines general trim value... range of ~16 to ~30 MHz, the second byte (00..03) is a fine adjustment.
Clock division?
---------------
5.5 MHz vs 11 Mhz: challenge is about the same. it's likely some kind of clock divider is used!
5.5 Mhz switch: 01 00 00 FF CC 01 5C 80 clkdiv = 4?
11 MHz switch: 01 00 00 FF CC 01 5B 80 clkdiv = 2?
22 MHz switch: 01 00 00 FF CC 01 5C 80 clkdiv = 1?
22 Mhz option packet: 0400005AA5FFFFFF00FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF01516D405D0201FFFDFFFFFF8BBFF7FE
11 MHz option packet: 0400005AA5FFFFFF00FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF00A8AF985D0102FFFDFFFFFF8BBFF7FE
5.5 MHz option packet: 0400005AA5FFFFFF00FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF005462585D0004FFFDFFFFFF8BBFF7FE
^^ clkdiv?
^^^^^^^^ clkspeed
Always 24 MHz for programming
-----------------------------
Calibration for anything but 24 Mhz (and around that) fails when switching baud. Another observation is that there is no
programming speed being calibrated anymore. This may suggest that a fixed speed is used for programming.
Adjusting BRT calculation to 24 MHz in the switch packet seems to work. So it is really using 24 MHz by default;
probably some pre-calibrated value.

View File

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

View File

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

View File

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

View File

@ -1,49 +1,19 @@
#!/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
with open("README.md", "r") as fh:
long_description = fh.read()
setup(
name = "stcgal",
version = stcgal.__version__,
packages = find_packages(exclude=["doc", "tests"]),
packages = find_packages(exclude=["doc"]),
install_requires = ["pyserial"],
extras_require = {
"usb": ["pyusb>=1.0.0"]
},
entry_points = {
"console_scripts": [
"stcgal = stcgal.frontend:cli",
],
},
description = "STC MCU ISP flash tool",
long_description = long_description,
long_description_content_type = "text/markdown",
keywords = "stc mcu microcontroller 8051 mcs-51",
url = "https://github.com/grigorig/stcgal",
author = "Grigori Goronzy",
author_email = "greg@kinoho.net",
@ -58,12 +28,7 @@ setup(
"Operating System :: Microsoft :: Windows",
"Operating System :: MacOS",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Topic :: Software Development :: Embedded Systems",
"Topic :: Software Development",
],
test_suite = "tests",
tests_require = ["PyYAML"],
)

View File

@ -1 +1 @@
__version__ = "1.4"
__version__ = "1.0"

View File

@ -1,27 +0,0 @@
#
# Copyright (c) 2013-2015 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 sys
import stcgal.frontend
if __name__ == "__main__":
sys.exit(stcgal.frontend.cli())

View File

@ -20,22 +20,11 @@
# SOFTWARE.
#
import sys
import sys, os, time, struct
import argparse
import stcgal
import serial
from stcgal.utils import BaudType
from stcgal.protocols import Stc89Protocol
from stcgal.protocols import Stc12AProtocol
from stcgal.protocols import Stc12BProtocol
from stcgal.protocols import Stc12Protocol
from stcgal.protocols import Stc15Protocol
from stcgal.protocols import Stc15AProtocol
from stcgal.protocols import StcUsb15Protocol
from stcgal.protocols import Stc8Protocol
from stcgal.protocols import StcAutoProtocol
from stcgal.protocols import StcProtocolException
from stcgal.protocols import StcFramingException
from stcgal.utils import Utils, BaudType
from stcgal.protocols import *
from stcgal.ihex import IHex
class StcGal:
@ -43,44 +32,29 @@ class StcGal:
def __init__(self, opts):
self.opts = opts
self.initialize_protocol(opts)
def initialize_protocol(self, opts):
"""Initialize protocol backend"""
if opts.protocol == "stc89":
self.protocol = Stc89Protocol(opts.port, opts.handshake, opts.baud)
elif opts.protocol == "stc12a":
self.protocol = Stc12AProtocol(opts.port, opts.handshake, opts.baud)
elif opts.protocol == "stc12b":
self.protocol = Stc12BProtocol(opts.port, opts.handshake, opts.baud)
elif opts.protocol == "stc12":
self.protocol = Stc12Protocol(opts.port, opts.handshake, opts.baud)
elif opts.protocol == "stc15a":
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 == "stc8":
self.protocol = Stc8Protocol(opts.port, opts.handshake, opts.baud,
round(opts.trim * 1000))
elif opts.protocol == "usb15":
self.protocol = StcUsb15Protocol()
else:
self.protocol = StcAutoProtocol(opts.port, opts.handshake, opts.baud)
self.protocol.debug = opts.debug
def emit_options(self, options):
"""Set options from command line to protocol handler."""
for opt in options:
for o in options:
try:
kv = opt.split("=", 1)
if len(kv) < 2:
raise ValueError("incorrect format")
kv = o.split("=", 1)
if len(kv) < 2: raise ValueError("incorrect format")
self.protocol.set_option(kv[0], kv[1])
except ValueError as ex:
raise NameError("invalid option '%s' (%s)" % (kv[0], ex))
except ValueError as e:
raise NameError("invalid option '%s' (%s)" % (kv[0], e))
def load_file_auto(self, fileobj):
"""Load file with Intel Hex autodetection."""
@ -93,16 +67,14 @@ class StcGal:
binary = hexfile.extract_data()
print("%d bytes (Intel HEX)" %len(binary))
return binary
except ValueError as ex:
raise IOError("invalid Intel HEX file (%s)" %ex)
except ValueError as e:
raise IOError("invalid Intel HEX file (%s)" %e)
else:
binary = fileobj.read()
print("%d bytes (Binary)" %len(binary))
return binary
def program_mcu(self):
"""Execute the standard programming flow."""
code_size = self.protocol.model.code
ee_size = self.protocol.model.eeprom
@ -132,9 +104,9 @@ class StcGal:
bindata = bindata[0:code_size]
bindata += eedata
# pad to 512 byte boundary
if len(bindata) % 512:
bindata += b'\xff' * (512 - len(bindata) % 512)
# pad to 256 byte boundary
if len(bindata) % 256:
bindata += bytes(256 - len(bindata) % 256)
if self.opts.option: self.emit_options(self.opts.option)
@ -145,67 +117,49 @@ class StcGal:
self.protocol.disconnect()
def run(self):
"""Run programmer, main entry point."""
try:
self.protocol.connect(autoreset=self.opts.autoreset, resetcmd=self.opts.resetcmd)
if isinstance(self.protocol, StcAutoProtocol):
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.initialize_protocol(self.opts)
else:
base_protocol = None
self.protocol.initialize(base_protocol)
try: self.protocol.connect()
except KeyboardInterrupt:
sys.stdout.flush()
sys.stdout.flush();
print("interrupted")
return 2
except (StcFramingException, StcProtocolException) as ex:
sys.stdout.flush()
print("Protocol error: %s" % ex, file=sys.stderr)
except (StcFramingException, StcProtocolException) as e:
sys.stdout.flush();
print("Protocol error: %s" % e, file=sys.stderr)
self.protocol.disconnect()
return 1
except serial.SerialException as ex:
sys.stdout.flush()
print("Serial port error: %s" % ex, file=sys.stderr)
return 1
except IOError as ex:
sys.stdout.flush()
print("I/O error: %s" % ex, file=sys.stderr)
except serial.SerialException as e:
sys.stdout.flush();
print("Serial port error: %s" % e, file=sys.stderr)
return 1
try:
if self.opts.code_image:
self.program_mcu()
return 0
self.protocol.disconnect()
return 0
except NameError as ex:
sys.stdout.flush()
print("Option error: %s" % ex, file=sys.stderr)
else:
self.protocol.disconnect()
return 0
except NameError as e:
sys.stdout.flush();
print("Option error: %s" % e, file=sys.stderr)
self.protocol.disconnect()
return 1
except (StcFramingException, StcProtocolException) as ex:
sys.stdout.flush()
print("Protocol error: %s" % ex, file=sys.stderr)
except (StcFramingException, StcProtocolException) as e:
sys.stdout.flush();
print("Protocol error: %s" % e, file=sys.stderr)
self.protocol.disconnect()
return 1
except KeyboardInterrupt:
sys.stdout.flush()
sys.stdout.flush();
print("interrupted", file=sys.stderr)
self.protocol.disconnect()
return 2
except serial.SerialException as ex:
print("Serial port error: %s" % ex, file=sys.stderr)
except serial.SerialException as e:
print("Serial port error: %s" % e, file=sys.stderr)
return 1
except IOError as ex:
sys.stdout.flush()
print("I/O error: %s" % ex, file=sys.stderr)
except IOError as e:
sys.stdout.flush();
print("I/O error: %s" % e, file=sys.stderr)
self.protocol.disconnect()
return 1
@ -213,22 +167,18 @@ class StcGal:
def cli():
# check arguments
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
description="stcgal {} - an STC MCU ISP flash tool\n".format(stcgal.__version__) +
"(C) 2014-2017 Grigori Goronzy\nhttps://github.com/grigorig/stcgal")
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("-r", "--resetcmd", help="Use this shell command for board power-cycling (instead of DTR assertion)", action="store")
parser.add_argument("-P", "--protocol", help="protocol version (default: auto)",
choices=["stc89", "stc12a", "stc12b", "stc12", "stc15a", "stc15", "stc8", "usb15", "auto"], default="auto")
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()

View File

@ -5,213 +5,201 @@
import struct
import codecs
class IHex(object):
@classmethod
def read(cls, lines):
ihex = cls()
class IHex:
"""Intel HEX parser and writer"""
segbase = 0
for line in lines:
line = line.strip()
if not line: continue
@classmethod
def read(cls, lines):
"""Read Intel HEX data from string or lines"""
ihex = cls()
t, a, d = ihex.parse_line(line)
if t == 0x00:
ihex.insert_data(segbase + a, d)
segbase = 0
for line in lines:
line = line.strip()
if not line:
continue
elif t == 0x01:
break # Should we check for garbage after this?
t, a, d = ihex.parse_line(line)
if t == 0x00:
ihex.insert_data(segbase + a, d)
elif t == 0x02:
ihex.set_mode(16)
segbase = struct.unpack(">H", d[0:2])[0] << 4
elif t == 0x01:
break # Should we check for garbage after this?
elif t == 0x03:
ihex.set_mode(16)
elif t == 0x02:
ihex.set_mode(16)
segbase = struct.unpack(">H", d[0:2])[0] << 4
cs, ip = struct.unpack(">2H", d[0:2])
ihex.set_start((cs, ip))
elif t == 0x03:
ihex.set_mode(16)
elif t == 0x04:
ihex.set_mode(32)
segbase = struct.unpack(">H", d[0:2])[0] << 16
cs, ip = struct.unpack(">2H", d[0:2])
ihex.set_start((cs, ip))
elif t == 0x05:
ihex.set_mode(32)
ihex.set_start(struct.unpack(">I", d[0:4])[0])
elif t == 0x04:
ihex.set_mode(32)
segbase = struct.unpack(">H", d[0:2])[0] << 16
else:
raise ValueError("Invalid type byte")
elif t == 0x05:
ihex.set_mode(32)
ihex.set_start(struct.unpack(">I", d[0:4])[0])
return ihex
else:
raise ValueError("Invalid type byte")
@classmethod
def read_file(cls, fname):
f = open(fname, "rb")
ihex = cls.read(f)
f.close()
return ihex
return ihex
def __init__(self):
self.areas = {}
self.start = None
self.mode = 8
self.row_bytes = 16
@classmethod
def read_file(cls, fname):
"""Read Intel HEX data from file"""
f = open(fname, "rb")
ihex = cls.read(f)
f.close()
return ihex
def set_row_bytes(self, row_bytes):
"""Set output hex file row width (bytes represented per row)."""
if row_bytes < 1 or row_bytes > 0xff:
raise ValueError("Value out of range: (%r)" % row_bytes)
self.row_bytes = row_bytes
def extract_data(self, start=None, end=None):
if start is None:
start = 0
if end is None:
result = bytearray()
for addr, data in self.areas.items():
if addr >= start:
if len(result) < (addr - start):
result[len(result):addr-start] = bytes(addr-start-len(result))
result[addr-start:addr-start+len(data)] = data
return bytes(result)
else:
result = bytearray()
for addr, data in self.areas.items():
if addr >= start and addr < end:
data = data[:end-addr]
if len(result) < (addr - start):
result[len(result):addr-start] = bytes(addr-start-len(result))
result[addr-start:addr-start+len(data)] = data
return bytes(result)
def set_start(self, start=None):
self.start = start
def __init__(self):
self.areas = {}
self.start = None
self.mode = 8
self.row_bytes = 16
def set_mode(self, mode):
self.mode = mode
def set_row_bytes(self, row_bytes):
"""Set output hex file row width (bytes represented per row)."""
if row_bytes < 1 or row_bytes > 0xff:
raise ValueError("Value out of range: (%r)" % row_bytes)
self.row_bytes = row_bytes
def get_area(self, addr):
for start, data in self.areas.items():
end = start + len(data)
if addr >= start and addr <= end:
return start
def extract_data(self, start=None, end=None):
"""Extract binary data"""
if start is None:
start = 0
return None
if end is None:
result = bytearray()
def insert_data(self, istart, idata):
iend = istart + len(idata)
for addr, data in self.areas.items():
if addr >= start:
if len(result) < (addr - start):
result[len(result):addr - start] = bytes(
addr - start - len(result))
result[addr - start:addr - start + len(data)] = data
area = self.get_area(istart)
if area is None:
self.areas[istart] = idata
return bytes(result)
else:
data = self.areas[area]
# istart - iend + len(idata) + len(data)
self.areas[area] = data[:istart-area] + idata + data[iend-area:]
result = bytearray()
def calc_checksum(self, bytes):
total = sum(bytes)
return (-total) & 0xFF
for addr, data in self.areas.items():
if addr >= start and addr < end:
data = data[:end - addr]
if len(result) < (addr - start):
result[len(result):addr - start] = bytes(
addr - start - len(result))
result[addr - start:addr - start + len(data)] = data
def parse_line(self, rawline):
if rawline[0:1] != b":":
raise ValueError("Invalid line start character (%r)" % rawline[0])
return bytes(result)
try:
#line = rawline[1:].decode("hex")
line = codecs.decode(rawline[1:], "hex_codec")
except:
raise ValueError("Invalid hex data")
def set_start(self, start=None):
self.start = start
length, addr, type = struct.unpack(">BHB", line[:4])
def set_mode(self, mode):
self.mode = mode
dataend = length + 4
data = line[4:dataend]
def get_area(self, addr):
for start, data in self.areas.items():
end = start + len(data)
if addr >= start and addr <= end:
return start
#~ print line[dataend:dataend + 2], repr(line)
cs1 = line[dataend]
cs2 = self.calc_checksum(line[:dataend])
return None
if cs1 != cs2:
raise ValueError("Checksums do not match")
def insert_data(self, istart, idata):
iend = istart + len(idata)
return (type, addr, data)
area = self.get_area(istart)
if area is None:
self.areas[istart] = idata
def make_line(self, type, addr, data):
line = struct.pack(">BHB", len(data), addr, type)
line += data
line += chr(self.calc_checksum(line))
#~ return ":" + line.encode("hex")
return ":" + line.encode("hex").upper() + "\r\n"
else:
data = self.areas[area]
# istart - iend + len(idata) + len(data)
self.areas[area] = data[
:istart - area] + idata + data[iend - area:]
def write(self):
output = ""
for start, data in sorted(self.areas.items()):
i = 0
segbase = 0
def calc_checksum(self, data):
total = sum(data)
return (-total) & 0xFF
while i < len(data):
chunk = data[i:i + self.row_bytes]
def parse_line(self, rawline):
if rawline[0:1] != b":":
raise ValueError("Invalid line start character (%r)" % rawline[0])
addr = start
newsegbase = segbase
try:
line = codecs.decode(rawline[1:], "hex_codec")
except ValueError:
raise ValueError("Invalid hex data")
if self.mode == 8:
addr = addr & 0xFFFF
length, addr, line_type = struct.unpack(">BHB", line[:4])
elif self.mode == 16:
t = addr & 0xFFFF
newsegbase = (addr - t) >> 4
addr = t
dataend = length + 4
data = line[4:dataend]
if newsegbase != segbase:
output += self.make_line(0x02, 0, struct.pack(">H", newsegbase))
segbase = newsegbase
cs1 = line[dataend]
cs2 = self.calc_checksum(line[:dataend])
elif self.mode == 32:
newsegbase = addr >> 16
addr = addr & 0xFFFF
if cs1 != cs2:
raise ValueError("Checksums do not match")
if newsegbase != segbase:
output += self.make_line(0x04, 0, struct.pack(">H", newsegbase))
segbase = newsegbase
return (line_type, addr, data)
output += self.make_line(0x00, addr, chunk)
def make_line(self, line_type, addr, data):
line = struct.pack(">BHB", len(data), addr, line_type)
line += data
line += chr(self.calc_checksum(line))
return ":" + line.encode("hex").upper() + "\r\n"
i += self.row_bytes
start += self.row_bytes
def write(self):
"""Write Intel HEX data to string"""
output = ""
if self.start is not None:
if self.mode == 16:
output += self.make_line(0x03, 0, struct.pack(">2H", self.start[0], self.start[1]))
elif self.mode == 32:
output += self.make_line(0x05, 0, struct.pack(">I", self.start))
for start, data in sorted(self.areas.items()):
i = 0
segbase = 0
output += self.make_line(0x01, 0, "")
return output
while i < len(data):
chunk = data[i:i + self.row_bytes]
addr = start
newsegbase = segbase
if self.mode == 8:
addr = addr & 0xFFFF
elif self.mode == 16:
t = addr & 0xFFFF
newsegbase = (addr - t) >> 4
addr = t
if newsegbase != segbase:
output += self.make_line(
0x02, 0, struct.pack(">H", newsegbase))
segbase = newsegbase
elif self.mode == 32:
newsegbase = addr >> 16
addr = addr & 0xFFFF
if newsegbase != segbase:
output += self.make_line(
0x04, 0, struct.pack(">H", newsegbase))
segbase = newsegbase
output += self.make_line(0x00, addr, chunk)
i += self.row_bytes
start += self.row_bytes
if self.start is not None:
if self.mode == 16:
output += self.make_line(
0x03, 0, struct.pack(">2H", self.start[0], self.start[1]))
elif self.mode == 32:
output += self.make_line(
0x05, 0, struct.pack(">I", self.start))
output += self.make_line(0x01, 0, "")
return output
def write_file(self, fname):
"""Write Intel HEX data to file"""
f = open(fname, "w")
f.write(self.write())
f.close()
def write_file(self, fname):
f = open(fname, "w")
f.write(self.write())
f.close()

View File

@ -32,79 +32,14 @@ class MCUModelDatabase:
MCUModel = collections.namedtuple("MCUModel", ["name", "magic", "total", "code", "eeprom"])
models = (
MCUModel(name='STC8F1K02S2', magic=0xf661, total=20480, code=2048, eeprom=10240),
MCUModel(name='STC8F1K04S2', magic=0xf662, total=20480, code=4096, eeprom=8192),
MCUModel(name='STC8F1K06S2', magic=0xf663, total=20480, code=6144, eeprom=6144),
MCUModel(name='STC8F1K08S2', magic=0xf664, total=20480, code=8192, eeprom=4096),
MCUModel(name='STC8F1K10S2', magic=0xf665, total=20480, code=10240, eeprom=2048),
MCUModel(name='STC8F1K12S2', magic=0xf666, total=20480, code=12288, eeprom=0),
MCUModel(name='STC8F1K17S2', magic=0xf667, total=20480, code=17408, eeprom=0),
MCUModel(name='STC8F1K02', magic=0xf671, total=20480, code=2048, eeprom=10240),
MCUModel(name='STC8F1K04', magic=0xf672, total=20480, code=4096, eeprom=8192),
MCUModel(name='STC8F1K06', magic=0xf673, total=20480, code=6144, eeprom=6144),
MCUModel(name='STC8F1K08', magic=0xf674, total=20480, code=8192, eeprom=4096),
MCUModel(name='STC8F1K10', magic=0xf675, total=20480, code=10240, eeprom=2048),
MCUModel(name='STC8F1K12', magic=0xf676, total=20480, code=12288, eeprom=0),
MCUModel(name='STC8F1K17', magic=0xf677, total=20480, code=17408, eeprom=0),
MCUModel(name='STC15U4K16S4', magic=0xf580, total=65536, code=16384, eeprom=44032),
MCUModel(name='STC15U4K24S4', magic=0xf581, total=65536, code=24576, eeprom=35840),
MCUModel(name='STC15U4K32S4', magic=0xf582, total=65536, code=32768, eeprom=27648),
MCUModel(name='STC15U4K40S4', magic=0xf583, total=65536, code=40960, eeprom=19456),
MCUModel(name='STC15U4K48S4', magic=0xf584, total=65536, code=49152, eeprom=11264),
MCUModel(name='STC15U4K56S4', magic=0xf585, total=65536, code=57344, eeprom=3072),
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='STC8A8K60S4A12', magic=0xf629, total=65536, code=61440, eeprom=4096),
MCUModel(name='STC8A8K64S4A12', magic=0xf628, total=65536, code=65024, eeprom=512),
MCUModel(name='STC8A4K08S2A12', magic=0xf651, total=65536, code=8192, eeprom=57344),
MCUModel(name='STC8A4K16S2A12', magic=0xf652, total=65536, code=16384, eeprom=49152),
MCUModel(name='STC8A4K24S2A12', magic=0xf653, total=65536, code=24576, eeprom=40960),
MCUModel(name='STC8A4K32S2A12', magic=0xf654, total=65536, code=32768, eeprom=32768),
MCUModel(name='STC8A4K40S2A12', magic=0xf655, total=65536, code=40960, eeprom=24576),
MCUModel(name='STC8A4K48S2A12', magic=0xf656, total=65536, code=49152, eeprom=16384),
MCUModel(name='STC8A4K56S2A12', magic=0xf657, total=65536, code=57344, eeprom=8192),
MCUModel(name='STC8A4K60S2A12', magic=0xf659, total=65536, code=61440, eeprom=4096),
MCUModel(name='STC8A4K64S2A12', magic=0xf658, total=65536, code=65024, eeprom=512),
MCUModel(name='STC8F8K08S4A12', magic=0xf611, total=65536, code=8192, eeprom=57344),
MCUModel(name='STC8F8K16S4A12', magic=0xf612, total=65536, code=16384, eeprom=49152),
MCUModel(name='STC8F8K24S4A12', magic=0xf613, total=65536, code=24576, eeprom=40960),
MCUModel(name='STC8F8K32S4A12', magic=0xf614, total=65536, code=32768, eeprom=32768),
MCUModel(name='STC8F8K40S4A12', magic=0xf615, total=65536, code=40960, eeprom=24576),
MCUModel(name='STC8F8K48S4A12', magic=0xf616, total=65536, code=49152, eeprom=16384),
MCUModel(name='STC8F8K56S4A12', magic=0xf617, total=65536, code=57344, eeprom=8192),
MCUModel(name='STC8F8K60S4A12', magic=0xf619, total=65536, code=61440, eeprom=4096),
MCUModel(name='STC8F8K64S4A12', magic=0xf618, 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='STC8F2K60S4', magic=0xf639, total=65536, code=61440, eeprom=4096),
MCUModel(name='STC8F2K64S4', magic=0xf638, total=65536, code=65024, eeprom=512),
MCUModel(name='STC8F2K08S2', magic=0xf641, total=65536, code=8192, eeprom=57344),
MCUModel(name='STC8F2K16S2', magic=0xf642, total=65536, code=16384, eeprom=49152),
MCUModel(name='STC8F2K24S2', magic=0xf643, total=65536, code=24576, eeprom=40960),
MCUModel(name='STC8F2K32S2', magic=0xf644, total=65536, code=32768, eeprom=32768),
MCUModel(name='STC8F2K40S2', magic=0xf645, total=65536, code=40960, eeprom=24576),
MCUModel(name='STC8F2K48S2', magic=0xf646, total=65536, code=49152, eeprom=16384),
MCUModel(name='STC8F2K56S2', magic=0xf647, total=65536, code=57344, eeprom=8192),
MCUModel(name='STC8F2K60S2', magic=0xf649, total=65536, code=61440, eeprom=4096),
MCUModel(name='STC8F2K64S2', magic=0xf648, 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),
@ -263,7 +198,6 @@ class MCUModelDatabase:
MCUModel(name='STC15W412S', magic=0xf51c, total=16384, code=12288, eeprom=1024),
MCUModel(name='IAP15W413S', magic=0xf55d, total=16384, code=13312, eeprom=0),
MCUModel(name='IRC15W415S', magic=0xf55e, total=16384, code=15872, eeprom=0),
MCUModel(name='JX15W415S', magic=0xf55f, total=16384, code=15872, eeprom=0),
MCUModel(name='STC15W401AS', magic=0xf52a, total=16384, code=1024, eeprom=12288),
MCUModel(name='STC15W402AS', magic=0xf52b, total=16384, code=2048, eeprom=11264),
MCUModel(name='STC15W404AS', magic=0xf51e, total=16384, code=4096, eeprom=9216),
@ -275,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),
@ -289,7 +220,6 @@ class MCUModelDatabase:
MCUModel(name='STC15W4K48S4', magic=0xf527, total=65536, code=49152, eeprom=11264),
MCUModel(name='STC15W4K56S4', magic=0xf528, total=65536, code=57344, eeprom=3072),
MCUModel(name='IAP15W4K58S4', magic=0xf569, total=65536, code=59392, eeprom=0),
MCUModel(name='IAP15W4K58S4-Stu', magic=0xf56d, total=65536, code=59392, eeprom=0),
MCUModel(name='IAP15W4K61S4', magic=0xf56a, total=65536, code=62464, eeprom=0),
MCUModel(name='IRC15W4K63S4', magic=0xf56b, total=65536, code=65024, eeprom=0),
MCUModel(name='U8W', magic=0xf56c, total=65536, code=62464, eeprom=0),
@ -882,28 +812,28 @@ class MCUModelDatabase:
MCUModel(name='STC12C5420', magic=0xe014, total=32768, code=20480, eeprom=12288),
MCUModel(name='STC12C5424', magic=0xe018, total=32768, code=24576, eeprom=12288),
MCUModel(name='STC12C5428', magic=0xe01c, total=32768, code=28672, eeprom=12288),
MCUModel(name='STC12LE5401AD', magic=0xe0e1, total=32768, code=1024, eeprom=12288),
MCUModel(name='STC12LE5402AD', magic=0xe0e2, total=32768, code=2048, eeprom=12288),
MCUModel(name='STC12LE5404AD', magic=0xe0e4, total=32768, code=4096, eeprom=12288),
MCUModel(name='STC12LE5406AD', magic=0xe0e6, total=32768, code=6144, eeprom=12288),
MCUModel(name='STC12LE5408AD', magic=0xe0e8, total=32768, code=8192, eeprom=12288),
MCUModel(name='STC12LE5410AD', magic=0xe0ea, total=32768, code=10240, eeprom=12288),
MCUModel(name='STC12LE5412AD', magic=0xe0ec, total=32768, code=12288, eeprom=12288),
MCUModel(name='STC12LE5401AD', magic=0xe0e1, total=32768, code=1024, eeprom=22016),
MCUModel(name='STC12LE5402AD', magic=0xe0e2, total=32768, code=2048, eeprom=20992),
MCUModel(name='STC12LE5404AD', magic=0xe0e4, total=32768, code=4096, eeprom=18944),
MCUModel(name='STC12LE5406AD', magic=0xe0e6, total=32768, code=6144, eeprom=16896),
MCUModel(name='STC12LE5408AD', magic=0xe0e8, total=32768, code=8192, eeprom=10752),
MCUModel(name='STC12LE5410AD', magic=0xe0ea, total=32768, code=10240, eeprom=4608),
MCUModel(name='STC12LE5412AD', magic=0xe0ec, total=32768, code=12288, eeprom=11776),
MCUModel(name='STC12LE5416AD', magic=0xe0f0, total=32768, code=16384, eeprom=12288),
MCUModel(name='STC12LE5420AD', magic=0xe0f4, total=32768, code=20480, eeprom=12288),
MCUModel(name='STC12LE5424AD', magic=0xe0f8, total=32768, code=24576, eeprom=12288),
MCUModel(name='STC12LE5428AD', magic=0xe0fc, total=32768, code=28672, eeprom=12288),
MCUModel(name='STC12LE5401', magic=0xe081, total=32768, code=1024, eeprom=12288),
MCUModel(name='STC12LE5402', magic=0xe082, total=32768, code=2048, eeprom=12288),
MCUModel(name='STC12LE5404', magic=0xe084, total=32768, code=4096, eeprom=12288),
MCUModel(name='STC12LE5406', magic=0xe086, total=32768, code=6144, eeprom=12288),
MCUModel(name='STC12LE5408', magic=0xe088, total=32768, code=8192, eeprom=12288),
MCUModel(name='STC12LE5410', magic=0xe08a, total=32768, code=10240, eeprom=12288),
MCUModel(name='STC12LE5412', magic=0xe08c, total=32768, code=12288, eeprom=12288),
MCUModel(name='STC12LE5420AD', magic=0xe0f4, total=32768, code=20480, eeprom=8192),
MCUModel(name='STC12LE5424AD', magic=0xe0f8, total=32768, code=24576, eeprom=4096),
MCUModel(name='STC12LE5428AD', magic=0xe0fc, total=32768, code=28672, eeprom=0),
MCUModel(name='STC12LE5401', magic=0xe081, total=32768, code=1024, eeprom=22016),
MCUModel(name='STC12LE5402', magic=0xe082, total=32768, code=2048, eeprom=20992),
MCUModel(name='STC12LE5404', magic=0xe084, total=32768, code=4096, eeprom=18944),
MCUModel(name='STC12LE5406', magic=0xe086, total=32768, code=6144, eeprom=16896),
MCUModel(name='STC12LE5408', magic=0xe088, total=32768, code=8192, eeprom=10752),
MCUModel(name='STC12LE5410', magic=0xe08a, total=32768, code=10240, eeprom=4608),
MCUModel(name='STC12LE5412', magic=0xe08c, total=32768, code=12288, eeprom=11776),
MCUModel(name='STC12LE5416', magic=0xe090, total=32768, code=16384, eeprom=12288),
MCUModel(name='STC12LE5420', magic=0xe094, total=32768, code=20480, eeprom=12288),
MCUModel(name='STC12LE5424', magic=0xe098, total=32768, code=24576, eeprom=12288),
MCUModel(name='STC12LE5428', magic=0xe09c, total=32768, code=28672, eeprom=12288),
MCUModel(name='STC12LE5420', magic=0xe094, total=32768, code=20480, eeprom=8192),
MCUModel(name='STC12LE5424', magic=0xe098, total=32768, code=24576, eeprom=4096),
MCUModel(name='STC12LE5428', magic=0xe09c, total=32768, code=28672, eeprom=0),
MCUModel(name='STC12C1052AD', magic=0xf211, total=8192, code=1024, eeprom=5120),
MCUModel(name='STC12C2052AD', magic=0xf212, total=8192, code=2048, eeprom=4096),
MCUModel(name='STC12C3052AD', magic=0xf213, total=8192, code=3072, eeprom=3072),
@ -1016,47 +946,6 @@ class MCUModelDatabase:
MCUModel(name='STC90LE513AD', magic=0xf18d, total=65536, code=53248, eeprom=10240),
MCUModel(name='STC90LE514AD', magic=0xf18e, total=65536, code=57344, eeprom=6144),
MCUModel(name='STC90LE516AD', magic=0xf190, total=65536, code=63488, eeprom=0),
# Warning, these definitions lack a valid eeprom size.
# XXX: It's unknown whether these actually exist, they were removed in STC-ISP.
MCUModel(name='STC15F04AD', magic=0xd444, total=4096, code=4096, eeprom=0),
MCUModel(name='STC15F06AD', magic=0xd446, total=6144, code=6144, eeprom=0),
MCUModel(name='STC15F08AD', magic=0xd448, total=8192, code=8192, eeprom=0),
MCUModel(name='STC15F10AD', magic=0xd44a, total=10240, code=10240, eeprom=0),
MCUModel(name='STC15F12AD', magic=0xd44c, total=12288, code=12288, eeprom=0),
MCUModel(name='STC15F04CCP', magic=0xd434, total=4096, code=4096, eeprom=0),
MCUModel(name='STC15F06CCP', magic=0xd436, total=6144, code=6144, eeprom=0),
MCUModel(name='STC15F08CCP', magic=0xd438, total=8192, code=8192, eeprom=0),
MCUModel(name='STC15F10CCP', magic=0xd43a, total=10240, code=10240, eeprom=0),
MCUModel(name='STC15F12CCP', magic=0xd43c, total=12288, code=12288, eeprom=0),
MCUModel(name='STC15F04', magic=0xd404, total=4096, code=4096, eeprom=0),
MCUModel(name='STC15F06', magic=0xd406, total=6144, code=6144, eeprom=0),
MCUModel(name='STC15F08', magic=0xd408, total=8192, code=8192, eeprom=0),
MCUModel(name='STC15F10', magic=0xd40a, total=10240, code=10240, eeprom=0),
MCUModel(name='STC15F12', magic=0xd40c, total=12288, code=12288, eeprom=0),
MCUModel(name='IAP15F08AD', magic=0xd458, total=8192, code=8192, eeprom=0),
MCUModel(name='IAP15F10AD', magic=0xd45a, total=10240, code=10240, eeprom=0),
MCUModel(name='IAP15F12AD', magic=0xd45c, total=12288, code=12288, eeprom=0),
MCUModel(name='IAP15F14AD', magic=0xd45e, total=14336, code=14336, eeprom=0),
MCUModel(name='STC15L04AD', magic=0xd4c4, total=4096, code=4096, eeprom=0),
MCUModel(name='STC15L06AD', magic=0xd4c6, total=6144, code=6144, eeprom=0),
MCUModel(name='STC15L08AD', magic=0xd4c8, total=8192, code=8192, eeprom=0),
MCUModel(name='STC15L10AD', magic=0xd4ca, total=10240, code=10240, eeprom=0),
MCUModel(name='STC15L12AD', magic=0xd4cc, total=12288, code=12288, eeprom=0),
MCUModel(name='STC15L04CCP', magic=0xd4b4, total=4096, code=4096, eeprom=0),
MCUModel(name='STC15L06CCP', magic=0xd4b6, total=6144, code=6144, eeprom=0),
MCUModel(name='STC15L08CCP', magic=0xd4b8, total=8192, code=8192, eeprom=0),
MCUModel(name='STC15L10CCP', magic=0xd4ba, total=10240, code=10240, eeprom=0),
MCUModel(name='STC15L12CCP', magic=0xd4bc, total=12288, code=12288, eeprom=0),
MCUModel(name='STC15L04', magic=0xd484, total=4096, code=4096, eeprom=0),
MCUModel(name='STC15L06', magic=0xd486, total=6144, code=6144, eeprom=0),
MCUModel(name='STC15L08', magic=0xd488, total=8192, code=8192, eeprom=0),
MCUModel(name='STC15L10', magic=0xd48a, total=10240, code=10240, eeprom=0),
MCUModel(name='STC15L12', magic=0xd48c, total=12288, code=12288, eeprom=0),
MCUModel(name='IAP15L08AD', magic=0xd4d8, total=8192, code=8192, eeprom=0),
MCUModel(name='IAP15L10AD', magic=0xd4da, total=10240, code=10240, eeprom=0),
MCUModel(name='IAP15L12AD', magic=0xd4dc, total=12288, code=12288, eeprom=0),
MCUModel(name='IAP15L14AD', magic=0xd4de, total=14336, code=14336, eeprom=0),
)
@classmethod
@ -1072,3 +961,6 @@ class MCUModelDatabase:
print(" Magic: %02X%02X" % (model.magic >> 8, model.magic & 0xff))
print(" Code flash: %.1f KB" % (model.code / 1024.0))
print(" EEPROM flash: %.1f KB" % (model.eeprom / 1024.0))

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -19,43 +19,31 @@
# SOFTWARE.
#
import argparse
import serial
import argparse
class Utils:
"""Common utility functions"""
@classmethod
def to_bool(cls, val):
def to_bool(self, val):
"""make sensible boolean from string or other type value"""
if not val:
return False
if isinstance(val, bool):
return val
elif isinstance(val, int):
return bool(val)
if isinstance(val, bool): return val
if isinstance(val, int): return bool(val)
if len(val) == 0: return False
return True if val[0].lower() == "t" or val[0] == "1" else False
@classmethod
def to_int(cls, val):
def to_int(self, val):
"""make int from any value, nice error message if not possible"""
try:
return int(val, 0)
except (TypeError, ValueError):
raise ValueError("invalid integer")
try: return int(val, 0)
except: raise ValueError("invalid integer")
@classmethod
def hexstr(cls, bytestr, sep=""):
def hexstr(self, bytestr, sep=""):
"""make formatted hex string output from byte sequence"""
return sep.join(["%02X" % x for x in bytes(bytestr)])
@classmethod
def decode_packed_bcd(cls, byt):
"""Decode two-digit packed BCD value"""
return (byt & 0x0f) + (10 * (byt >> 4))
return sep.join(["%02X" % x for x in bytestr])
class BaudType:
@ -67,5 +55,5 @@ class BaudType:
raise argparse.ArgumentTypeError("illegal baudrate")
return baud
def __repr__(self):
return "baudrate"
def __repr__(self): return "baudrate"

View File

View File

@ -1,19 +0,0 @@
name: IAP15F2K61S2 programming test
protocol: stc15
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
responses:
- [0x50, 0x87, 0xD3, 0x75, 0x9C, 0xF5, 0x3B, 0x17, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x09, 0x81, 0x00, 0x00, 0x71, 0x53, 0x00, 0xF4, 0x49, 0x04, 0x06, 0x58, 0x9C, 0x02, 0x0E, 0x14, 0x17, 0x19, 0x19, 0x00, 0xF4, 0xF4, 0x04, 0xD2]
- [0x00, 0x0B, 0x03, 0x37, 0x04, 0x9A, 0x06, 0x02, 0x06, 0x6B, 0x09, 0x27, 0x0B, 0xE8, 0x0D, 0x0A, 0x12, 0x5A, 0x17, 0x9B, 0x14, 0x8F, 0x1C, 0x96, 0x00, 0x00]
- [0x00, 0x0C, 0x09, 0x04, 0x09, 0x09, 0x09, 0x0E, 0x09, 0x0E, 0x09, 0x18, 0x09, 0x1D, 0x12, 0x00, 0x12, 0x0F, 0x12, 0x19, 0x12, 0x23, 0x12, 0x2D, 0x12, 0x37]
- [0x01]
- [0x05]
- [0x03, 0x0D, 0x00, 0x00, 0x21, 0x02, 0x26, 0x32]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x04, 0x54]

View File

@ -1,19 +0,0 @@
name: STC12C2052AD programming test
protocol: stc12a
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
responses:
- [0x00, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEB, 0x04, 0xEB, 0x58, 0x44, 0x00, 0xF2, 0x12, 0x83, 0xFD, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFD, 0xF7, 0xF7, 0xFF]
- [0x8F, 0xC0, 0x79, 0x3F, 0xFE, 0x28, 0x85]
- [0x8E, 0xC0, 0x79, 0x3F, 0xFE, 0x28]
- [0x80]
- [0x80]
- [0x80]
- [0x80]
- [0x80]
- [0x80, 0x66]
- [0x80, 0x80]
- [0x80, 0x80]
- [0x80, 0x80]
- [0x80, 0xEE]
- [0x10, 0xC0, 0x16, 0xF7, 0xFF, 0xBF, 0x03, 0xFF, 0x58, 0x44, 0xFD, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFD, 0xF7, 0xF7, 0xFF]
- [0x80]

View File

@ -1,15 +0,0 @@
name: STC12C5A60S2 programming test
protocol: stc12
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
responses:
- [0x50, 0x04, 0xBD, 0x04, 0xBC, 0x04, 0xBC, 0x04, 0xBD, 0x04, 0xBC, 0x04, 0xBC, 0x04, 0xBC, 0x04, 0xBC, 0x62, 0x49, 0x00, 0xD1, 0x7E, 0x8C, 0xFF, 0x7F, 0xF7, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x00, 0xB0, 0x02, 0x2E, 0x6B, 0x00, 0xCD, 0x80, 0x00, 0x00]
- [0x8F]
- [0x8F, 0xC0, 0x7E, 0x3F, 0xFE, 0xA0, 0x83, 0x04]
- [0x84, 0xC0, 0x7E, 0x3F, 0xFE, 0xA0, 0x04]
- [0x00]
- [0x00, 0x03]
- [0x00, 0x00]
- [0x00, 0x00]
- [0x00, 0x00]
- [0x8D]
- [0x50, 0xFF, 0x7F, 0xF7, 0xFF, 0xFF, 0x03, 0xFF, 0x62, 0x49, 0xFF, 0x7F, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x03, 0x00, 0xB0, 0x02, 0x2E, 0x6B, 0x00, 0xCD, 0x80, 0x00, 0x00]

View File

@ -1,20 +0,0 @@
name: STC15F104E programming test
protocol: stc15a
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
responses:
- [0x50, 0x02, 0xB0, 0x02, 0xB0, 0x02, 0xAF, 0x02, 0xB0, 0x02, 0xE6, 0x02, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x67, 0x51, 0xFF, 0xF2, 0x94, 0x8C, 0xEF, 0x3B, 0xF5, 0x58, 0x34, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x50, 0x0C, 0x94, 0x21, 0xFF, 0x29]
- [0x8f]
- [0x65, 0x58, 0x50, 0x0C, 0x95, 0x21, 0xFF, 0x2B, 0xFF, 0xFF, 0x06, 0x06, 0x58, 0x00, 0x02, 0x00, 0x58, 0x80, 0x02, 0x00, 0x58, 0x80, 0x02, 0x00, 0x58, 0xFF, 0x02, 0x00, 0x58, 0x00, 0x02, 0x00, 0x58, 0x80, 0x02, 0x00]
- [0x65, 0x58, 0x50, 0x0C, 0x95, 0x21, 0xFF, 0x2B, 0xFF, 0xFF, 0x06, 0x0B, 0x58, 0x24, 0x02, 0x00, 0x58, 0x25, 0x02, 0x00, 0x58, 0x26, 0x02, 0x00, 0x58, 0x27, 0x02, 0x00, 0x58, 0x28, 0x02, 0x00, 0x58, 0x29, 0x02, 0x00, 0x58, 0x2A, 0x02, 0x00, 0x58, 0x2B, 0x02, 0x00, 0x58, 0x2C, 0x02, 0x00, 0x58, 0x2D, 0x02, 0x00, 0x58, 0x2E, 0x02, 0x00]
- [0x01]
- [0x05]
- [0x03, 0x0C, 0x00, 0x00, 0x17, 0x01, 0xA0, 0xE0]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x04, 0x54]

View File

@ -1,19 +0,0 @@
name: STC15L104W programming test
protocol: stc15
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
responses:
- [0x50, 0x66, 0x3C, 0x93, 0xBA, 0xF7, 0xBB, 0x9F, 0x00, 0x5B, 0x68, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x71, 0x51, 0x03, 0xF2, 0xD4, 0x04, 0x06, 0x58, 0xBA, 0x02, 0x2A, 0x31, 0x32, 0x38, 0x30, 0x80, 0x14, 0x10, 0x04, 0xD9]
- [0x00, 0x0B, 0x03, 0x0A, 0x04, 0x4F, 0x05, 0x9E, 0x06, 0x20, 0x08, 0xB9, 0x0B, 0x5C, 0x0C, 0x6A, 0x11, 0x7E, 0x16, 0x79, 0x13, 0x77, 0x1A, 0xB1, 0x00, 0x00]
- [0x00, 0x0C, 0x04, 0xD6, 0x04, 0xDB, 0x04, 0xE0, 0x04, 0xE0, 0x04, 0xE0, 0x04, 0xE5, 0x11, 0xE2, 0x11, 0xF1, 0x11, 0xFB, 0x12, 0x05, 0x12, 0x0A, 0x12, 0x19]
- [0x01]
- [0x05]
- [0x03, 0x0C, 0x00, 0x00, 0x17, 0x01, 0xA0, 0xE0]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x04, 0x54]

View File

@ -1,20 +0,0 @@
name: STC15W4K56S4 programming test
protocol: stc15
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
responses:
- [0x50, 0x8D, 0xFF, 0x73, 0x96, 0xF5, 0x7B, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x27, 0xED, 0x00, 0x00, 0x73, 0x54, 0x00, 0xF5, 0x28, 0x04, 0x06, 0x70, 0x96, 0x02, 0x15, 0x19, 0x1C, 0x1E, 0x23, 0x00, 0xEC, 0xE0, 0x04, 0xD7, 0xF8, 0x73, 0xBF, 0xFF, 0xFF, 0x15, 0x09, 0x25, 0x60]
- [0x00, 0x0B, 0x0D, 0x21, 0x12, 0xBC, 0x18, 0x3E, 0x1A, 0x05, 0x24, 0xFA, 0x2F, 0xB3, 0x34, 0xD1, 0x4A, 0x52, 0x5E, 0xC0, 0x52, 0xDB, 0x73, 0x1A, 0x00, 0x00]
- [0x00, 0x0C, 0x23, 0xBF, 0x23, 0xD3, 0x23, 0xE7, 0x23, 0xF6, 0x24, 0x0F, 0x24, 0x23, 0x47, 0x73, 0x47, 0xB9, 0x47, 0xE1, 0x48, 0x09, 0x48, 0x36, 0x48, 0x59]
- [0x01]
- [0x05]
- [0x03, 0xF5, 0x28, 0x00, 0xA5, 0x03, 0x27, 0x49]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x07, 0x54]
- [0x04, 0x54]

View File

@ -1,19 +0,0 @@
name: STC89C52RC programming test
protocol: stc89
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
responses:
- [0x00, 0x25, 0xE6, 0x25, 0xE6, 0x25, 0xE6, 0x25, 0xE6, 0x25, 0xE6, 0x25, 0xE6, 0x25, 0xE2, 0x25, 0xE6, 0x43, 0x43, 0xFC, 0xF0, 0x02, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
- [0x8F, 0xFD, 0xF8, 0x02, 0x10, 0x28, 0x81]
- [0x8E, 0xFD, 0xF8, 0x02, 0x10, 0x28]
- [0x80]
- [0x80]
- [0x80]
- [0x80]
- [0x80]
- [0x80, 0x66]
- [0x80, 0x80]
- [0x80, 0x80]
- [0x80, 0x80]
- [0x8D, 0xFC, 0xFF, 0xF6, 0xFF]
- [0x10, 0xC0, 0x16, 0xF6, 0xFF, 0xF1, 0x03, 0xFF, 0x43, 0x43, 0xFC]
- [0x80]

View File

@ -1,20 +0,0 @@
name: STC8A8K64S4A12 programming test
protocol: stc8
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
responses:
- [0x50, 0x01, 0x6E, 0x0B, 0xD0, 0x78, 0x00, 0x01, 0xFF, 0xFF, 0x8B, 0xBF, 0xFF, 0x28, 0x43, 0xF7, 0xFE, 0x73, 0x55, 0x00, 0xF6, 0x28, 0x09, 0x85, 0xE3, 0x5F, 0x80, 0x07, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0xFE, 0x05, 0x3A, 0x17, 0x05, 0x25, 0x91, 0xFF]
- [0x00, 0x0C, 0x37, 0x49, 0x3B, 0x8D, 0x3F, 0xE0, 0x44, 0x57, 0x48, 0x9E, 0x4D, 0x06, 0x51, 0x35, 0x55, 0x94, 0x59, 0xCF, 0x5D, 0xDA, 0x62, 0x3C, 0x66, 0xDA]
- [0x00, 0x0C, 0x51, 0x59, 0x51, 0x8C, 0x51, 0xB3, 0x51, 0x71, 0x51, 0x9B, 0x51, 0xC2, 0x51, 0x77, 0x51, 0xAA, 0x51, 0xC8, 0x51, 0x62, 0x51, 0x89, 0x51, 0xB0]
- [0x01]
- [0x05]
- [0x03, 0xF6, 0x28, 0x02, 0xBC, 0x26, 0x98, 0xDF]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x02, 0x54]
- [0x07, 0x54]
- [0x04, 0x54]

View File

@ -1,120 +0,0 @@
#
# Copyright (c) 2017 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.
#
"""Tests with fuzzing of input data"""
import random
import sys
import unittest
from unittest.mock import patch
import yaml
import stcgal.frontend
import stcgal.protocols
from tests.test_program import get_default_opts, convert_to_bytes
class ByteArrayFuzzer:
"""Fuzzer for byte arrays"""
def __init__(self):
self.rng = random.Random()
self.cut_propability = 0.01 # probability for cutting off an array early
self.cut_min = 0 # minimum cut amount
self.cut_max = sys.maxsize # maximum cut amount
self.bitflip_probability = 0.0001 # probability for flipping a bit
self.randomize_probability = 0.001 # probability for randomizing a char
def fuzz(self, inp):
"""Fuzz an array of bytes according to predefined settings"""
arr = bytearray(inp)
arr = self.cut_off(arr)
self.randomize(arr)
return bytes(arr)
def randomize(self, arr):
"""Randomize array contents with bitflips and random bytes"""
for i, _ in enumerate(arr):
for j in range(8):
if self.rng.random() < self.bitflip_probability:
arr[i] ^= (1 << j)
if self.rng.random() < self.randomize_probability:
arr[i] = self.rng.getrandbits(8)
def cut_off(self, arr):
"""Cut off data from end of array"""
if self.rng.random() < self.cut_propability:
cut_limit = min(len(arr), self.cut_max)
cut_len = self.rng.randrange(self.cut_min, cut_limit)
arr = arr[0:len(arr) - cut_len]
return arr
class TestProgramFuzzed(unittest.TestCase):
"""Special programming cycle tests that use a fuzzing approach"""
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
@patch("stcgal.protocols.Stc89Protocol.write_packet")
@patch("stcgal.protocols.serial.Serial", autospec=True)
@patch("stcgal.protocols.time.sleep")
@patch("sys.stdout")
@patch("sys.stderr")
def test_program_fuzz(self, err, out, sleep_mock, serial_mock, write_mock, read_mock):
"""Test programming cycles with fuzzing enabled"""
yml = [
"./tests/iap15f2k61s2.yml",
"./tests/stc12c2052ad.yml",
"./tests/stc15w4k56s4.yml",
"./tests/stc12c5a60s2.yml",
"./tests/stc89c52rc.yml",
"./tests/stc15l104w.yml",
"./tests/stc15f104e.yml",
"./tests/stc8a8k64s4a12.yml",
]
fuzzer = ByteArrayFuzzer()
fuzzer.cut_propability = 0.01
fuzzer.bitflip_probability = 0.005
fuzzer.rng = random.Random(1)
for y in yml:
with self.subTest(msg="trace {}".format(y)):
self.single_fuzz(y, serial_mock, fuzzer, read_mock, err, out,
sleep_mock, write_mock)
def single_fuzz(self, yml, serial_mock, fuzzer, read_mock, err, out, sleep_mock, write_mock):
"""Test a single programming cycle with fuzzing"""
with open(yml) as test_file:
test_data = yaml.load(test_file.read())
for _ in range(1000):
with self.subTest():
opts = get_default_opts()
opts.protocol = test_data["protocol"]
opts.code_image.read.return_value = bytes(test_data["code_data"])
serial_mock.return_value.inWaiting.return_value = 1
fuzzed_responses = []
for arr in convert_to_bytes(test_data["responses"]):
fuzzed_responses.append(fuzzer.fuzz(arr))
read_mock.side_effect = fuzzed_responses
gal = stcgal.frontend.StcGal(opts)
self.assertGreaterEqual(gal.run(), 0)
err.reset_mock()
out.reset_mock()
sleep_mock.reset_mock()
serial_mock.reset_mock()
write_mock.reset_mock()
read_mock.reset_mock()

View File

@ -1,144 +0,0 @@
#
# Copyright (c) 2017 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.
#
"""Tests that simulate a whole programming cycle"""
import unittest
from unittest.mock import patch
import yaml
import stcgal.frontend
import stcgal.protocols
def convert_to_bytes(list_of_lists):
"""Convert lists of integer lists to list of byte lists"""
return [bytes(x) for x in list_of_lists]
def get_default_opts():
"""Get a default preconfigured option object"""
opts = unittest.mock.MagicMock()
opts.protocol = "stc89"
opts.autoreset = False
opts.port = ""
opts.baud = 19200
opts.handshake = 9600
opts.trim = 22118
opts.eeprom_image = None
opts.debug = False
opts.code_image.name = "test.bin"
opts.code_image.read.return_value = b"123456789"
return opts
class ProgramTests(unittest.TestCase):
"""Test MCU programming cycles for different families, based on traces"""
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
@patch("stcgal.protocols.Stc89Protocol.write_packet")
@patch("stcgal.protocols.serial.Serial", autospec=True)
@patch("stcgal.protocols.time.sleep")
@patch("sys.stdout")
def test_program_stc89(self, out, sleep_mock, serial_mock, write_mock, read_mock):
"""Test a programming cycle with STC89 protocol"""
self._program_yml("./tests/stc89c52rc.yml", serial_mock, read_mock)
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
@patch("stcgal.protocols.Stc89Protocol.write_packet")
@patch("stcgal.protocols.serial.Serial", autospec=True)
@patch("stcgal.protocols.time.sleep")
@patch("sys.stdout")
def test_program_stc12(self, out, sleep_mock, serial_mock, write_mock, read_mock):
"""Test a programming cycle with STC12 protocol"""
self._program_yml("./tests/stc12c5a60s2.yml", serial_mock, read_mock)
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
@patch("stcgal.protocols.Stc89Protocol.write_packet")
@patch("stcgal.protocols.serial.Serial", autospec=True)
@patch("stcgal.protocols.time.sleep")
@patch("sys.stdout")
def test_program_stc12a(self, out, sleep_mock, serial_mock, write_mock, read_mock):
"""Test a programming cycle with STC12A protocol"""
self._program_yml("./tests/stc12c2052ad.yml", serial_mock, read_mock)
def test_program_stc12b(self):
"""Test a programming cycle with STC12B protocol"""
self.skipTest("trace missing")
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
@patch("stcgal.protocols.Stc89Protocol.write_packet")
@patch("stcgal.protocols.serial.Serial", autospec=True)
@patch("stcgal.protocols.time.sleep")
@patch("sys.stdout")
def test_program_stc15f2(self, out, sleep_mock, serial_mock, write_mock, read_mock):
"""Test a programming cycle with STC15 protocol, F2 series"""
self._program_yml("./tests/iap15f2k61s2.yml", serial_mock, read_mock)
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
@patch("stcgal.protocols.Stc89Protocol.write_packet")
@patch("stcgal.protocols.serial.Serial", autospec=True)
@patch("stcgal.protocols.time.sleep")
@patch("sys.stdout")
def test_program_stc15w4(self, out, sleep_mock, serial_mock, write_mock, read_mock):
"""Test a programming cycle with STC15 protocol, W4 series"""
self._program_yml("./tests/stc15w4k56s4.yml", serial_mock, read_mock)
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
@patch("stcgal.protocols.Stc89Protocol.write_packet")
@patch("stcgal.protocols.serial.Serial", autospec=True)
@patch("stcgal.protocols.time.sleep")
@patch("sys.stdout")
def test_program_stc8a8(self, out, sleep_mock, serial_mock, write_mock, read_mock):
"""Test a programming cycle with STC8 protocol, STC8A8 series"""
self._program_yml("./tests/stc8a8k64s4a12.yml", serial_mock, read_mock)
@unittest.skip("trace is broken")
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
@patch("stcgal.protocols.Stc89Protocol.write_packet")
@patch("stcgal.protocols.serial.Serial", autospec=True)
@patch("stcgal.protocols.time.sleep")
@patch("sys.stdout")
def test_program_stc15a(self, out, sleep_mock, serial_mock, write_mock, read_mock):
"""Test a programming cycle with STC15A protocol"""
self._program_yml("./tests/stc15f104e.yml", serial_mock, read_mock)
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
@patch("stcgal.protocols.Stc89Protocol.write_packet")
@patch("stcgal.protocols.serial.Serial", autospec=True)
@patch("stcgal.protocols.time.sleep")
@patch("sys.stdout")
def test_program_stc15l1(self, out, sleep_mock, serial_mock, write_mock, read_mock):
"""Test a programming cycle with STC15 protocol, L1 series"""
self._program_yml("./tests/stc15l104w.yml", serial_mock, read_mock)
def test_program_stc15w4_usb(self):
"""Test a programming cycle with STC15W4 USB protocol"""
self.skipTest("USB not supported yet, trace missing")
def _program_yml(self, yml, serial_mock, read_mock):
"""Program MCU with data from YAML file"""
with open(yml) as test_file:
test_data = yaml.load(test_file.read())
opts = get_default_opts()
opts.protocol = test_data["protocol"]
opts.code_image.read.return_value = bytes(test_data["code_data"])
serial_mock.return_value.inWaiting.return_value = 1
read_mock.side_effect = convert_to_bytes(test_data["responses"])
gal = stcgal.frontend.StcGal(opts)
self.assertEqual(gal.run(), 0)

View File

@ -1,84 +0,0 @@
#
# Copyright (c) 2017 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.
#
"""Tests for utility functions and other misc parts"""
import argparse
import unittest
from stcgal.utils import Utils, BaudType
class TestUtils(unittest.TestCase):
"""Test for utility functions in the Utils class"""
def test_to_bool(self):
"""Test special utility function for bool conversion"""
self.assertTrue(Utils.to_bool(True))
self.assertTrue(Utils.to_bool("true"))
self.assertTrue(Utils.to_bool("True"))
self.assertTrue(Utils.to_bool("t"))
self.assertTrue(Utils.to_bool("T"))
self.assertTrue(Utils.to_bool(1))
self.assertTrue(Utils.to_bool(-1))
self.assertFalse(Utils.to_bool(0))
self.assertFalse(Utils.to_bool(None))
self.assertFalse(Utils.to_bool("false"))
self.assertFalse(Utils.to_bool("False"))
self.assertFalse(Utils.to_bool("f"))
self.assertFalse(Utils.to_bool("F"))
self.assertFalse(Utils.to_bool(""))
def test_to_int(self):
"""Test wrapped integer conversion"""
self.assertEqual(Utils.to_int("2"), 2)
self.assertEqual(Utils.to_int("0x10"), 16)
with self.assertRaises(ValueError):
Utils.to_int("a")
with self.assertRaises(ValueError):
Utils.to_int("")
with self.assertRaises(ValueError):
Utils.to_int(None)
def test_hexstr(self):
"""Test byte array formatter"""
self.assertEqual(Utils.hexstr([10]), "0A")
self.assertEqual(Utils.hexstr([1, 2, 3]), "010203")
with self.assertRaises(Exception):
Utils.hexstr([400, 500])
def test_decode_packed_bcd(self):
"""Test packed BCD decoder"""
self.assertEqual(Utils.decode_packed_bcd(0x01), 1)
self.assertEqual(Utils.decode_packed_bcd(0x10), 10)
self.assertEqual(Utils.decode_packed_bcd(0x11), 11)
self.assertEqual(Utils.decode_packed_bcd(0x25), 25)
self.assertEqual(Utils.decode_packed_bcd(0x99), 99)
class TestBaudType(unittest.TestCase):
"""Test BaudType class"""
def test_create_baud_type(self):
"""Test creation of BaudType instances"""
baud_type = BaudType()
self.assertEqual(baud_type("2400"), 2400)
self.assertEqual(baud_type("115200"), 115200)
with self.assertRaises(argparse.ArgumentTypeError):
baud_type("2374882")