Compare commits
157 Commits
stc15-baud
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
fdf5fdd605 | ||
|
a660184520 | ||
|
6e8e73669e | ||
|
b32bbf99c8 | ||
|
cdc365a5f0 | ||
|
521339066c | ||
|
48a36b90c9 | ||
|
1c37582952 | ||
|
6a598002e6 | ||
|
fcf4dff166 | ||
|
bef3313056 | ||
|
36c920dd77 | ||
|
ad0becf1d0 | ||
|
6254494f92 | ||
|
f881eccaff | ||
|
ef06e311fc | ||
|
6373620d18 | ||
|
8b55c166db | ||
|
ae7645cc73 | ||
|
36bdf16cff | ||
|
4c3c3065e0 | ||
|
717af49b16 | ||
|
a6b791b089 | ||
|
4894e8f219 | ||
|
f41ae5679f | ||
|
1468d60005 | ||
|
86bee9141a | ||
|
b43792ccd8 | ||
|
20ae770f8f | ||
|
796a17f7cf | ||
|
4840d3cda5 | ||
|
2d3c24fc3a | ||
|
761c68e469 | ||
|
9900e3088d | ||
|
15e04c1626 | ||
|
187aa9a3cf | ||
|
482e6b139f | ||
|
9202399a84 | ||
|
3cf2cb38e7 | ||
|
384471f765 | ||
|
df2fbc23cd | ||
|
77df068efd | ||
|
2fb96d6236 | ||
|
c2fd3ab710 | ||
|
0d5e8e645f | ||
|
1ec855e6a1 | ||
|
d708a00e9e | ||
|
5c2950f084 | ||
|
c5d509d1fa | ||
|
0e020f2aa4 | ||
|
b46d81a184 | ||
|
ad5a532ab9 | ||
|
b3741af045 | ||
|
1e78d62f5d | ||
|
d0597578de | ||
|
eaeab65044 | ||
|
a19fc406a3 | ||
|
51ac52d3a3 | ||
|
43dbb2ef64 | ||
|
d7ed8bd530 | ||
|
6b83017de9 | ||
|
2d7ccf8b3d | ||
|
77b3f0e1b7 | ||
|
5d3214060b | ||
|
7e413b09ec | ||
|
3aa08b67c0 | ||
|
42f93bc481 | ||
|
dbfc1b3f50 | ||
|
9d47588ad2 | ||
|
217e5fb17e | ||
|
3875b1f415 | ||
|
8e31765cba | ||
|
75db655419 | ||
|
1c062ed0c7 | ||
|
4fe0a30072 | ||
|
7d9f512b6d | ||
|
6544699a84 | ||
|
f5089af93a | ||
|
bc829ce54c | ||
|
97d0d1123b | ||
|
5032b631bf | ||
|
9ae334ec25 | ||
|
05984a6c49 | ||
|
e0e2ab5526 | ||
|
4cc0deb8e9 | ||
|
5ab2a73411 | ||
|
4a40d5613a | ||
|
83c0b47f62 | ||
|
b0e882ff32 | ||
|
ccd4b1e26b | ||
|
71d7257422 | ||
|
0ff7e16f38 | ||
|
aca713595b | ||
|
69b83f0ea1 | ||
|
170008971d | ||
|
cd229eab47 | ||
|
ce251f9d30 | ||
|
11d2ea22e6 | ||
|
c7c4937628 | ||
|
ac119e180e | ||
|
fcbc560ade | ||
|
7b4758499b | ||
|
fe60e647bf | ||
|
0ffcbd197b | ||
|
85e815366c | ||
|
8bc9d89257 | ||
|
b47092093e | ||
|
bc5e8ce6cb | ||
|
d9e71a8694 | ||
|
4dcde5cc49 | ||
|
3ec6f5b6bd | ||
|
eb6df3b645 | ||
|
eb8eecbc9b | ||
|
c71e455f16 | ||
|
a5e1cc26ee | ||
|
b77157bc40 | ||
|
092fbdc842 | ||
|
e0bda73fed | ||
|
57100062af | ||
|
030497beb0 | ||
|
fd923f3a92 | ||
|
b145fb364a | ||
|
a29c9bf42e | ||
|
1cde6da007 | ||
|
ca30a508aa | ||
|
b9208c4772 | ||
|
ad5a89297f | ||
|
0cb56f4919 | ||
|
f195258eb5 | ||
|
ff9530833d | ||
|
8b0fdcb42a | ||
|
ebcfeb467c | ||
|
d7e226df6b | ||
|
191a580469 | ||
|
c131a9d901 | ||
|
3f4263e8fe | ||
|
ba4faf9c43 | ||
|
f1bafb1e0d | ||
|
fdd6707d2d | ||
|
532363d97b | ||
|
5865b06f7f | ||
|
1b69257cd3 | ||
|
38ac5f0788 | ||
|
6dccf13fb6 | ||
|
0ca8b2ea2d | ||
|
53184b549e | ||
|
cf68e3c6dc | ||
|
5d10c06f1e | ||
|
7e84b8e0fb | ||
|
f34ba6644f | ||
|
f15b64f4f7 | ||
|
2e822375e0 | ||
|
7d6e8e9bfd | ||
|
506289b8ee | ||
|
f417b6eed5 | ||
|
86e289b65c | ||
|
53f9544281 |
50
.github/workflows/python.yml
vendored
Normal file
50
.github/workflows/python.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
name: Python package
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: [3.7, 3.8]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pyusb coverage coveralls pyserial PyYAML tqdm
|
||||
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
||||
- name: Build package
|
||||
run: |
|
||||
python setup.py build
|
||||
- name: Test with unittest
|
||||
run: |
|
||||
coverage run --source=stcgal setup.py test
|
||||
- name: Coveralls
|
||||
run: |
|
||||
coveralls
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
COVERALLS_FLAG_NAME: ${{ matrix.python-version }}
|
||||
COVERALLS_PARALLEL: true
|
||||
|
||||
coveralls:
|
||||
name: Finish Coveralls
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
container: python:3-slim
|
||||
steps:
|
||||
- name: Finished
|
||||
run: |
|
||||
pip3 install --upgrade coveralls
|
||||
coveralls --finish
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,7 +1,15 @@
|
||||
*~
|
||||
*.pyc
|
||||
*.egg-info
|
||||
__pycache__
|
||||
*.eggs/
|
||||
*.pybuild/
|
||||
__pycache__/
|
||||
/build
|
||||
/dist
|
||||
/deb_dist
|
||||
/debian/stcgal*
|
||||
/debian/files
|
||||
/.vscode
|
||||
.coverage
|
||||
coverage.xml
|
||||
htmlcov/
|
68
README-zh_CN.md
Normal file
68
README-zh_CN.md
Normal file
@ -0,0 +1,68 @@
|
||||
文档说明 Explanation
|
||||
-------------------
|
||||
此文档翻译自README.MD
|
||||
|
||||
This document was translated from README.MD
|
||||
|
||||
最后修改时间:2020年6月8日
|
||||
|
||||
Last modified time: June 8, 2020
|
||||
|
||||
|
||||
stcgal - 用于STC MCU的ISP闪存工具
|
||||
===============================
|
||||
|
||||
stcgal是用于[STC MCU Ltd]的命令行闪存编程工具。
|
||||
兼容8051微控制器。
|
||||
|
||||
|
||||
STC微控制器具有基于UART / USB的引导加载程序(BSL)。
|
||||
它采用系统内编程,即基于数据包的协议通过串行链路刷新代码存储器和IAP存储器。
|
||||
BSL还用于配置各种设备选项。
|
||||
不幸的是,该协议没有公开记录,STC仅提供(粗略的)Windows GUI应用程序进行编程
|
||||
|
||||
|
||||
stcgal是STC的Windows软件的功能全面的开源替代品。
|
||||
它支持多种MCU,非常便携,适合自动下载。
|
||||
|
||||
特点
|
||||
--------
|
||||
|
||||
* 支持STC 89/90/10/11/12/15/8/32系列
|
||||
* UART和USB BSL支持
|
||||
* 显示信息
|
||||
* 确定工作频率
|
||||
* 程序闪存
|
||||
* 程序IAP / EEPROM
|
||||
* 设置设备选项
|
||||
* 读取唯一的设备ID(STC 10/11/12/15/8)
|
||||
* 设置RC振荡器频率(STC 15/8)
|
||||
* 自动电源(使用DTR切换或自定义Shell命令循环)
|
||||
* 自动UART协议检测
|
||||
|
||||
快速开始
|
||||
----------
|
||||
|
||||
安装stcgal(可能需要root /管理员权限):
|
||||
|
||||
pip3 install stcgal
|
||||
|
||||
呼叫stcgal并显示的用法:
|
||||
|
||||
stcgal -h
|
||||
|
||||
更多的信息
|
||||
-------------------
|
||||
|
||||
[安装方法](doc/zh_CN/INSTALL.md)
|
||||
|
||||
[如何取使用](doc/zh_CN/USAGE.md)
|
||||
|
||||
[常见问题](doc/zh_CN/FAQ.md)
|
||||
|
||||
[支持的MCU型号](doc/zh_CN/MODELS.md)
|
||||
|
||||
执照
|
||||
-------
|
||||
|
||||
stcgal是根据MIT许可发布的。
|
281
README.md
281
README.md
@ -1,8 +1,12 @@
|
||||
[![Build Status](https://github.com/grigorig/stcgal/workflows/Python%20package/badge.svg?branch=master)](https://github.com/grigorig/stcgal/actions?query=workflow%3A%22Python+package%22)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/grigorig/stcgal/badge.svg?branch=master)](https://coveralls.io/github/grigorig/stcgal?branch=master)
|
||||
[![PyPI version](https://badge.fury.io/py/stcgal.svg)](https://badge.fury.io/py/stcgal)
|
||||
|
||||
stcgal - STC MCU ISP flash tool
|
||||
===============================
|
||||
|
||||
stcgal is a command line flash programming tool for STC MCU Ltd. [1]
|
||||
8051 compatible microcontrollers. The name was inspired by avrdude [2].
|
||||
stcgal is a command line flash programming tool for [STC MCU Ltd](http://stcmcu.com/).
|
||||
8051 compatible microcontrollers.
|
||||
|
||||
STC microcontrollers have an UART/USB based boot strap loader (BSL). It
|
||||
utilizes a packet-based protocol to flash the code memory and IAP
|
||||
@ -15,281 +19,42 @@ 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)
|
||||
* STC90C52RC (BSL version: 4.3C)
|
||||
* STC89C54RD+ (BSL version: 4.3C)
|
||||
* STC12C2052 (BSL version: 5.8D)
|
||||
* STC12C2052AD (BSL version: 5.8D)
|
||||
* STC12C5608AD (BSL version: 6.0G)
|
||||
* STC12C5A16S2 (BSL version: 6.2I)
|
||||
* STC12C5A60S2 (BSL version: 6.2I)
|
||||
* STC11F02E (BSL version: 6.5K)
|
||||
* STC10F04XE (BSL version: 6.5J)
|
||||
* STC11F08XE (BSL version: 6.5M)
|
||||
* STC12C5204AD (BSL version: 6.6H)
|
||||
* STC15F104E (BSL version: 6.7Q)
|
||||
* STC15F204EA (BSL version: 6.7R)
|
||||
* STC15L104W (BSL version: 7.1.4Q)
|
||||
* STC15F104W (BSL version: 7.1.4Q)
|
||||
* IAP15F2K61S2 (BSL version: 7.1.4S)
|
||||
* STC15L2K16S2 (BSL version: 7.2.4S)
|
||||
* STC15W408AS (BSL version: 7.2.4T)
|
||||
* STC15W4K56S4 (BSL version: 7.3.4T, UART and USB mode)
|
||||
|
||||
Compatibility reports, both negative and positive, are welcome.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Support for STC 89/90/10/11/12/15/8/32 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)
|
||||
* Trim RC oscillator frequency (STC 15)
|
||||
* Automatic power-cycling with DTR toggle
|
||||
* 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
|
||||
|
||||
Installation
|
||||
------------
|
||||
Quickstart
|
||||
----------
|
||||
|
||||
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.
|
||||
Install stcgal (might need root/administrator privileges):
|
||||
|
||||
pip3 install stcgal
|
||||
|
||||
Usage
|
||||
-----
|
||||
Call stcgal and show usage:
|
||||
|
||||
Call stcgal with ```-h``` for usage information.
|
||||
stcgal -h
|
||||
|
||||
```
|
||||
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]
|
||||
Further information
|
||||
-------------------
|
||||
|
||||
stcgal 1.0 - an STC MCU ISP flash tool
|
||||
(C) 2014-2015 Grigori Goronzy
|
||||
https://github.com/grigorig/stcgal
|
||||
[Installation](doc/INSTALL.md)
|
||||
|
||||
positional arguments:
|
||||
code_image code segment file to flash (BIN/HEX)
|
||||
eeprom_image eeprom segment file to flash (BIN/HEX)
|
||||
[How to use stcgal](doc/USAGE.md)
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-a, --autoreset cycle power automatically by asserting DTR
|
||||
-P {stc89,stc12a,stc12,stc15a,stc15,auto}, --protocol {stc89,stc12a,stc12,stc15a,stc15,auto}
|
||||
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
|
||||
```
|
||||
[Frequently Asked Questions](doc/FAQ.md)
|
||||
|
||||
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
|
||||
* ```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 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.
|
||||
|
||||
### Automatic power-cycling
|
||||
|
||||
STC's microcontrollers require a power-on reset to invoke the bootloader,
|
||||
which can be inconvenient. stcgal can use the DTR control signal of a
|
||||
serial interface to automate this. The DTR signal is asserted for
|
||||
approximately 500 ms when the autoreset feature is enabled with the
|
||||
```-a``` flag. This requires external circuitry to actually switch the
|
||||
power. In some cases, when the microcontroller draws only little power,
|
||||
it is possible to directly supply power from the DTR signal, however.
|
||||
|
||||
### Exit status
|
||||
|
||||
The exit status is 0 if no error occured while executing stcgal. Any
|
||||
error, such as a protocol error or I/O error, results in an exit
|
||||
status of 1. If the the user aborted stcgal by pressing CTRL-C,
|
||||
that results in an exit status of 2.
|
||||
|
||||
### USB support
|
||||
|
||||
STC15W4 series have an USB-based BSL that can be optionally
|
||||
used. USB support in stcgal is experimental and might change in the
|
||||
future. USB mode is enabled by using the ```usb15``` protocol. The
|
||||
port (```-p```) flag as well as the baudrate options are ignored for
|
||||
the USB protocol. RC frequency trimming is not supported.
|
||||
[List of tested MCU models](doc/MODELS.md)
|
||||
|
||||
License
|
||||
-------
|
||||
|
10
TODO.md
10
TODO.md
@ -1,10 +0,0 @@
|
||||
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
|
12
debian/changelog
vendored
12
debian/changelog
vendored
@ -1,12 +0,0 @@
|
||||
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
|
||||
|
||||
-- Andrew 'Necromant' Andrianov <andrew@ncrmnt.org> Wed, 25 Nov 2015 13:07:03 +0300
|
1
debian/compat
vendored
1
debian/compat
vendored
@ -1 +0,0 @@
|
||||
9
|
27
debian/control
vendored
27
debian/control
vendored
@ -1,27 +0,0 @@
|
||||
Source: stcgal
|
||||
Section: electronics
|
||||
Priority: optional
|
||||
Maintainer: Andrew Andrianov <andrew@ncrmnt.org>
|
||||
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
|
||||
Recommends: python3-usb (>= 1.0.0~b2)
|
||||
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.
|
||||
.
|
||||
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.
|
||||
.
|
||||
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.
|
32
debian/copyright
vendored
32
debian/copyright
vendored
@ -1,32 +0,0 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: stcgal
|
||||
Upstream-Contact: Grigori Goronzy <greg@kinoho.net>
|
||||
Source: https://github.com/grigorig/stcgal
|
||||
|
||||
Files: *
|
||||
Copyright: 2013-2015 Grigori Goronzy <greg@kinoho.net>
|
||||
License: MIT
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2015 Andrew 'Necromant' Andrianov <andrew@ncrmnt.org>
|
||||
2015 Grigori Goronzy <greg@kinoho.net>
|
||||
License: MIT
|
||||
|
||||
License: MIT
|
||||
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.
|
2
debian/docs
vendored
2
debian/docs
vendored
@ -1,2 +0,0 @@
|
||||
README.md
|
||||
TODO.md
|
7
debian/rules
vendored
7
debian/rules
vendored
@ -1,7 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
export PYBUILD_NAME=stcgal
|
||||
|
||||
%:
|
||||
dh $@ --with python3 --buildsystem=pybuild
|
||||
|
1
debian/source/format
vendored
1
debian/source/format
vendored
@ -1 +0,0 @@
|
||||
3.0 (native)
|
75
doc/FAQ.md
Normal file
75
doc/FAQ.md
Normal file
@ -0,0 +1,75 @@
|
||||
Frequently Asked Questions
|
||||
==========================
|
||||
|
||||
### Is it possible to read code (or EEPROM) memory out of a chip?
|
||||
|
||||
By design, it is not possible to read back code flash memory 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.
|
||||
|
||||
On some STC MCUs, you can erase code flash memory without erasing EEPROM. That means you can create a program to dump the EEPROM. stcgal does not have any native support to do that at this time.
|
||||
|
||||
### Which serial interfaces have been tested with stcgal?
|
||||
|
||||
stcgal should work fine with common 16550 compatible UARTs that are traditionally available on many platforms. However, nowadays, USB-based UARTs are the typical case. 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 start with the error `module 'serial' has no attribute 'PARITY_NONE'` or similar
|
||||
|
||||
There is a module name conflict between the PyPI package 'serial' (a data serialization library) and the PyPI package 'pyserial' (the serial port access library needed by stcgal). You have to uninstall the 'serial' package (`pip3 uninstall serial`) and reinstall 'pyserial' (`pip3 install --force-reinstall pyserial`) to fix this. There is no other known solution at the moment.
|
||||
|
||||
### 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 compatibility issues with protocol autodetection (for instance with some fake FTDI USB UART chips). Try to explicitly provide the protocol variant with the option ```-P```.
|
||||
* Other 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 or flash programming 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.
|
||||
|
17
doc/INSTALL.md
Normal file
17
doc/INSTALL.md
Normal file
@ -0,0 +1,17 @@
|
||||
Installation
|
||||
============
|
||||
|
||||
stcgal requires Python 3.5 (or later), pyserial 3.0 or later and
|
||||
TQDM 4.0.0 or later. USB support is optional and requires pyusb
|
||||
1.0.0b2 or later. You can run stcgal directly with the included
|
||||
```stcgal.py``` script if the dependencies are already installed.
|
||||
|
||||
There are several options for permanent installation:
|
||||
|
||||
* Use Python3 and ```pip```. Run ```pip3 install stcgal``` to
|
||||
install the latest release of stcgal globally on your system.
|
||||
This may require administrator/root permissions for write access
|
||||
to system directories.
|
||||
|
||||
* Use setuptools. Run ```./setup.py build``` to build and
|
||||
```sudo ./setup.py install``` to install stcgal.
|
56
doc/MODELS.md
Normal file
56
doc/MODELS.md
Normal file
@ -0,0 +1,56 @@
|
||||
Supported MCU models
|
||||
====================
|
||||
|
||||
stcgal should fully support STC 89/90/10/11/12/15/8/32 series MCUs.
|
||||
|
||||
So far, stcgal was tested with the following MCU models:
|
||||
|
||||
STC89/90 series
|
||||
* STC89C52RC (BSL version: 4.3C/6.6C)
|
||||
* STC89C54RD+ (BSL version: 4.3C)
|
||||
* STC90C52RC (BSL version: 4.3C)
|
||||
* STC90C58RD+ (BSL version: 4.3C)
|
||||
|
||||
STC10/11 series
|
||||
* STC10F04XE (BSL version: 6.5J)
|
||||
* STC11F02E (BSL version: 6.5K)
|
||||
* STC11F08XE (BSL version: 6.5M)
|
||||
|
||||
STC12 series
|
||||
* 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)
|
||||
* STC12C5204AD (BSL version: 6.6H)
|
||||
|
||||
STC15 series
|
||||
* STC15F104E (BSL version: 6.7Q)
|
||||
* STC15F204EA (BSL version: 6.7R)
|
||||
* STC15L104W (BSL version: 7.1.4Q)
|
||||
* STC15F104W (BSL version: 7.1.4Q and 7.2.5Q)
|
||||
* IAP15F2K61S2 (BSL version: 7.1.4S)
|
||||
* STC15L2K16S2 (BSL version: 7.2.4S)
|
||||
* IAP15L2K61S2 (BSL version: 7.2.5S)
|
||||
* STC15W408AS (BSL version: 7.2.4T and 7.2.5T)
|
||||
* STC15W4K56S4 (BSL version: 7.3.4T and 7.3.7T, UART and USB mode)
|
||||
|
||||
STC8 series
|
||||
* STC8A8K64S4A12 (BSL version: 7.3.9U and 7.3.12U)
|
||||
* STC8F2K08S2 (BSL version: 7.3.10U)
|
||||
* STC8A8K64D4 (BSL version: 7.4.2U)
|
||||
* STC8G1K08A-8PIN (BSL version: 7.3.12U)
|
||||
* STC8G1K08-20/16PIN (BSL version: 7.3.12U)
|
||||
* STC8G1K17-20/16PIN (BSL version: 7.3.12U)
|
||||
* STC8G2K64S4 (BSL version: 7.3.11U)
|
||||
* STC8H1K08 (BSL version: 7.3.12U)
|
||||
* STC8H1K17T (BSL version: 7.4.5U)
|
||||
* STC8H3K64S2 (BSL version: 7.4.1U)
|
||||
* STC8H3K64S4 (BSL version: 7.4.1U)
|
||||
* STC8H4K64TL (BSL version: 7.4.3U)
|
||||
* STC8H8K64U (BSL version: 7.4.4U)
|
||||
|
||||
STC32 series
|
||||
* STC32G12K128-Beta (BSL version: 7.4.4U)
|
||||
|
||||
Compatibility reports, both negative and positive, are welcome.
|
18
doc/PyPI.md
Normal file
18
doc/PyPI.md
Normal file
@ -0,0 +1,18 @@
|
||||
stcgal - STC MCU ISP flash tool
|
||||
===============================
|
||||
|
||||
stcgal is a command line flash programming tool for [STC MCU Ltd](http://stcmcu.com/).
|
||||
8051 compatible microcontrollers.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
[See the GitHub page for more information](https://github.com/grigorig/stcgal).
|
257
doc/USAGE.md
Normal file
257
doc/USAGE.md
Normal file
@ -0,0 +1,257 @@
|
||||
Usage
|
||||
=====
|
||||
|
||||
Call stcgal with ```-h``` for usage information.
|
||||
|
||||
```
|
||||
usage: stcgal [-h] [-e] [-a] [-A {dtr,rts}] [-r RESETCMD]
|
||||
[-P {stc89,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto}]
|
||||
[-p PORT] [-b BAUD] [-l HANDSHAKE] [-o OPTION] [-t TRIM] [-D]
|
||||
[-V]
|
||||
[code_image] [eeprom_image]
|
||||
|
||||
stcgal 1.7 - an STC MCU ISP flash tool
|
||||
(C) 2014-2018 Grigori Goronzy and others
|
||||
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)
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-e, --erase only erase flash memory
|
||||
-a, --autoreset cycle power automatically by asserting DTR
|
||||
-A {dtr,rts,dtr_inverted,rts_inverted}, --resetpin {dtr,rts,dtr_inverted,rts_inverted}
|
||||
pin to hold down when using --autoreset (default: DTR)
|
||||
-r RESETCMD, --resetcmd RESETCMD
|
||||
shell command for board power-cycling (instead of DTR
|
||||
assertion)
|
||||
-P {stc89,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto}, --protocol {stc89,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto}
|
||||
protocol version (default: auto)
|
||||
-p PORT, --port PORT serial port device
|
||||
-b BAUD, --baud BAUD transfer baud rate (default: 115200)
|
||||
-l HANDSHAKE, --handshake HANDSHAKE
|
||||
handshake baud rate (default: 2400)
|
||||
-o OPTION, --option OPTION
|
||||
set option (can be used multiple times, see
|
||||
documentation)
|
||||
-t TRIM, --trim TRIM RC oscillator frequency in kHz (STC15+ series only)
|
||||
-D, --debug enable debug output
|
||||
-V, --version print version info and exit
|
||||
```
|
||||
|
||||
Most importantly, ```-p``` sets the serial port to be used for programming.
|
||||
|
||||
### Transfer baud rate
|
||||
|
||||
The default value of 115200 Baud is supported by all MCU starting with
|
||||
the STC15 family, and at least the STC12C5A56S2 before that. For older
|
||||
MCU, you might have to use ```-b 19200``` for correct operation.
|
||||
|
||||
### 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:
|
||||
|
||||
* ```auto``` Automatic detection of UART based protocols (default)
|
||||
* ```stc89``` STC89/90 series
|
||||
* ```stc89a``` STC89/90 series (BSL 7.2.5C)
|
||||
* ```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``` STC8A8K64S4A12 and STC8F series
|
||||
* ```stc8d``` All STC8 and STC32 series
|
||||
* ```stc8g``` STC8G1 and STC8H1 series
|
||||
* ```usb15``` USB support on STC15W4 series
|
||||
|
||||
The text files in the doc/reverse-engineering 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!
|
||||
```
|
||||
|
||||
If the identification fails, see the [FAQ](FAQ.md) for troubleshooting.
|
||||
|
||||
### 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 4000 and 30000 kHz 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.
|
@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# This curious script dumps all model info from STC-ISP.
|
||||
# Data is directly read from the binary.
|
||||
# Offsets are for stc-isp-15xx-v6.85K.exe, sha1sum aa66e4c1ab49de27369b83c954a7c202acce0950
|
||||
|
||||
MCU_TABLE_OFFSET = 0x00064550
|
||||
MCU_TABLE_SIZE = 941
|
||||
MCU_RECORD_SIZE = 32
|
||||
MCU_NAMES_OFFSET = 0x0007e80c
|
||||
MCU_NAMES_PTR_OFFSET = 0x0047e80c
|
||||
|
||||
import struct
|
||||
import sys
|
||||
|
||||
inp = open(sys.argv[1], "rb")
|
||||
|
||||
for i in range(MCU_TABLE_SIZE):
|
||||
mcu_record_offset = MCU_TABLE_OFFSET + MCU_RECORD_SIZE * i
|
||||
inp.seek(mcu_record_offset)
|
||||
mcu_record = inp.read(MCU_RECORD_SIZE)
|
||||
flags, name_ptr, mcu_id, code_size, ee_size, _, total_size, _ = struct.unpack("<8I", mcu_record)
|
||||
mcu_id &= 0xffff
|
||||
|
||||
mcu_name_offset = MCU_NAMES_OFFSET + (name_ptr - MCU_NAMES_PTR_OFFSET)
|
||||
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.
|
||||
|
||||
# STC12x54xx always have 12 KB eeprom
|
||||
if name_str.startswith("STC12C54") or name_str.startswith("STC12LE54"):
|
||||
ee_size = 12 * 1024
|
||||
|
||||
print("MCUModel(name='%s', magic=0x%02x%02x, total=%d, code=%d, eeprom=%d)," %
|
||||
(name_str, mcu_id >> 8, mcu_id & 0xff, total_size, code_size, ee_size))
|
||||
|
||||
inp.close()
|
||||
|
484
doc/reverse-engineering/dump-mcu.c
Normal file
484
doc/reverse-engineering/dump-mcu.c
Normal file
@ -0,0 +1,484 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2022 Vincent DEFERT. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* This program automates the procedure explained below and generates
|
||||
* on the standard output the content of the 'models' list of models.py.
|
||||
*
|
||||
* It takes the name of the stc-isp executable as argument.
|
||||
*/
|
||||
/**
|
||||
* Manual procedure to read MCU definitions from a new STC-ISP executable
|
||||
* ========================================================================
|
||||
*
|
||||
* We want to extract 2 tables from the executable, one with MCU names and
|
||||
* the other with their characteristics, let's call them "Name Table" and
|
||||
* "Info Table" respectively.
|
||||
*
|
||||
* The Info Table appears first in the executable and contains references
|
||||
* to the MCU name in the Name Table. Each entry in the Name Table is 16
|
||||
* bytes long, 32 for the Info Table. New entries are prepended to the
|
||||
* Info Table, and appended to the Name Table. Of course, both have the
|
||||
* same number of entries.
|
||||
*
|
||||
* This means that the Name Table is very easy to locate, as well as the
|
||||
* end of the Info Table, but not its beginning, which must be calculated.
|
||||
*
|
||||
* Finally, the field of an Info Table entry that references the MCU name
|
||||
* is expressed as a memory address, not a file position, so we'll need to
|
||||
* determine the base memory address of the name table.
|
||||
*
|
||||
* 1. Dump the content of the executable in a text file.
|
||||
*
|
||||
* hexdump -C stc-isp-v6.89G.exe > stc-isp-v6.89G.txt
|
||||
*
|
||||
* 2. Locate the first entry of the Name Table.
|
||||
*
|
||||
* Search for the following byte sequence:
|
||||
* 53 54 43 39 30 4c 45 35 31 36 41 44 00 00 00 00
|
||||
* (i.e. nul-terminated "STC90LE516AD" string).
|
||||
*
|
||||
* Let's call this file position NTS (Name Table Start).
|
||||
*
|
||||
* 3. Locate the end of the Name Table.
|
||||
*
|
||||
* Search for the following byte sequence:
|
||||
* 55 4e 4b 4e 4f 57 4e 00 25 30 36 58 00 00 00 00
|
||||
* (i.e. nul-terminated "UNKNOWN" and "%06X" strings).
|
||||
*
|
||||
* Let's call this file position NTE (Name Table End).
|
||||
*
|
||||
* 4. Find the end of the Info Table.
|
||||
*
|
||||
* Search for the following byte sequence (fixed last entry):
|
||||
* 05 46 01 00 xx xx xx xx 90 f1 00 00 00 f8 00 00
|
||||
* 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00
|
||||
*
|
||||
* Bytes marked as 'xx' must be ignored while searching
|
||||
*
|
||||
* [Note: searching for '90 f1 00 00 00 f8 00 00' is sufficient.]
|
||||
*
|
||||
* It should be followed by 32 zeroed bytes. Let's call the file position
|
||||
* of the first zeroed byte ITE (Info Table End).
|
||||
*
|
||||
* 5. Find the beginning of the Info Table.
|
||||
*
|
||||
* The Info Table start with a block of 32 zeroed bytes except bytes
|
||||
* 4-7 which point at NTE, i.e. an info block pointing at the 'UNKNOWN'
|
||||
* MCU name. It's the only reliable way to determine the location of
|
||||
* the Info Table.
|
||||
*
|
||||
* Our first valid info block will thus be the offset of the Unknown
|
||||
* block + 32. Let's call this file position ITS (Info Table Start).
|
||||
*
|
||||
* 6. Calculate the number of MCU definitions (i.e. Info Table entries).
|
||||
*
|
||||
* NB_MCU = (ITE - ITS) / 32
|
||||
*
|
||||
* 7. Determine the base memory address of the name table.
|
||||
*
|
||||
* Let's suppose 'xx xx xx xx' is '9c f7 4a 00'. As it belongs to the Info
|
||||
* Table entry describing the first item of the Name Table, we directly
|
||||
* have what we're looking for, i.e. 0x004af79c.
|
||||
*
|
||||
* NTBA = littleEndianOf32bitUnsignedInt('xx xx xx xx')
|
||||
*
|
||||
* The index in the Name Table corresponding to a given Info Table item
|
||||
* is thus:
|
||||
*
|
||||
* NAME_IDX = (nameAddressFieldOfInfoTableItem - NTBA) / 0x10
|
||||
*
|
||||
* NOTE: for some reason, the Info Table entries of the STC08XE-3V and
|
||||
* STC08XE-5V each have 2 distinct mcuId, which gives 1115 Info Table
|
||||
* entries for 1113 strings in the Name Table.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Must be updated with the "UNKNOWN" name offset before use.
|
||||
static uint8_t infoTableStartSignature[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
// 0x90, 0xf1 is the magic number of the STC90LE516AD
|
||||
// We test only the last 24 byte of its 32-byte entry, as they are
|
||||
// sufficiently discriminating and do not depend on a particular
|
||||
// executable release.
|
||||
static const uint8_t infoTableEndSignature[] = {
|
||||
0x90, 0xf1, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
// NUL-terminated "STC90LE516AD" followed by 3 NUL bytes
|
||||
static const uint8_t nameTableStartSignature[] = {
|
||||
0x53, 0x54, 0x43, 0x39, 0x30, 0x4c, 0x45, 0x35,
|
||||
0x31, 0x36, 0x41, 0x44, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
// NUL-terminated "UNKNOWN" and "%06X" followed by 3 NUL bytes
|
||||
static const uint8_t nameTableEndSignature[] = {
|
||||
0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x00,
|
||||
0x25, 0x30, 0x36, 0x58, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t flags;
|
||||
uint32_t nameAddr;
|
||||
uint32_t mcuId;
|
||||
uint32_t flashSize;
|
||||
uint32_t eepromSize;
|
||||
uint32_t eepromStartAddr; // STC89 & STC90 only. 0 means IAP.
|
||||
uint32_t totalSize;
|
||||
uint32_t unknown2;
|
||||
} MCUInfo;
|
||||
|
||||
// Bit 1 is 1 for MCU which can accept 5V power supply voltage, be it
|
||||
// exclusively or not, and 0 for low-voltage only MCU (around 3.3V).
|
||||
#define FLAG_ACCEPT_5V_SUPPLY_VOLTAGE 0x00000002
|
||||
|
||||
// Bit 3 is 1 for so-called "IAP" MCU, meaning the start address of the
|
||||
// flash portion used for EEPROM emulation can be configured.
|
||||
#define FLAG_CONFIGURABLE_EEPROM_SIZE 0x00000008
|
||||
|
||||
// Bit 7 is 1 for MCU with an adjustable internal RC oscillator, i.e.
|
||||
// that supports calibration. When bits 7 and 8 are both 0, the MCU has
|
||||
// no IRCO at all (external crystal only).
|
||||
#define FLAG_CONFIGURABLE_IRCO_FREQ 0x00000080
|
||||
|
||||
// Bit 8 is 1 for MCU with a fixed-frequency internal RC oscillator
|
||||
// (the old IRC* models).
|
||||
#define FLAG_FIXED_FREQUENCY_IRCO 0x00000100
|
||||
|
||||
// Bit 12 is 1 for MCS-251 MCU, i.e. with a flash size that can be
|
||||
// larger than 64KB.
|
||||
#define FLAG_IS_MCS251_MCU 0x00001000
|
||||
|
||||
#define SEARCH_BUFFER_LEN 8192
|
||||
#define MCU_NAME_LEN 16
|
||||
|
||||
#define NO_MATCH -1
|
||||
#define FOUND -2
|
||||
|
||||
// May help to guess the meaning of new flags as they are added.
|
||||
|
||||
static void toBits(uint32_t n, char *result) {
|
||||
*result = '\0';
|
||||
int pos = 0;
|
||||
|
||||
for (uint32_t mask = 0x80000000; mask; mask >>= 1, pos++) {
|
||||
if (pos) {
|
||||
strcat(result, ",");
|
||||
}
|
||||
|
||||
if (n & mask) {
|
||||
strcat(result, "1");
|
||||
} else {
|
||||
strcat(result, "0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void printCSVHeader(FILE *csvFile) {
|
||||
if (csvFile != NULL) {
|
||||
fprintf(csvFile, "name,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,flags (hex),mcuId,flashSize,eepromSize,eepromStartAddr,totalSize,unknown2\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void printCSVRow(FILE *csvFile, const MCUInfo *info, const char *name) {
|
||||
char flags[64];
|
||||
|
||||
if (csvFile != NULL) {
|
||||
toBits(info->flags, flags);
|
||||
|
||||
fprintf(
|
||||
csvFile,
|
||||
"%s,%s,0x%08x,0x%04x,%u,%u,0x%08x,%u,0x%08x\n",
|
||||
name,
|
||||
flags,
|
||||
info->flags,
|
||||
(uint16_t) info->mcuId,
|
||||
info->flashSize,
|
||||
info->eepromSize,
|
||||
info->eepromStartAddr,
|
||||
info->totalSize,
|
||||
info->unknown2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *toBool(uint32_t flags, uint32_t mask) {
|
||||
return (flags & mask) ? "True" : "False";
|
||||
}
|
||||
|
||||
static void printMCUModel(const MCUInfo *info, const char *name) {
|
||||
printf(
|
||||
" MCUModel(name='%s', magic=0x%04x, total=%u, code=%u, eeprom=%u, iap=%s, calibrate=%s, mcs251=%s),\n",
|
||||
name,
|
||||
(uint16_t) info->mcuId,
|
||||
info->totalSize,
|
||||
info->flashSize,
|
||||
info->eepromSize,
|
||||
toBool(info->flags, FLAG_CONFIGURABLE_EEPROM_SIZE),
|
||||
toBool(info->flags, FLAG_CONFIGURABLE_IRCO_FREQ),
|
||||
toBool(info->flags, FLAG_IS_MCS251_MCU)
|
||||
);
|
||||
}
|
||||
|
||||
static void printUsage(const char *pgmName) {
|
||||
printf("Usage: %s <STC-ISP_executable> [<CSV_output_file>]\n", pgmName);
|
||||
printf("\n");
|
||||
printf("- STC-ISP_executable is the file from which MCU models must be extracted.\n");
|
||||
printf("Their list will be printed on the standard output.\n");
|
||||
printf("\n");
|
||||
printf("- The optional CSV_output_file will receive the MCU flags detail of each model\n");
|
||||
printf("to facilitate reverse engineering efforts.\n");
|
||||
printf("\n");
|
||||
printf("Example: %s stc-isp-v6.91Q.exe MCUFlags.csv > MCUModels.txt\n", pgmName);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
int rc = 1;
|
||||
MCUInfo *infoTable = NULL;
|
||||
char *nameTable = NULL;
|
||||
int mcuCount = 0;
|
||||
uint32_t infoTableStartOffset = 0;
|
||||
uint32_t infoTableEndOffset = 0;
|
||||
uint32_t nameTableStartOffset = 0;
|
||||
uint32_t nameTableEndOffset = 0;
|
||||
uint32_t baseAddr = 0;
|
||||
int nameTableSize = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "ERROR: missing argument\n");
|
||||
printUsage(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
FILE *exeFile = fopen(argv[1], "rb");
|
||||
FILE *csvFile = NULL;
|
||||
|
||||
if (exeFile != NULL) {
|
||||
if (argc > 2) {
|
||||
csvFile = fopen(argv[2], "wt");
|
||||
}
|
||||
|
||||
rc = 2;
|
||||
uint8_t *buffer = (uint8_t *) malloc(SEARCH_BUFFER_LEN);
|
||||
|
||||
if (buffer != NULL) {
|
||||
rc = 3;
|
||||
int infoTableEndMatch = NO_MATCH;
|
||||
int nameTableStartMatch = NO_MATCH;
|
||||
int nameTableEndMatch = NO_MATCH;
|
||||
uint32_t fileOffset = 0;
|
||||
int bytesRead = 0;
|
||||
|
||||
while ((bytesRead = fread(buffer, 1, SEARCH_BUFFER_LEN, exeFile)) != 0) {
|
||||
for (int curByte = 0; curByte < SEARCH_BUFFER_LEN; curByte++) {
|
||||
int noMatch = 1;
|
||||
|
||||
if (infoTableEndMatch > NO_MATCH) {
|
||||
if (infoTableEndSignature[infoTableEndMatch + 1] == buffer[curByte]) {
|
||||
infoTableEndMatch++;
|
||||
noMatch = 0;
|
||||
|
||||
if (infoTableEndMatch == (sizeof(infoTableEndSignature) -1)) {
|
||||
infoTableEndMatch = FOUND;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
infoTableEndMatch = NO_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
if (nameTableStartMatch > NO_MATCH) {
|
||||
if (nameTableStartSignature[nameTableStartMatch + 1] == buffer[curByte]) {
|
||||
nameTableStartMatch++;
|
||||
noMatch = 0;
|
||||
|
||||
if (nameTableStartMatch == (sizeof(nameTableStartSignature) -1)) {
|
||||
nameTableStartMatch = FOUND;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
nameTableStartMatch = NO_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
if (nameTableEndMatch > NO_MATCH) {
|
||||
if (nameTableEndSignature[nameTableEndMatch + 1] == buffer[curByte]) {
|
||||
nameTableEndMatch++;
|
||||
noMatch = 0;
|
||||
|
||||
if (nameTableEndMatch == (sizeof(nameTableEndSignature) - 1)) {
|
||||
nameTableEndMatch = FOUND;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
nameTableEndMatch = NO_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
if (noMatch) {
|
||||
if (infoTableEndMatch == NO_MATCH && infoTableEndSignature[0] == buffer[curByte]) {
|
||||
infoTableEndMatch = 0;
|
||||
infoTableEndOffset = fileOffset + curByte;
|
||||
} else if (nameTableStartMatch == NO_MATCH && nameTableStartSignature[0] == buffer[curByte]) {
|
||||
nameTableStartMatch = 0;
|
||||
nameTableStartOffset = fileOffset + curByte;
|
||||
} else if (nameTableEndMatch == NO_MATCH && nameTableEndSignature[0] == buffer[curByte]) {
|
||||
nameTableEndMatch = 0;
|
||||
nameTableEndOffset = fileOffset + curByte;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (infoTableEndMatch == FOUND && nameTableStartMatch == FOUND && nameTableEndMatch == FOUND) {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
fileOffset += SEARCH_BUFFER_LEN;
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
// Point to the byte immediately following the table's last entry.
|
||||
infoTableEndOffset += sizeof(infoTableEndSignature);
|
||||
// Read last item of Info Table
|
||||
fseek(exeFile, infoTableEndOffset - sizeof(MCUInfo), SEEK_SET);
|
||||
MCUInfo lastItem;
|
||||
fread(&lastItem, sizeof(MCUInfo), 1, exeFile);
|
||||
// We need it now in order to calculate the memory address
|
||||
// corresponding to the UNKNOWN name.
|
||||
// We'll also need baseAddr later, anyway.
|
||||
baseAddr = lastItem.nameAddr;
|
||||
|
||||
rc = 4;
|
||||
int infoTableStartMatch = NO_MATCH;
|
||||
uint32_t fileOffset = 0;
|
||||
int bytesRead = 0;
|
||||
*((uint32_t *)(infoTableStartSignature)) = (baseAddr - nameTableStartOffset) + nameTableEndOffset;
|
||||
fseek(exeFile, 0, SEEK_SET);
|
||||
|
||||
while ((bytesRead = fread(buffer, 1, SEARCH_BUFFER_LEN, exeFile)) != 0) {
|
||||
for (int curByte = 0; curByte < SEARCH_BUFFER_LEN; curByte++) {
|
||||
if (infoTableStartMatch > NO_MATCH) {
|
||||
if (infoTableStartSignature[infoTableStartMatch + 1] == buffer[curByte]) {
|
||||
infoTableStartMatch++;
|
||||
|
||||
if (infoTableStartMatch == (sizeof(infoTableStartSignature) - 1)) {
|
||||
infoTableStartMatch = FOUND;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
infoTableStartMatch = NO_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
if (infoTableStartMatch == NO_MATCH && infoTableStartSignature[0] == buffer[curByte]) {
|
||||
infoTableStartMatch = 0;
|
||||
infoTableStartOffset = fileOffset + curByte;
|
||||
}
|
||||
}
|
||||
|
||||
if (infoTableStartMatch == FOUND) {
|
||||
// Point to the first entry following the Unknown one.
|
||||
infoTableStartOffset += sizeof(MCUInfo) - 4;
|
||||
// Calculate number of entries while we're at it
|
||||
mcuCount = (infoTableEndOffset - infoTableStartOffset) / sizeof(MCUInfo);
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
fileOffset += SEARCH_BUFFER_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
if (rc == 0) {
|
||||
nameTableSize = nameTableEndOffset - nameTableStartOffset;
|
||||
|
||||
nameTable = (char *) malloc(nameTableSize);
|
||||
|
||||
if (nameTable == NULL) {
|
||||
rc = 5;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
fseek(exeFile, nameTableStartOffset, SEEK_SET);
|
||||
fread(nameTable, nameTableSize, 1, exeFile);
|
||||
|
||||
infoTable = (MCUInfo *) malloc(infoTableEndOffset - infoTableStartOffset);
|
||||
|
||||
if (infoTable != NULL) {
|
||||
fseek(exeFile, infoTableStartOffset, SEEK_SET);
|
||||
fread(infoTable, infoTableEndOffset - infoTableStartOffset, 1, exeFile);
|
||||
|
||||
} else {
|
||||
rc = 6;
|
||||
free(nameTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(exeFile);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
printCSVHeader(csvFile);
|
||||
|
||||
for (int mcu = 0; mcu < mcuCount; mcu++) {
|
||||
const char *mcuName = &nameTable[infoTable[mcu].nameAddr - baseAddr];
|
||||
|
||||
if (strncmp(mcuName, "STC12C54", 8) == 0 || strncmp(mcuName, "STC12LE54", 9) == 0) {
|
||||
// STC12x54xx always have 12KB EEPROM
|
||||
infoTable[mcu].eepromSize = 12 * 1024;
|
||||
}
|
||||
|
||||
printCSVRow(csvFile, &infoTable[mcu], mcuName);
|
||||
printMCUModel(&infoTable[mcu], mcuName);
|
||||
}
|
||||
|
||||
free(infoTable);
|
||||
free(nameTable);
|
||||
}
|
||||
|
||||
if (csvFile != NULL) {
|
||||
fclose(csvFile);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
BIN
doc/reverse-engineering/mcu-flags-meaning.ods
Normal file
BIN
doc/reverse-engineering/mcu-flags-meaning.ods
Normal file
Binary file not shown.
BIN
doc/reverse-engineering/mcu-models+flags.ods
Normal file
BIN
doc/reverse-engineering/mcu-models+flags.ods
Normal file
Binary file not shown.
57
doc/reverse-engineering/mcudb_flags.txt
Normal file
57
doc/reverse-engineering/mcudb_flags.txt
Normal file
@ -0,0 +1,57 @@
|
||||
STC15F103
|
||||
00064F50 63 C3 08 00 2C FC 47 00 9B F2 00 00 00 0C 00 00 c...,.G.........
|
||||
00064F60 00 08 00 00 00 00 00 00 00 20 00 00 07 03 00 00 ......... ......
|
||||
|
||||
STC15L103
|
||||
00065110 61 C3 08 00 90 FB 47 00 DB F2 00 00 00 0C 00 00 a.....G.........
|
||||
00065120 00 08 00 00 00 00 00 00 00 20 00 00 07 03 00 00 ......... ......
|
||||
|
||||
STC15F104E
|
||||
00065190 E3 02 08 00 AC B1 47 00 94 F2 00 00 00 10 00 00 ......G.........
|
||||
000651A0 00 04 00 00 00 00 00 00 00 20 00 00 07 00 00 00 ......... ......
|
||||
|
||||
STC15L104W
|
||||
X Y Z
|
||||
00065050 E1 C3 08 00 B8 B1 47 00 D4 F2 00 00 00 10 00 00 ......G.........
|
||||
00065060 00 04 00 00 00 00 00 00 00 20 00 00 07 03 00 00 ......... ......
|
||||
|
||||
STC15L104E
|
||||
000651B0 E1 02 08 00 94 B1 47 00 D4 F2 00 00 00 10 00 00 ......G.........
|
||||
000651C0 00 04 00 00 00 00 00 00 00 20 00 00 07 00 00 00 ......... ......
|
||||
|
||||
|
||||
byte X bit 1: F vs L? low => L part, high => F part
|
||||
byte Z: protocol/model generation number?
|
||||
|
||||
IAP15F2K61S2
|
||||
00063750 AF 0B 09 00 08 06 48 00 49 F4 00 00 00 F4 00 00 ......H.I.......
|
||||
00063760 00 00 00 00 00 00 00 00 00 00 01 00 07 00 00 00 ................
|
||||
|
||||
STC15F2K08S2
|
||||
00063650 A3 0B 09 00 78 06 48 00 01 F4 00 00 00 20 00 00 ....x.H...... ..
|
||||
00063660 00 D4 00 00 00 00 00 00 00 00 01 00 07 00 00 00 ................
|
||||
|
||||
STC15F2K32S2
|
||||
000636B0 A3 0B 09 00 48 06 48 00 04 F4 00 00 00 80 00 00 ....H.H.........
|
||||
000636C0 00 74 00 00 00 00 00 00 00 00 01 00 07 00 00 00 .t..............
|
||||
|
||||
STC15F2K60S2
|
||||
00063730 A3 0B 09 00 64 B2 47 00 08 F4 00 00 00 F0 00 00 ....d.G.........
|
||||
00063740 00 04 00 00 00 00 00 00 00 00 01 00 07 00 00 00 ................
|
||||
|
||||
IRC15F2K63S2
|
||||
00063770 BF 0C 09 00 F8 05 48 00 4A F4 00 00 00 FE 00 00 ......H.J.......
|
||||
00063780 00 00 00 00 00 00 00 00 00 00 01 00 07 00 00 00 ................
|
||||
|
||||
IRC15F1K63S
|
||||
00064470 BE 8C 09 00 20 00 48 00 20 F4 00 00 00 FE 00 00 .... .H. .......
|
||||
00064480 00 00 00 00 00 00 00 00 00 00 01 00 07 00 00 00 ................
|
||||
|
||||
IRC15W207S
|
||||
000648B0 B7 CC 0A 00 AC FE 47 00 56 F5 00 00 00 1E 00 00 ......G.V.......
|
||||
000648C0 00 00 00 00 00 00 00 00 00 20 00 00 07 00 00 00 ......... ......
|
||||
|
||||
STC15H4K56S4
|
||||
00063610 AF 8B 0E 00 98 06 48 00 07 F6 00 00 00 E0 00 00 ......H.........
|
||||
00063620 00 00 00 00 00 00 00 00 00 00 01 00 07 00 00 00 ................
|
||||
|
46
doc/reverse-engineering/stc15-usb-protocol.txt
Normal file
46
doc/reverse-engineering/stc15-usb-protocol.txt
Normal file
@ -0,0 +1,46 @@
|
||||
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
|
||||
|
108
doc/reverse-engineering/stc15w4.txt
Normal file
108
doc/reverse-engineering/stc15w4.txt
Normal file
@ -0,0 +1,108 @@
|
||||
fresh chip, RC frequency untuned, caught with stcgal
|
||||
|
||||
2015-12-10 23:39:46.886233: PC
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
2015-12-10 23:39:50.989044: MCU
|
||||
46 B9 68 00 34 50 8D FF 73 96 F5 7B 9F FF FF FF
|
||||
FF FF 25 EF 00 00 73 54 00 F5 28 04 06 70 96 02
|
||||
15 19 1C 1E 23 00 EC E0 04 D7 F8 73 BF FF FF 15
|
||||
09 25 60 16 92 16
|
||||
2015-12-10 23:39:51.231028: PC
|
||||
46 B9 6A 00 07 82 00 F3 16
|
||||
|
||||
Checking target MCU ...
|
||||
MCU type: STC15W4K56S4
|
||||
F/W version: 7.3.4T
|
||||
|
||||
Current H/W Option:
|
||||
. Current system clock source is internal IRC oscillator
|
||||
. IRC is unadjusted
|
||||
. Oscillator gain is HIGH
|
||||
. Wakeup Timer frequency: 36.351KHz
|
||||
. Do not detect the level of P3.2 and P3.3 next download
|
||||
. Power-on reset, use the extra power-on delay
|
||||
. RESET pin behaves as I/O pin
|
||||
. Interrupt while detect a Low-Voltage
|
||||
. Thresh voltage level of the built-in LVD : 2.78 V
|
||||
. Permit EEPROM operation under Low-Voltag
|
||||
. CPU-Core supply level : 3.38 V
|
||||
. Hardware do not enable Watch-Dog-Timer
|
||||
. Watch-Dog-Timer pre-scalar : 64
|
||||
. Watch-Dog-Timer stop count in idle mode
|
||||
. Program can modify the Watch-Dog-Timer scalar
|
||||
. Erase user EEPROM area at next download
|
||||
. Do not control 485 at next download
|
||||
. Do not check user password next download
|
||||
. TXD is independent IO
|
||||
. TXD pin as quasi-bidirectional mode after reset
|
||||
. P2.0 output HIGH level after reset
|
||||
|
||||
. MCU type: STC15W4K56S4
|
||||
F/W version: 7.3.4T
|
||||
|
||||
Complete !
|
||||
|
||||
Waiting for MCU, please cycle power: done
|
||||
Target model:
|
||||
Name: STC15W4K56S4
|
||||
Magic: F528
|
||||
Code flash: 56.0 KB
|
||||
EEPROM flash: 3.0 KB
|
||||
Target frequency: 0.000 MHz
|
||||
Target BSL version: 7.3.4T
|
||||
Target wakeup frequency: 36.351 KHz
|
||||
Target options:
|
||||
reset_pin_enabled=False
|
||||
clock_source=internal
|
||||
clock_gain=high
|
||||
watchdog_por_enabled=False
|
||||
watchdog_stop_idle=True
|
||||
watchdog_prescale=64
|
||||
low_voltage_reset=False
|
||||
low_voltage_threshold=3
|
||||
eeprom_lvd_inhibit=False
|
||||
eeprom_erase_enabled=True
|
||||
bsl_pindetect_enabled=False
|
||||
por_reset_delay=long
|
||||
rstout_por_state=high
|
||||
uart2_passthrough=False
|
||||
uart2_pin_mode=normal
|
||||
Disconnected!
|
||||
|
||||
|
||||
cpu core supply level
|
||||
|
||||
2.68v
|
||||
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 7A C0 FD 27 ED 00 00 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 EA 92 FF FF FF 15 09 25 60 14 BD 16
|
||||
|
||||
3.33v
|
||||
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 92 30 FD 25 EA 00 FC 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 F7 92 FF FF FF 15 09 25 60 15 49 16
|
||||
|
||||
3.63v
|
||||
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 7A C0 FD 25 EF 00 00 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 FD 92 FF FF FF 15 09 25 60 14 D0 16
|
||||
|
||||
3.73v
|
||||
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 92 30 FD 25 EA 00 00 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 FF 92 FF FF FF 15 09 25 60 14 55 16
|
||||
^^
|
||||
core voltage
|
||||
voltage: ff -> 3.73v
|
||||
fd -> 3.63v
|
||||
f7 -> 3.33v
|
||||
ea -> 2.68v
|
||||
|
32
doc/reverse-engineering/stc8-new.txt
Normal file
32
doc/reverse-engineering/stc8-new.txt
Normal file
@ -0,0 +1,32 @@
|
||||
Cycling power: done
|
||||
Waiting for MCU: <- Packet data: 46 B9 68 00 30 50 FF FF FF FF 8F 00 04 FF FF 8B FD FF 27 3E F5 73 73 55 00 F6 41 0A 88 86 6F 8F 08 20 20 20 01 00 00 20 05 3C 18 05 22 32 FF 12 18 16
|
||||
-> Packet data: 46 B9 6A 00 07 FF 01 70 16
|
||||
done
|
||||
Target model:
|
||||
Name: STC8F2K08S2
|
||||
Magic: F641
|
||||
Code flash: 8.0 KB
|
||||
EEPROM flash: 56.0 KB
|
||||
Target frequency: 0.000 MHz
|
||||
Target BSL version: 7.3.10U
|
||||
Target wakeup frequency: 34.950 KHz
|
||||
Target ref. voltage: 1340 mV
|
||||
Target mfg. date: 2018-05-22
|
||||
Target options:
|
||||
reset_pin_enabled=False
|
||||
clock_gain=high
|
||||
watchdog_por_enabled=False
|
||||
watchdog_stop_idle=True
|
||||
watchdog_prescale=64
|
||||
low_voltage_reset=False
|
||||
low_voltage_threshold=2
|
||||
eeprom_erase_enabled=True
|
||||
bsl_pindetect_enabled=False
|
||||
por_reset_delay=long
|
||||
rstout_por_state=high
|
||||
uart1_remap=False
|
||||
uart2_passthrough=False
|
||||
uart2_pin_mode=normal
|
||||
epwm_open_drain=False
|
||||
program_eeprom_split=29440
|
||||
Disconnected!
|
71
doc/reverse-engineering/stc8-options.txt
Normal file
71
doc/reverse-engineering/stc8-options.txt
Normal file
@ -0,0 +1,71 @@
|
||||
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: ?
|
138
doc/reverse-engineering/stc8-protocol.txt
Normal file
138
doc/reverse-engineering/stc8-protocol.txt
Normal file
@ -0,0 +1,138 @@
|
||||
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.
|
80
doc/reverse-engineering/stc89a-c52rc.txt
Normal file
80
doc/reverse-engineering/stc89a-c52rc.txt
Normal file
@ -0,0 +1,80 @@
|
||||
001046: Read (UP): 2021-01-09 15:37:44.9125552 +0.0085328
|
||||
46 b9 68 00 29 50 fd 84 1e 11 4d 05 8e 96 27 7c F.h.)P....M...'|
|
||||
^
|
||||
cpu_6t
|
||||
04 47 01 7f 40 81 72 43 00 f0 51 05 80 00 ff ff .G..@.rC..Q.....
|
||||
^ ^ ^ ^
|
||||
freq_counte | | |
|
||||
bl_version |
|
||||
bl_stepping |
|
||||
bl_minor
|
||||
|
||||
|
||||
ff ff 38 20 20 02 19 60 0d a0 16 ..8 ..`...
|
||||
|
||||
|
||||
001057: Write (DOWN): 2021-01-09 15:37:44.9814096 +0.0129872
|
||||
46 b9 6a 00 0a 01 ff fd 82 02 f3 16 F.j.........
|
||||
^
|
||||
handshake
|
||||
|
||||
|
||||
001072: Read (UP): 2021-01-09 15:37:45.0836096 +0.0115168
|
||||
46 b9 68 00 07 01 00 70 16 F.h....p.
|
||||
|
||||
001113: Write (DOWN): 2021-01-09 15:37:45.1352048 +0.0171904
|
||||
46 b9 6a 00 0b 05 00 00 46 b9 01 79 16 F.j.....F..y.
|
||||
^
|
||||
ping-pong
|
||||
|
||||
|
||||
001116: Read (UP): 2021-01-09 15:37:45.1392768 +0.0017200
|
||||
46 b9 68 00 07 05 00 74 16 F.h....t.
|
||||
|
||||
|
||||
001127: Write (DOWN): 2021-01-09 15:37:45.1502464 +0.0109472
|
||||
46 b9 6a 00 0b 03 00 00 46 b9 01 77 16 F.j.....F..w.
|
||||
^
|
||||
erase_flash ?
|
||||
|
||||
|
||||
001170: Read (UP): 2021-01-09 15:37:45.4729040 +0.0099696
|
||||
46 b9 68 00 0e 03 f0 51 c5 f2 06 7c 14 04 07 16 F.h....Q...|....
|
||||
^
|
||||
mcu id
|
||||
|
||||
|
||||
001181: Write (DOWN): 2021-01-09 15:37:45.4791856 +0.0062576
|
||||
46 b9 6a 00 8b 32 00 00 46 b9 02 00 08 12 00 3f F.j..2..F......?
|
||||
^ ^
|
||||
write address
|
||||
write data
|
||||
80 fe 75 81 07 12 00 4c e5 82 60 03 02 00 03 e4 ..u....L..`.....
|
||||
78 ff f6 d8 fd 02 00 03 ae 82 af 83 8e 04 8f 05 x...............
|
||||
1e be ff 01 1f ec 4d 60 0f 7c 90 7d 01 1c bc ff ......M`.|.}....
|
||||
01 1d ec 4d 70 f7 80 e4 22 90 03 e8 12 00 1e e5 ...Mp...".......
|
||||
80 f4 f5 80 80 f3 75 82 00 22 ff ff ff ff ff ff ......u.."......
|
||||
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
|
||||
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
|
||||
ff ff ff ff ff ff ff ff ff ff 52 f9 16 ..........R..
|
||||
|
||||
|
||||
001188: Read (UP): 2021-01-09 15:37:45.5301744 +0.0047088
|
||||
46 b9 68 00 08 02 54 00 c6 16 F.h...T...
|
||||
^
|
||||
write done
|
||||
|
||||
|
||||
001199: Write (DOWN): 2021-01-09 15:37:45.5575264 +0.0273248
|
||||
46 b9 6a 00 0c 04 00 00 46 b9 fd 02 76 16 F.j.....F...v.
|
||||
^
|
||||
write msr
|
||||
|
||||
|
||||
001202: Read (UP): 2021-01-09 15:37:45.5625296 +0.0018304
|
||||
46 b9 68 00 08 04 54 00 c8 16 F.h...T...
|
||||
unknown
|
||||
|
||||
001213: Write (DOWN): 2021-01-09 15:37:45.5712992 +0.0087472
|
||||
46 b9 6a 00 07 ff 01 70 16 F.j....p.
|
||||
unknown
|
35
doc/reverse-engineering/untrimmed.txt
Normal file
35
doc/reverse-engineering/untrimmed.txt
Normal file
@ -0,0 +1,35 @@
|
||||
Cycling power: done
|
||||
Waiting for MCU: done
|
||||
Protocol detected: stc8
|
||||
Target model:
|
||||
Name: STC8F2K08S2
|
||||
Magic: F641
|
||||
Code flash: 8.0 KB
|
||||
EEPROM flash: 56.0 KB
|
||||
Target frequency: 0.000 MHz
|
||||
Target BSL version: 7.3.10U
|
||||
Target wakeup frequency: 34.950 KHz
|
||||
Target ref. voltage: 1340 mV
|
||||
Target mfg. date: 2018-05-22
|
||||
Target options:
|
||||
reset_pin_enabled=False
|
||||
clock_gain=high
|
||||
watchdog_por_enabled=False
|
||||
watchdog_stop_idle=True
|
||||
watchdog_prescale=64
|
||||
low_voltage_reset=False
|
||||
low_voltage_threshold=2
|
||||
eeprom_erase_enabled=True
|
||||
bsl_pindetect_enabled=False
|
||||
por_reset_delay=long
|
||||
rstout_por_state=high
|
||||
uart1_remap=False
|
||||
uart2_passthrough=False
|
||||
uart2_pin_mode=normal
|
||||
epwm_open_drain=False
|
||||
program_eeprom_split=29440
|
||||
Loading flash: 80 bytes (Intel HEX)
|
||||
<- Packet data: 46 B9 68 00 30 50 FF FF FF FF 8F 00 04 FF FF 8B FD FF 27 38 F5 73 73 55 00 F6 41 0A 88 86 6F 8F 08 20 20 20 01 00 00 20 05 3C 18 05 22 32 FF 12 12 16
|
||||
Protocol error: uncalibrated, please provide a trim value
|
||||
-> Packet data: 46 B9 6A 00 07 FF 01 70 16
|
||||
Disconnected!
|
84
doc/zh_CN/FAQ.md
Normal file
84
doc/zh_CN/FAQ.md
Normal file
@ -0,0 +1,84 @@
|
||||
文档说明 Explanation
|
||||
------------------------
|
||||
此文档翻译自FAQ.md
|
||||
|
||||
This document was translated from FAQ.md
|
||||
|
||||
最后修改时间:2020年6月8日
|
||||
|
||||
Last modified time: June 8, 2020
|
||||
|
||||
常见问题
|
||||
======================================
|
||||
|
||||
### 问题1:是否可以从芯片中读取代码(或EEPROM)存储器?
|
||||
|
||||
从设计上讲,这是STC的引导加载程序协议无法实现的。 STC将此视为安全功能。目前没有已知的解决方法。有关更多详细信息和讨论,请参见问题7。
|
||||
|
||||
### 问题2:哪些串行接口已通过stcgal测试过?
|
||||
|
||||
stcgal应该可以与波特率为16550的UART兼容。
|
||||
但是,如今,基于USB模拟的UART是典型的情况。
|
||||
以下是已通过stcgal成功测试的USB模拟UART接口芯片:
|
||||
|
||||
* FT232系列(操作系统:Linux,Windows)
|
||||
* CH340 / CH341(操作系统:Windows,Linux需要内核4.10)
|
||||
* PL2303(操作系统:Windows,Linux)
|
||||
* CP2102(操作系统:Windows,Linux,macOS)
|
||||
|
||||
已知不起作用的接口:
|
||||
|
||||
* Raspberry Pi Mini UART(缺少奇偶校验支持,请启用PL011 UART)
|
||||
|
||||
### 问题3:stcgal 启动失败同时显示 `module 'serial' has no attribute 'PARITY_NONE'` 等类似信息
|
||||
|
||||
PyPI软件包“ serial”(数据序列库)和PyPI软件包“ pyserial”(stcgal所需的串行端口访问库)之间存在模块名称冲突。
|
||||
您必须卸载'serial'软件包(`pip3 uninstall serial`)并重新安装'pyserial'(`pip3 install --force-reinstall pyserial`)才能解决此问题。
|
||||
目前没有其他已知的解决方案。
|
||||
|
||||
### 问题4:stcgal无法识别MCU,并停留在“Waiting for MCU”中
|
||||
|
||||
有许多问题可能导致此症状:
|
||||
* 电气问题和错误连接。确保正确连接了RX / TX,GND和VCC。
|
||||
如果您不使用自动复位功能,还应确保仅在stcgal启动后才接通电源,因为引导加载程序仅在上电复位时被调用。
|
||||
* 通过I / O引脚供电。
|
||||
即使未连接VCC,也可以通过I / O引脚(例如RX / TX)为MCU供电。
|
||||
在这种情况下,上电复位逻辑不起作用。请参阅下一个问题。
|
||||
* erial接口不兼容。由于各种原因,一些基于USB的UART与STC MCU的兼容性很差。
|
||||
您可以尝试使用选项`-l 1200`将握手波特率从标准2400波特降低到1200波特,在某些情况下可以解决这些问题。
|
||||
|
||||
### 问题5:如何避免MCU从I/O引脚供电?
|
||||
可以采取各种补救措施来避免MCU从I/O引脚供电。
|
||||
* 您可以尝试在MCU VCC和GND之间连接一个电阻(<1k),以使注入的电源短路,并希望将电压降至欠压值以下。
|
||||
* 另一种选择是在可能注入功率的I / O线上插入串联电阻。例如,在RX / TX线上尝试一个类似1k的值。
|
||||
* 还有另一种可能性是切换GND而不是VCC。
|
||||
在大多数情况下,这应该是一个相当可靠的解决方案。
|
||||
|
||||
### 问题6:RC频率调整失败
|
||||
首先,请确保指定的频率使用正确的单位。频率以kHz为单位指定,安全范围约为5000 kHz-30000 kHz。
|
||||
此外,频率调整使用UART时钟作为时钟参考,因此UART不兼容或时钟不准确也会导致频率调整问题。如果可能的话,
|
||||
尝试另一个UART芯片。
|
||||
|
||||
### 问题7:波特率切换失败或闪存编程失败
|
||||
特别是在高编程波特率,例如, 115200波特。尝试降低波特率,或使用默认的19200波特率。
|
||||
某些USB UART也会由于时序不正确而引起问题,这可能会导致各种问题。
|
||||
|
||||
### 问题8:如何使用自动重置功能?
|
||||
标准自动重置功能的工作原理与Arduino类似。 DTR是低电平有效信号,在stcgal启动时置位500 ms,然后在其余的编程序列中置为无效。
|
||||
在标准USB UART上,这将导致500 ms的低脉冲,然后是高相位。 stcgal作者推荐以下电路:
|
||||
```
|
||||
VCC --o o-- MCU GND
|
||||
| |
|
||||
.-. |
|
||||
| | 1k |
|
||||
| | |
|
||||
'_' |
|
||||
| |
|
||||
| ||-+
|
||||
DTR --o --||<- BS170/BSS138
|
||||
||-| (N-CH MOSFET)
|
||||
|
|
||||
|
|
||||
GND ---------o
|
||||
```
|
||||
该电路使用一个N沟道MOSFET作为开关来切换MCU的GND。 VCC直接连接。这避免了寄生供电问题。上拉电阻可确保在DTR输入悬空时接通MCU。
|
24
doc/zh_CN/INSTALL.md
Normal file
24
doc/zh_CN/INSTALL.md
Normal file
@ -0,0 +1,24 @@
|
||||
文档说明 Explanation
|
||||
------------------------
|
||||
此文档翻译自INSTALL.md
|
||||
|
||||
This document was translated from INSTALL.md
|
||||
|
||||
最后修改时间:2020年6月8日
|
||||
|
||||
Last modified time: June 8, 2020
|
||||
|
||||
安装说明
|
||||
============
|
||||
|
||||
stcgal需要Python 3.2(或更高版本),pyserial 3.0或更高版本以及TQDM 4.0.0或更高版本。
|
||||
USB支持是可选的,并且需要pyusb 1.0.0b2或更高版本。如果已经安装了依赖项,则可以使用包含的
|
||||
```stcgal.py``` 脚本直接运行stcgal。
|
||||
|
||||
永久安装有几种选择:
|
||||
|
||||
* 使用Python3和```pip```。运行```pip3 install stcgal```
|
||||
在系统上全局安装最新版本的stcgal。
|
||||
这可能需要管理员/ root用户权限才能进行写到系统目录。
|
||||
|
||||
* 使用setuptools。运行`./setup.py build`来构建,并运行'sudo ./setup.py install`'来安装stcgal。
|
65
doc/zh_CN/MODELS.md
Normal file
65
doc/zh_CN/MODELS.md
Normal file
@ -0,0 +1,65 @@
|
||||
文档说明 Explanation
|
||||
------------------------
|
||||
此文档翻译自MODELS.md
|
||||
|
||||
This document was translated from MODELS.md
|
||||
|
||||
最后修改时间:2020年6月8日
|
||||
|
||||
Last modified time: June 8, 2020
|
||||
|
||||
支持的MCU型号
|
||||
====================
|
||||
|
||||
stcgal理论上完全支持STC 89/90/10/11/12/15/8/32系列MCU。
|
||||
|
||||
到目前为止,stcgal已使用以下MCU模型进行了测试:
|
||||
|
||||
89/90系列
|
||||
* STC89C52RC (BSL 版本: 4.3C/6.6C)
|
||||
* STC89C54RD+ (BSL 版本: 4.3C)
|
||||
* STC90C52RC (BSL 版本: 4.3C)
|
||||
* STC90C58RD+ (BSL 版本: 4.3C)
|
||||
|
||||
STC12C系列
|
||||
* STC12C2052 (BSL 版本: 5.8D)
|
||||
* STC12C2052AD (BSL 版本: 5.8D)
|
||||
* STC12C5608AD (BSL 版本: 6.0G)
|
||||
* STC12C5A16S2 (BSL 版本: 6.2I)
|
||||
* STC12C5A60S2 (BSL 版本: 6.2I/7.1I)
|
||||
* STC12C5204AD (BSL 版本: 6.6H)
|
||||
|
||||
10/11系列价格
|
||||
* STC10F04XE (BSL 版本: 6.5J)
|
||||
* STC11F02E (BSL 版本: 6.5K)
|
||||
* STC11F08XE (BSL 版本: 6.5M)
|
||||
|
||||
STC15系列
|
||||
* STC15F104E (BSL 版本: 6.7Q)
|
||||
* STC15F204EA (BSL 版本: 6.7R)
|
||||
* STC15L104W (BSL 版本: 7.1.4Q)
|
||||
* STC15F104W (BSL 版本: 7.1.4Q)
|
||||
* IAP15F2K61S2 (BSL 版本: 7.1.4S)
|
||||
* STC15L2K16S2 (BSL 版本: 7.2.4S)
|
||||
* IAP15L2K61S2 (BSL 版本: 7.2.5S)
|
||||
* STC15W408AS (BSL 版本: 7.2.4T 和 7.2.5T)
|
||||
* STC15W4K56S4 (BSL 版本: 7.3.4T 和 7.3.7T, UART and USB mode)
|
||||
|
||||
STC8系列
|
||||
* STC8A8K64S4A12 (BSL 版本: 7.3.9U 和 7.3.12U)
|
||||
* STC8F2K08S2 (BSL 版本: 7.3.10U)
|
||||
* STC8A8K64D4 (BSL 版本: 7.4.2U)
|
||||
* STC8G1K08A-8PIN (BSL 版本: 7.3.12U)
|
||||
* STC8G1K08-20/16PIN (BSL 版本: 7.3.12U)
|
||||
* STC8G1K17-20/16PIN (BSL 版本: 7.3.12U)
|
||||
* STC8G2K64S4 (BSL 版本: 7.3.11U)
|
||||
* STC8H1K08 (BSL 版本: 7.3.12U)
|
||||
* STC8H3K64S2 (BSL 版本: 7.4.1U)
|
||||
* STC8H3K64S4 (BSL 版本: 7.4.1U)
|
||||
* STC8H4K64TL (BSL 版本: 7.4.3U)
|
||||
* STC8H8K64U (BSL 版本: 7.4.4U)
|
||||
|
||||
STC32系列
|
||||
* STC32G12K128-Beta (BSL 版本: 7.4.4U)
|
||||
|
||||
欢迎提供兼容性报告,无论是负面的还是正面的。
|
22
doc/zh_CN/PyPI.md
Normal file
22
doc/zh_CN/PyPI.md
Normal file
@ -0,0 +1,22 @@
|
||||
文档说明 Explanation
|
||||
------------------------
|
||||
此文档翻译自PyPI.md
|
||||
|
||||
This document was translated from PyPI.md
|
||||
|
||||
最后修改时间:2020年6月8日
|
||||
|
||||
Last modified time: June 8, 2020
|
||||
|
||||
stcgal - 用于STC MCU的ISP闪存工具
|
||||
===============================
|
||||
|
||||
stcgal是用于[STC MCU Ltd](http://stcmcu.com/)的命令行闪存编程工具。 兼容8051微控制器。
|
||||
|
||||
STC微控制器具有基于UART / USB的引导加载程序(BSL)。
|
||||
它采用系统内编程,即基于数据包的协议通过串行链路刷新代码存储器和IAP存储器。
|
||||
BSL还用于配置各种设备选项。 不幸的是,该协议没有公开记录,STC仅提供(粗略的)Windows GUI应用程序进行编程
|
||||
|
||||
stcgal是STC的Windows软件的功能全面的开源替代品。 它支持多种MCU,非常便携,适合自动下载。
|
||||
|
||||
[有关更多信息,请参见GitHub页面。](https://github.com/grigorig/stcgal).
|
248
doc/zh_CN/USAGE.md
Normal file
248
doc/zh_CN/USAGE.md
Normal file
@ -0,0 +1,248 @@
|
||||
文档说明 Explanation
|
||||
------------------------
|
||||
此文档翻译自USAGE.md
|
||||
|
||||
This document was translated from USAGE.md
|
||||
|
||||
最后修改时间:2020年6月8日
|
||||
|
||||
Last modified time: June 8, 2020
|
||||
|
||||
使用方法
|
||||
=====
|
||||
|
||||
使用 ```-h``` 调用stcgal以获取使用信息。('//'后面是翻译,实际使用过程中没有后面内容)
|
||||
|
||||
```
|
||||
usage: stcgal [-h] [-e] [-a] [-A {dtr,rts}] [-r RESETCMD]
|
||||
[-P {stc89,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto}]
|
||||
[-p PORT] [-b BAUD] [-l HANDSHAKE] [-o OPTION] [-t TRIM] [-D]
|
||||
[-V]
|
||||
[code_image] [eeprom_image]
|
||||
|
||||
stcgal 1.7 - an STC MCU ISP flash tool
|
||||
(C) 2014-2018 Grigori Goronzy and others
|
||||
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) //EEPROM段文件刷新
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit //显示此帮助消息并退出
|
||||
-a, --autoreset cycle power automatically by asserting DTR//断言DTR自动重启电源
|
||||
-A {dtr,rts}, --resetpin {dtr,rts}
|
||||
pin to hold down when using --autoreset (default: DTR)
|
||||
-r RESETCMD, --resetcmd RESETCMD
|
||||
shell command for board power-cycling (instead of DTR //用于板上电重启的shell命令(而不是DTR断言)
|
||||
assertion)
|
||||
-P {stc89,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto}, --protocol {stc89,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto}
|
||||
protocol version (default: auto) //协议版本(芯片系列)(在默认状态为auto)
|
||||
-p PORT, --port PORT serial port device //串口设备
|
||||
-b BAUD, --baud BAUD transfer baud rate (default: 115200) //传输波特率(默认值:115200)
|
||||
-l HANDSHAKE, --handshake HANDSHAKE
|
||||
handshake baud rate (default: 2400) //握手波特率(默认值:2400)
|
||||
-o OPTION, --option OPTION
|
||||
set option (can be used multiple times, see//设置选项(可以多次使用,请参阅文档)
|
||||
documentation)
|
||||
-t TRIM, --trim TRIM RC oscillator frequency in kHz (STC15+ series only)//RC振荡器频率(kHz)(仅STC15 +系列)
|
||||
-D, --debug enable debug output //启用调试输出
|
||||
-V, --version print version info and exit //打印版本信息并退出
|
||||
```
|
||||
|
||||
最重要的是, ```-p``` 设置用于编程的串行端口。
|
||||
|
||||
### 传输波特率
|
||||
|
||||
所有从 STC15 系列开始的 MCU 都支持默认值 115200 波特,至少是之前的 STC12C5A56S2。
|
||||
对于较旧的 MCU,您可能必须使用 ```-b 19200``` 才能正确操作。
|
||||
|
||||
### 通讯协议与规定
|
||||
|
||||
STC MCU对BSL使用各种相关但不兼容的协议。协议可以用```-P``` 标志来指定。
|
||||
默认情况下,使用UART协议自动检测。协议与MCU系列的对应关系如下:
|
||||
|
||||
* ```auto``` 自动检测基于UART的协议(默认)
|
||||
* ```stc89``` STC89/90 系列
|
||||
* ```stc89a``` STC89/90 系列(BSL 7.2.5C)
|
||||
* ```stc12a``` STC12x052 系列和其他类似系列
|
||||
* ```stc12b``` STC12x52 系列, STC12x56 系列和其他类似系列
|
||||
* ```stc12``` 多数 STC10/11/12 系列
|
||||
* ```stc15a``` STC15x104E 和 STC15x204E(A) 系列
|
||||
* ```stc15``` 多数 STC15 系列
|
||||
* ```stc8``` STC8A8K64S4A12 和 STC8F 系列
|
||||
* ```stc8d``` 所有 STC8 和 STC32 系列
|
||||
* ```stc8g``` STC8G1 和 STC8H1 系列
|
||||
* ```usb15``` 支持USB的STC15W4系列
|
||||
|
||||
doc / reverse-engineering子目录中的文本文件提供了BSL使用的反向工程协议的概述。
|
||||
有关更多详细信息,请阅读源代码。
|
||||
|
||||
### 获取MCU信息
|
||||
|
||||
调用stcgal而不编写任何文件。它将转储有关MCU的信息,例如:('//'后面是翻译,实际使用过程中没有后面内容)
|
||||
|
||||
```
|
||||
$ ./stcgal.py -P stc15
|
||||
Waiting for MCU, please cycle power: done //等待MCU,请重启电源
|
||||
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 //单片机BSL版本
|
||||
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 //串口2直通
|
||||
uart2_pin_mode=normal //串口2引脚模式
|
||||
Disconnected!
|
||||
```
|
||||
|
||||
如果识别失败,阅读[FAQ(chinese)](FAQ.md)
|
||||
|
||||
### 编程Flash闪存
|
||||
|
||||
stcgal支持Intel十六进制编码文件以及二进制文件。
|
||||
Intel HEX通过文件扩展名(. hex,. ihx 或者. ihex ) 自动测试。
|
||||
|
||||
像前面一样调用 stcgal,但提供代码映像的路径:
|
||||
|
||||
```
|
||||
$ ./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 //单片机BSL版本
|
||||
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 //串口2直通
|
||||
uart2_pin_mode=normal //串口2模式
|
||||
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!
|
||||
```
|
||||
|
||||
还可以编程存储器的EEPROM部分,。 将 Flash 图像路径添加到命令行后添加EEPROM图像路径。
|
||||
|
||||
stcgal默认使用 19200 bps的保守波特率。 可以通过标志```-b```选择更快的波特率来加快编程速度。
|
||||
|
||||
### 设备选项
|
||||
|
||||
stcgal转储了许多目标选项。 也可以修改这些。 在命令行上提供一个( 或者更多) `-o` 标志,后面跟一个 key-value 对来调整这些设置。
|
||||
例如你可以将外部晶体启用为时钟源:
|
||||
|
||||
```
|
||||
$ ./stcgal.py -P stc15 -o clock_source=external hello.bin
|
||||
```
|
||||
|
||||
请注意,设备选项只能在 Flash 内存被编程时设置 !
|
||||
|
||||
#### 命令行选项键
|
||||
|
||||
并非所有部件都支持所有选项。 描述中列出了支持每个选项的协议或者部分。
|
||||
|
||||
选项密钥 | 可能的值 | 协议/模型 | 描述
|
||||
------------------------------|-------------------|---------------------|------------
|
||||
```cpu_6t_enabled``` | true/false | 仅STC89 | 6T快速模式
|
||||
```bsl_pindetect_enabled``` | true/false | 全部 | BSL仅在 p3。2/p3。3 或者 p1.0/p1.1 ( 取决于模型) 低时启用
|
||||
```eeprom_erase_enabled``` | true/false | 全部 | 使用下一个编程周期擦除 EEPROM
|
||||
```clock_gain``` | low/high | 所有带XTAL引脚 | 外部晶体的时钟增益
|
||||
```ale_enabled``` | true/false | 仅STC89 | 如果 true,正常 GPIO,如果 false,则启用ALE引脚
|
||||
```xram_enabled``` | true/false | 仅STC89 | 使用内部 XRAM ( 仅适用于 STC89 )
|
||||
```watchdog_por_enabled``` | true/false | 全部 | 复位复位后的看门狗状态( POR )
|
||||
```low_voltage_reset``` | low/high | STC12A/STC12 | 低电压复位级别( 低:~3.3V, 高: ~3.7V)
|
||||
```low_voltage_reset``` | true/false | STC12 | 启用RESET2引脚低压检测
|
||||
```low_voltage_reset``` | true/false | STC15A | 启用低电压复位( brownout )
|
||||
```clock_source``` | internal/external | 带XTAL的STC12A+ | 使用内部( RC ) 或者外部( 晶体) 时钟
|
||||
```watchdog_stop_idle``` | true/false | STC12A+ | 在空闲模式停止看门狗
|
||||
```watchdog_prescale``` | 2,4,8,...,256 | STC12A+ | 看门狗定时器预分频器,必须是两个电源。
|
||||
```reset_pin_enabled``` | true/false | STC12+ | 如果 true,正常 GPIO,如果 false,则复位引脚
|
||||
```oscillator_stable_delay``` | 4096,...,32768 | 仅STC11F系列 | 时钟中的晶体稳定延迟。 一定是 two。
|
||||
```por_reset_delay``` | short/long | STC12+ | 复位复位( POR ) 延迟
|
||||
```low_voltage_threshold``` | 0...7 | STC15A+ | 低电压检测阈值。型号特定
|
||||
```eeprom_lvd_inhibit``` | true/false | STC15A+ | 在低电压情况下忽略EEPROM写入
|
||||
```rstout_por_state``` | low/high | STC15+ | 上电复位后的RSTOUT / RSTSV引脚状态
|
||||
```uart1_remap``` | true/false | STC8 | 通过UART1到UART2引脚( 用于单导线UART模式)
|
||||
```uart2_passthrough``` | true/false | STC15+ | 直通UART1至UART2引脚(用于单线UART模式)
|
||||
```uart2_pin_mode``` | push-pull/normal | STC15+ | UART2 TX引脚的输出模式
|
||||
```cpu_core_voltage``` | low/mid/high | STC15W+ | CPU核心电压( 低:~2.7V, mid: ~3.3V, 高:~3.6V)
|
||||
```epwm_open_drain``` | true/false | STC8 | 上电复位后,对EPWM引脚使用漏极开路引脚模式
|
||||
```program_eeprom_split``` | 512 - 65024 | STC8A8 w/ 64 KB | 选择代码闪存和EEPROM闪存之间的划分(以512字节块为单位)
|
||||
|
||||
### 频率微调
|
||||
|
||||
如果使用内部RC振荡器 (```clock_source=internal```),
|
||||
stcgal可以执行修整过程以将其调整为给定值。 仅在STC15系列及更高版本中受支持。
|
||||
调整值与设备选项一起存储。 使用 ```-t``` 标志请求对某个值进行修剪。
|
||||
通常可以实现4000到30000 kHz之间的频率。 如果修剪失败,stcgal将中止。
|
||||
|
||||
### 自动功率循环
|
||||
|
||||
STC的微控制器需要上电复位才能调用引导加载程序,这可能很不方便。
|
||||
stcgal可以使用串行接口的DTR控制信号来自动执行此操作。
|
||||
当通过```-a```用自动复位功能时,DTR信号有效约500 ms。
|
||||
这需要外部电路来实际切换电源。
|
||||
在某些情况下,当微控制器仅消耗很少的功率时,就有可能直接从DTR信号提供功率。
|
||||
|
||||
作为DTR的替代方法,可以使用定制的shell命令或外部脚本(通过-r选项)来重置设备。
|
||||
您应将命令与```-a```选项一起指定。不要忘了引号 !
|
||||
|
||||
例如:
|
||||
|
||||
```
|
||||
$ ./stcgal.py -P stc15 -a -r "echo 1 > /sys/class/gpio/gpio666/value"
|
||||
```
|
||||
或者
|
||||
|
||||
```
|
||||
$ ./stcgal.py -P stc15 -a -r "./powercycle.sh"
|
||||
```
|
||||
|
||||
### 退出状态
|
||||
|
||||
如果在执行stcgal时没有发生错误,则退出状态为 0.。
|
||||
任何错误( 如协议错误或者 I/O 错误) 都会导致退出状态 1。
|
||||
如果用户按ctrl键中止 stcgal,则会导致退出状态为 2.
|
||||
|
||||
### USB支持
|
||||
|
||||
STC15W4系列具有一个基于USB的BSL,可以选择性的使用它。
|
||||
stcgal中的USB支持是实验性的,将来可能会改变。
|
||||
USB模式是通过使用“ usb15”协议启用的。
|
||||
USB协议会忽略端口(```-p```)标志以及波特率选项。同时不支持RC频率调整。
|
16
setup.py
16
setup.py
@ -24,11 +24,14 @@
|
||||
import stcgal
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
with open("doc/PyPI.md", "r") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
setup(
|
||||
name = "stcgal",
|
||||
version = stcgal.__version__,
|
||||
packages = find_packages(exclude=["doc"]),
|
||||
install_requires = ["pyserial"],
|
||||
packages = find_packages(exclude=["doc", "tests"]),
|
||||
install_requires = ["pyserial>=3.0", "tqdm>=4.0.0"],
|
||||
extras_require = {
|
||||
"usb": ["pyusb>=1.0.0"]
|
||||
},
|
||||
@ -38,13 +41,16 @@ setup(
|
||||
],
|
||||
},
|
||||
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",
|
||||
license = "MIT License",
|
||||
platforms = "any",
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Environment :: Console",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
@ -52,7 +58,11 @@ setup(
|
||||
"Operating System :: Microsoft :: Windows",
|
||||
"Operating System :: MacOS",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Topic :: Software Development :: Embedded Systems",
|
||||
"Topic :: Software Development",
|
||||
],
|
||||
test_suite = "tests",
|
||||
tests_require = ["PyYAML"],
|
||||
)
|
||||
|
@ -1 +1 @@
|
||||
__version__ = "1.2"
|
||||
__version__ = "1.10"
|
||||
|
27
stcgal/__main__.py
Executable file
27
stcgal/__main__.py
Executable file
@ -0,0 +1,27 @@
|
||||
#
|
||||
# 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())
|
@ -20,11 +20,25 @@
|
||||
# SOFTWARE.
|
||||
#
|
||||
|
||||
import sys, os, time, struct
|
||||
import sys
|
||||
import argparse
|
||||
import stcgal
|
||||
from stcgal.utils import Utils, BaudType
|
||||
from stcgal.protocols import *
|
||||
import serial
|
||||
from stcgal.utils import BaudType
|
||||
from stcgal.protocols import Stc89Protocol
|
||||
from stcgal.protocols import Stc89AProtocol
|
||||
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 Stc8dProtocol
|
||||
from stcgal.protocols import Stc8gProtocol
|
||||
from stcgal.protocols import StcAutoProtocol
|
||||
from stcgal.protocols import StcProtocolException
|
||||
from stcgal.protocols import StcFramingException
|
||||
from stcgal.ihex import IHex
|
||||
|
||||
class StcGal:
|
||||
@ -32,9 +46,15 @@ class StcGal:
|
||||
|
||||
def __init__(self, opts):
|
||||
self.opts = opts
|
||||
self.hexFileType = 8
|
||||
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 == "stc89a":
|
||||
self.protocol = Stc89AProtocol(opts.port, opts.handshake, opts.baud)
|
||||
elif opts.protocol == "stc12a":
|
||||
self.protocol = Stc12AProtocol(opts.port, opts.handshake, opts.baud)
|
||||
elif opts.protocol == "stc12b":
|
||||
@ -42,26 +62,36 @@ class StcGal:
|
||||
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))
|
||||
self.protocol = Stc15AProtocol(opts.port, opts.handshake, opts.baud, round(opts.trim * 1000))
|
||||
elif opts.protocol == "stc15":
|
||||
self.protocol = Stc15Protocol(opts.port, opts.handshake, opts.baud,
|
||||
round(opts.trim * 1000))
|
||||
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 == "stc8d":
|
||||
self.protocol = Stc8dProtocol(opts.port, opts.handshake, opts.baud, round(opts.trim * 1000))
|
||||
elif opts.protocol == "stc8g":
|
||||
"""FIXME Ugly hack, but works until I fully implement the STC8G protocol"""
|
||||
if opts.trim < 27360:
|
||||
self.protocol = Stc8dProtocol(opts.port, opts.handshake, opts.baud, round(opts.trim * 1000))
|
||||
else:
|
||||
self.protocol = Stc8gProtocol(opts.port, opts.handshake, opts.baud, round(opts.trim * 1000))
|
||||
elif opts.protocol == "usb15":
|
||||
self.protocol = StcUsb15Protocol()
|
||||
else:
|
||||
self.protocol = StcBaseProtocol(opts.port, opts.handshake, opts.baud)
|
||||
|
||||
self.protocol = StcAutoProtocol(opts.port, opts.handshake, opts.baud)
|
||||
self.protocol.debug = opts.debug
|
||||
|
||||
def emit_options(self, options):
|
||||
for o in options:
|
||||
"""Set options from command line to protocol handler."""
|
||||
|
||||
for opt in options:
|
||||
try:
|
||||
kv = o.split("=", 1)
|
||||
if len(kv) < 2: raise ValueError("incorrect format")
|
||||
kv = opt.split("=", 1)
|
||||
if len(kv) < 2:
|
||||
raise ValueError("incorrect format")
|
||||
self.protocol.set_option(kv[0], kv[1])
|
||||
except ValueError as e:
|
||||
raise NameError("invalid option '%s' (%s)" % (kv[0], e))
|
||||
except ValueError as ex:
|
||||
raise NameError("invalid option '%s' (%s)" % (kv[0], ex))
|
||||
|
||||
def load_file_auto(self, fileobj):
|
||||
"""Load file with Intel Hex autodetection."""
|
||||
@ -71,120 +101,153 @@ class StcGal:
|
||||
fname.endswith(".ihex")):
|
||||
try:
|
||||
hexfile = IHex.read(fileobj)
|
||||
self.hexFileType = hexfile.get_mode()
|
||||
binary = hexfile.extract_data()
|
||||
print("%d bytes (Intel HEX)" %len(binary))
|
||||
return binary
|
||||
except ValueError as e:
|
||||
raise IOError("invalid Intel HEX file (%s)" %e)
|
||||
except ValueError as ex:
|
||||
raise IOError("invalid Intel HEX file (%s)" %ex)
|
||||
else:
|
||||
binary = fileobj.read()
|
||||
print("%d bytes (Binary)" %len(binary))
|
||||
return binary
|
||||
|
||||
def program_mcu(self):
|
||||
code_size = self.protocol.model.code
|
||||
ee_size = self.protocol.model.eeprom
|
||||
"""Execute the standard programming flow."""
|
||||
|
||||
if self.opts.option: self.emit_options(self.opts.option)
|
||||
|
||||
if self.protocol.split_code and self.protocol.model.iap:
|
||||
code_size = self.protocol.split_code
|
||||
ee_size = self.protocol.split_eeprom
|
||||
else:
|
||||
code_size = self.protocol.model.code
|
||||
ee_size = self.protocol.model.eeprom
|
||||
|
||||
print("Loading flash: ", end="")
|
||||
sys.stdout.flush()
|
||||
bindata = self.load_file_auto(self.opts.code_image)
|
||||
|
||||
if self.protocol.model.mcs251 and self.hexFileType != 32:
|
||||
print("Invalid input file. MCU is an MCS-251, input file MUST specify a linear", file=sys.stderr)
|
||||
print("base address, i.e. contain a type 04 record. More information at:", file=sys.stderr)
|
||||
print("https://en.wikipedia.org/wiki/Intel_HEX", file=sys.stderr)
|
||||
else:
|
||||
# warn if it overflows
|
||||
if len(bindata) > code_size:
|
||||
print("WARNING: code_image overflows into eeprom segment!", file=sys.stderr)
|
||||
if len(bindata) > (code_size + ee_size):
|
||||
print("WARNING: code_image truncated!", file=sys.stderr)
|
||||
bindata = bindata[0:code_size + ee_size]
|
||||
|
||||
# warn if it overflows
|
||||
if len(bindata) > code_size:
|
||||
print("WARNING: code_image overflows into eeprom segment!", file=sys.stderr)
|
||||
if len(bindata) > (code_size + ee_size):
|
||||
print("WARNING: code_image truncated!", file=sys.stderr)
|
||||
bindata = bindata[0:code_size + ee_size]
|
||||
# add eeprom data if supplied
|
||||
if self.opts.eeprom_image:
|
||||
print("Loading EEPROM: ", end="")
|
||||
sys.stdout.flush()
|
||||
eedata = self.load_file_auto(self.opts.eeprom_image)
|
||||
if len(eedata) > ee_size:
|
||||
print("WARNING: eeprom_image truncated!", file=sys.stderr)
|
||||
eedata = eedata[0:ee_size]
|
||||
if len(bindata) < code_size:
|
||||
bindata += bytes([0xff] * (code_size - len(bindata)))
|
||||
elif len(bindata) > code_size:
|
||||
print("WARNING: eeprom_image overlaps code_image!", file=sys.stderr)
|
||||
bindata = bindata[0:code_size]
|
||||
bindata += eedata
|
||||
|
||||
# add eeprom data if supplied
|
||||
if self.opts.eeprom_image:
|
||||
print("Loading EEPROM: ", end="")
|
||||
sys.stdout.flush()
|
||||
eedata = self.load_file_auto(self.opts.eeprom_image)
|
||||
if len(eedata) > ee_size:
|
||||
print("WARNING: eeprom_image truncated!", file=sys.stderr)
|
||||
eedata = eedata[0:ee_size]
|
||||
if len(bindata) < code_size:
|
||||
bindata += bytes(code_size - len(bindata))
|
||||
elif len(bindata) > code_size:
|
||||
print("WARNING: eeprom_image overlaps code_image!", file=sys.stderr)
|
||||
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 512 byte boundary
|
||||
if len(bindata) % 512:
|
||||
bindata += b'\xff' * (512 - len(bindata) % 512)
|
||||
self.protocol.handshake()
|
||||
self.protocol.erase_flash(len(bindata), code_size)
|
||||
self.protocol.program_flash(bindata)
|
||||
self.protocol.program_options()
|
||||
|
||||
self.protocol.disconnect()
|
||||
|
||||
if self.opts.option: self.emit_options(self.opts.option)
|
||||
def erase_mcu(self):
|
||||
"""Erase MCU without programming"""
|
||||
|
||||
code_size = self.protocol.model.code
|
||||
|
||||
self.protocol.handshake()
|
||||
self.protocol.erase_flash(len(bindata), code_size)
|
||||
self.protocol.program_flash(bindata)
|
||||
self.protocol.program_options()
|
||||
self.protocol.erase_flash(code_size, code_size)
|
||||
self.protocol.disconnect()
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self.protocol.connect(autoreset=self.opts.autoreset)
|
||||
"""Run programmer, main entry point."""
|
||||
|
||||
if self.opts.protocol == "auto":
|
||||
if self.opts.version:
|
||||
print("stcgal {}".format(stcgal.__version__))
|
||||
return 0
|
||||
|
||||
try:
|
||||
self.protocol.connect(autoreset=self.opts.autoreset, resetcmd=self.opts.resetcmd, resetpin=self.opts.resetpin)
|
||||
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.__init__(self.opts)
|
||||
self.initialize_protocol(self.opts)
|
||||
else:
|
||||
base_protocol = None
|
||||
|
||||
self.protocol.initialize(base_protocol)
|
||||
except KeyboardInterrupt:
|
||||
sys.stdout.flush();
|
||||
sys.stdout.flush()
|
||||
print("interrupted")
|
||||
return 2
|
||||
except (StcFramingException, StcProtocolException) as e:
|
||||
sys.stdout.flush();
|
||||
print("Protocol error: %s" % e, file=sys.stderr)
|
||||
self.protocol.disconnect()
|
||||
except (StcFramingException, StcProtocolException) as ex:
|
||||
sys.stdout.flush()
|
||||
print("Protocol error: %s" % ex, file=sys.stderr)
|
||||
if not isinstance(self.protocol, StcAutoProtocol):
|
||||
self.protocol.disconnect()
|
||||
return 1
|
||||
except serial.SerialException as e:
|
||||
sys.stdout.flush();
|
||||
print("Serial port error: %s" % e, file=sys.stderr)
|
||||
except serial.SerialException as ex:
|
||||
sys.stdout.flush()
|
||||
print("Serial port error: %s" % ex, file=sys.stderr)
|
||||
return 1
|
||||
except IOError as e:
|
||||
sys.stdout.flush();
|
||||
print("I/O error: %s" % e, file=sys.stderr)
|
||||
except IOError as ex:
|
||||
sys.stdout.flush()
|
||||
print("I/O error: %s" % ex, file=sys.stderr)
|
||||
return 1
|
||||
except Exception as ex:
|
||||
sys.stdout.flush()
|
||||
print("Unexpected error: %s" % ex, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
if self.opts.code_image:
|
||||
self.program_mcu()
|
||||
return 0
|
||||
elif self.opts.erase:
|
||||
self.erase_mcu()
|
||||
else:
|
||||
self.protocol.disconnect()
|
||||
return 0
|
||||
except NameError as e:
|
||||
sys.stdout.flush();
|
||||
print("Option error: %s" % e, file=sys.stderr)
|
||||
return 0
|
||||
except NameError as ex:
|
||||
sys.stdout.flush()
|
||||
print("Option error: %s" % ex, file=sys.stderr)
|
||||
self.protocol.disconnect()
|
||||
return 1
|
||||
except (StcFramingException, StcProtocolException) as e:
|
||||
sys.stdout.flush();
|
||||
print("Protocol error: %s" % e, file=sys.stderr)
|
||||
except (StcFramingException, StcProtocolException) as ex:
|
||||
sys.stdout.flush()
|
||||
print("Protocol error: %s" % ex, 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 e:
|
||||
print("Serial port error: %s" % e, file=sys.stderr)
|
||||
except serial.SerialException as ex:
|
||||
print("Serial port error: %s" % ex, file=sys.stderr)
|
||||
return 1
|
||||
except IOError as e:
|
||||
sys.stdout.flush();
|
||||
print("I/O error: %s" % e, file=sys.stderr)
|
||||
except IOError as ex:
|
||||
sys.stdout.flush()
|
||||
print("I/O error: %s" % ex, file=sys.stderr)
|
||||
self.protocol.disconnect()
|
||||
return 1
|
||||
|
||||
@ -192,17 +255,25 @@ class StcGal:
|
||||
def cli():
|
||||
# check arguments
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="stcgal %s - an STC MCU ISP flash tool\n(C) 2014-2015 Grigori Goronzy\nhttps://github.com/grigorig/stcgal" %stcgal.__version__)
|
||||
parser.add_argument("code_image", help="code segment file to flash (BIN/HEX)", type=argparse.FileType("rb"), nargs='?')
|
||||
description="stcgal {} - an STC MCU ISP flash tool\n".format(stcgal.__version__) +
|
||||
"(C) 2014-2018 Grigori Goronzy and others\nhttps://github.com/grigorig/stcgal")
|
||||
exclusives = parser.add_mutually_exclusive_group()
|
||||
exclusives.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='?')
|
||||
exclusives.add_argument("-e", "--erase", help="only erase flash memory", action="store_true")
|
||||
parser.add_argument("-a", "--autoreset", help="cycle power automatically by asserting DTR", action="store_true")
|
||||
parser.add_argument("-P", "--protocol", help="protocol version (default: auto)", choices=["stc89", "stc12a", "stc12b", "stc12", "stc15a", "stc15", "usb15", "auto"], default="auto")
|
||||
parser.add_argument("-A", "--resetpin", help="pin to hold down when using --autoreset (default: DTR)",
|
||||
choices=["dtr", "rts", "dtr_inverted", "rts_inverted"], default="dtr")
|
||||
parser.add_argument("-r", "--resetcmd", help="shell command for board power-cycling (instead of DTR assertion)", action="store")
|
||||
parser.add_argument("-P", "--protocol", help="protocol version (default: auto)",
|
||||
choices=["stc89", "stc89a", "stc12a", "stc12b", "stc12", "stc15a", "stc15", "stc8", "stc8d", "stc8g", "usb15", "auto"], default="auto")
|
||||
parser.add_argument("-p", "--port", help="serial port device", default="/dev/ttyUSB0")
|
||||
parser.add_argument("-b", "--baud", help="transfer baud rate (default: 19200)", type=BaudType(), default=19200)
|
||||
parser.add_argument("-b", "--baud", help="transfer baud rate (default: 115200)", type=BaudType(), default=115200)
|
||||
parser.add_argument("-l", "--handshake", help="handshake baud rate (default: 2400)", type=BaudType(), default=2400)
|
||||
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("-o", "--option", help="set option (can be used multiple times, see documentation)", 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")
|
||||
parser.add_argument("-V", "--version", help="print version info and exit", action="store_true")
|
||||
opts = parser.parse_args()
|
||||
|
||||
# run programmer
|
||||
|
333
stcgal/ihex.py
333
stcgal/ihex.py
@ -5,201 +5,220 @@
|
||||
import struct
|
||||
import codecs
|
||||
|
||||
class IHex(object):
|
||||
@classmethod
|
||||
def read(cls, lines):
|
||||
ihex = cls()
|
||||
|
||||
segbase = 0
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line: continue
|
||||
class IHex:
|
||||
"""Intel HEX parser and writer"""
|
||||
|
||||
t, a, d = ihex.parse_line(line)
|
||||
if t == 0x00:
|
||||
ihex.insert_data(segbase + a, d)
|
||||
@classmethod
|
||||
def read(cls, lines):
|
||||
"""Read Intel HEX data from string or lines"""
|
||||
ihex = cls()
|
||||
|
||||
elif t == 0x01:
|
||||
break # Should we check for garbage after this?
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
elif t == 0x02:
|
||||
ihex.set_mode(16)
|
||||
segbase = struct.unpack(">H", d[0:2])[0] << 4
|
||||
t, a, d = ihex.parse_line(line)
|
||||
if t == 0x00:
|
||||
ihex.insert_data(a, d)
|
||||
|
||||
elif t == 0x03:
|
||||
ihex.set_mode(16)
|
||||
elif t == 0x01:
|
||||
break # Should we check for garbage after this?
|
||||
|
||||
cs, ip = struct.unpack(">2H", d[0:2])
|
||||
ihex.set_start((cs, ip))
|
||||
elif t == 0x02:
|
||||
ihex.set_mode(16)
|
||||
ihex.linearBaseAddress = struct.unpack(">H", d[0:2])[0] << 4
|
||||
|
||||
elif t == 0x04:
|
||||
ihex.set_mode(32)
|
||||
segbase = struct.unpack(">H", d[0:2])[0] << 16
|
||||
elif t == 0x03:
|
||||
ihex.set_mode(16)
|
||||
|
||||
elif t == 0x05:
|
||||
ihex.set_mode(32)
|
||||
ihex.set_start(struct.unpack(">I", d[0:4])[0])
|
||||
cs, ip = struct.unpack(">2H", d[0:2])
|
||||
ihex.set_start((cs, ip))
|
||||
|
||||
else:
|
||||
raise ValueError("Invalid type byte")
|
||||
elif t == 0x04:
|
||||
ihex.set_mode(32)
|
||||
ihex.linearBaseAddress = struct.unpack(">H", d[0:2])[0] << 16
|
||||
|
||||
return ihex
|
||||
elif t == 0x05:
|
||||
ihex.set_mode(32)
|
||||
ihex.set_start(struct.unpack(">I", d[0:4])[0])
|
||||
|
||||
@classmethod
|
||||
def read_file(cls, fname):
|
||||
f = open(fname, "rb")
|
||||
ihex = cls.read(f)
|
||||
f.close()
|
||||
return ihex
|
||||
else:
|
||||
raise ValueError("Invalid type byte")
|
||||
|
||||
def __init__(self):
|
||||
self.areas = {}
|
||||
self.start = None
|
||||
self.mode = 8
|
||||
self.row_bytes = 16
|
||||
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
|
||||
@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_mode(self, mode):
|
||||
self.mode = mode
|
||||
def __init__(self):
|
||||
self.areas = {}
|
||||
self.start = None
|
||||
self.mode = 8
|
||||
self.row_bytes = 16
|
||||
self.linearBaseAddress = 0
|
||||
|
||||
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 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
|
||||
|
||||
return None
|
||||
def extract_data(self, start=None, end=None):
|
||||
"""Extract binary data"""
|
||||
if start is None:
|
||||
start = 0
|
||||
|
||||
def insert_data(self, istart, idata):
|
||||
iend = istart + len(idata)
|
||||
if end is None:
|
||||
result = bytearray()
|
||||
|
||||
area = self.get_area(istart)
|
||||
if area is None:
|
||||
self.areas[istart] = 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
|
||||
|
||||
else:
|
||||
data = self.areas[area]
|
||||
# istart - iend + len(idata) + len(data)
|
||||
self.areas[area] = data[:istart-area] + idata + data[iend-area:]
|
||||
return bytes(result)
|
||||
|
||||
def calc_checksum(self, bytes):
|
||||
total = sum(bytes)
|
||||
return (-total) & 0xFF
|
||||
result = bytearray()
|
||||
|
||||
def parse_line(self, rawline):
|
||||
if rawline[0:1] != b":":
|
||||
raise ValueError("Invalid line start character (%r)" % rawline[0])
|
||||
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
|
||||
|
||||
try:
|
||||
#line = rawline[1:].decode("hex")
|
||||
line = codecs.decode(rawline[1:], "hex_codec")
|
||||
except:
|
||||
raise ValueError("Invalid hex data")
|
||||
return bytes(result)
|
||||
|
||||
length, addr, type = struct.unpack(">BHB", line[:4])
|
||||
def set_start(self, start=None):
|
||||
self.start = start
|
||||
|
||||
dataend = length + 4
|
||||
data = line[4:dataend]
|
||||
def set_mode(self, mode):
|
||||
self.mode = mode
|
||||
|
||||
#~ print line[dataend:dataend + 2], repr(line)
|
||||
cs1 = line[dataend]
|
||||
cs2 = self.calc_checksum(line[:dataend])
|
||||
def get_mode(self):
|
||||
return self.mode
|
||||
|
||||
def get_linearBaseAddress(self):
|
||||
return self.linearBaseAddress
|
||||
|
||||
if cs1 != cs2:
|
||||
raise ValueError("Checksums do not match")
|
||||
def get_area(self, addr):
|
||||
for start, data in self.areas.items():
|
||||
end = start + len(data)
|
||||
if addr >= start and addr <= end:
|
||||
return start
|
||||
|
||||
return (type, addr, data)
|
||||
return None
|
||||
|
||||
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"
|
||||
def insert_data(self, istart, idata):
|
||||
iend = istart + len(idata)
|
||||
|
||||
def write(self):
|
||||
output = ""
|
||||
|
||||
for start, data in sorted(self.areas.items()):
|
||||
i = 0
|
||||
segbase = 0
|
||||
area = self.get_area(istart)
|
||||
if area is None:
|
||||
self.areas[istart] = idata
|
||||
|
||||
while i < len(data):
|
||||
chunk = data[i:i + self.row_bytes]
|
||||
else:
|
||||
data = self.areas[area]
|
||||
# istart - iend + len(idata) + len(data)
|
||||
self.areas[area] = data[
|
||||
:istart - area] + idata + data[iend - area:]
|
||||
|
||||
addr = start
|
||||
newsegbase = segbase
|
||||
def calc_checksum(self, data):
|
||||
total = sum(data)
|
||||
return (-total) & 0xFF
|
||||
|
||||
if self.mode == 8:
|
||||
addr = addr & 0xFFFF
|
||||
def parse_line(self, rawline):
|
||||
if rawline[0:1] != b":":
|
||||
raise ValueError("Invalid line start character (%r)" % rawline[0])
|
||||
|
||||
elif self.mode == 16:
|
||||
t = addr & 0xFFFF
|
||||
newsegbase = (addr - t) >> 4
|
||||
addr = t
|
||||
try:
|
||||
line = codecs.decode(rawline[1:], "hex_codec")
|
||||
except ValueError:
|
||||
raise ValueError("Invalid hex data")
|
||||
|
||||
if newsegbase != segbase:
|
||||
output += self.make_line(0x02, 0, struct.pack(">H", newsegbase))
|
||||
segbase = newsegbase
|
||||
length, addr, line_type = struct.unpack(">BHB", line[:4])
|
||||
|
||||
elif self.mode == 32:
|
||||
newsegbase = addr >> 16
|
||||
addr = addr & 0xFFFF
|
||||
dataend = length + 4
|
||||
data = line[4:dataend]
|
||||
|
||||
if newsegbase != segbase:
|
||||
output += self.make_line(0x04, 0, struct.pack(">H", newsegbase))
|
||||
segbase = newsegbase
|
||||
cs1 = line[dataend]
|
||||
cs2 = self.calc_checksum(line[:dataend])
|
||||
|
||||
output += self.make_line(0x00, addr, chunk)
|
||||
if cs1 != cs2:
|
||||
raise ValueError("Checksums do not match")
|
||||
|
||||
i += self.row_bytes
|
||||
start += self.row_bytes
|
||||
return (line_type, addr, data)
|
||||
|
||||
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))
|
||||
def make_line(self, line_type, addr, data):
|
||||
line = struct.pack(">BHB", len(data), addr, line_type)
|
||||
line += data
|
||||
line += bytes([self.calc_checksum(line)])
|
||||
return ":" + line.hex().upper() + "\r\n"
|
||||
|
||||
output += self.make_line(0x01, 0, "")
|
||||
return output
|
||||
def write(self):
|
||||
"""Write Intel HEX data to string"""
|
||||
output = ""
|
||||
|
||||
def write_file(self, fname):
|
||||
f = open(fname, "w")
|
||||
f.write(self.write())
|
||||
f.close()
|
||||
for start, data in sorted(self.areas.items()):
|
||||
i = 0
|
||||
segbase = 0
|
||||
|
||||
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
|
||||
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, b"")
|
||||
return output
|
||||
|
||||
def write_file(self, fname):
|
||||
"""Write Intel HEX data to file"""
|
||||
f = open(fname, "w")
|
||||
f.write(self.write())
|
||||
f.close()
|
||||
|
2091
stcgal/models.py
2091
stcgal/models.py
File diff suppressed because it is too large
Load Diff
@ -21,15 +21,24 @@
|
||||
#
|
||||
|
||||
import struct
|
||||
from abc import ABC
|
||||
from stcgal.utils import Utils
|
||||
|
||||
class BaseOption:
|
||||
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))
|
||||
@ -38,12 +47,14 @@ class BaseOption:
|
||||
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)
|
||||
|
||||
|
||||
@ -51,6 +62,7 @@ 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),
|
||||
@ -69,7 +81,7 @@ class Stc89Option(BaseOption):
|
||||
return not bool(self.msr & 1)
|
||||
|
||||
def set_t6(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr &= 0xfe
|
||||
self.msr |= 0x01 if not bool(val) else 0x00
|
||||
|
||||
@ -77,7 +89,7 @@ class Stc89Option(BaseOption):
|
||||
return not bool(self.msr & 4)
|
||||
|
||||
def set_pindetect(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr &= 0xfb
|
||||
self.msr |= 0x04 if not bool(val) else 0x00
|
||||
|
||||
@ -85,7 +97,7 @@ class Stc89Option(BaseOption):
|
||||
return not bool(self.msr & 8)
|
||||
|
||||
def set_ee_erase(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr &= 0xf7
|
||||
self.msr |= 0x08 if not bool(val) else 0x00
|
||||
|
||||
@ -104,7 +116,7 @@ class Stc89Option(BaseOption):
|
||||
return bool(self.msr & 32)
|
||||
|
||||
def set_ale(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr &= 0xdf
|
||||
self.msr |= 0x20 if bool(val) else 0x00
|
||||
|
||||
@ -112,7 +124,7 @@ class Stc89Option(BaseOption):
|
||||
return bool(self.msr & 64)
|
||||
|
||||
def set_xram(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr &= 0xbf
|
||||
self.msr |= 0x40 if bool(val) else 0x00
|
||||
|
||||
@ -120,7 +132,7 @@ class Stc89Option(BaseOption):
|
||||
return not bool(self.msr & 128)
|
||||
|
||||
def set_watchdog(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr &= 0x7f
|
||||
self.msr |= 0x80 if not bool(val) else 0x00
|
||||
|
||||
@ -129,6 +141,7 @@ class Stc12AOption(BaseOption):
|
||||
"""Manipulate STC12A series option bytes"""
|
||||
|
||||
def __init__(self, msr):
|
||||
super().__init__()
|
||||
assert len(msr) == 4
|
||||
self.msr = bytearray(msr)
|
||||
|
||||
@ -150,7 +163,7 @@ class Stc12AOption(BaseOption):
|
||||
def set_low_voltage_detect(self, val):
|
||||
lvds = {"low": 1, "high": 0}
|
||||
if val not in lvds.keys():
|
||||
raise ValueError("must be one of %s" % list(sources.keys()))
|
||||
raise ValueError("must be one of %s" % list(lvds.keys()))
|
||||
self.msr[3] &= 0xbf
|
||||
self.msr[3] |= lvds[val] << 6
|
||||
|
||||
@ -169,7 +182,7 @@ class Stc12AOption(BaseOption):
|
||||
return not bool(self.msr[1] & 32)
|
||||
|
||||
def set_watchdog(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[1] &= 0xdf
|
||||
self.msr[1] |= 0x20 if not val else 0x00
|
||||
|
||||
@ -177,7 +190,7 @@ class Stc12AOption(BaseOption):
|
||||
return not bool(self.msr[1] & 8)
|
||||
|
||||
def set_watchdog_idle(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[1] &= 0xf7
|
||||
self.msr[1] |= 0x08 if not val else 0x00
|
||||
|
||||
@ -196,7 +209,7 @@ class Stc12AOption(BaseOption):
|
||||
return not bool(self.msr[2] & 2)
|
||||
|
||||
def set_ee_erase(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[2] &= 0xfd
|
||||
self.msr[2] |= 0x02 if not val else 0x00
|
||||
|
||||
@ -204,7 +217,7 @@ class Stc12AOption(BaseOption):
|
||||
return not bool(self.msr[2] & 1)
|
||||
|
||||
def set_pindetect(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[2] &= 0xfe
|
||||
self.msr[2] |= 0x01 if not val else 0x00
|
||||
|
||||
@ -213,6 +226,7 @@ class Stc12Option(BaseOption):
|
||||
"""Manipulate STC10/11/12 series option bytes"""
|
||||
|
||||
def __init__(self, msr):
|
||||
super().__init__()
|
||||
assert len(msr) == 4
|
||||
self.msr = bytearray(msr)
|
||||
|
||||
@ -235,7 +249,7 @@ class Stc12Option(BaseOption):
|
||||
return bool(self.msr[0] & 1)
|
||||
|
||||
def set_reset_pin_enabled(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[0] &= 0xfe
|
||||
self.msr[0] |= 0x01 if bool(val) else 0x00
|
||||
|
||||
@ -243,7 +257,7 @@ class Stc12Option(BaseOption):
|
||||
return not bool(self.msr[0] & 64)
|
||||
|
||||
def set_low_voltage_detect(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[0] &= 0xbf
|
||||
self.msr[0] |= 0x40 if not val else 0x00
|
||||
|
||||
@ -295,7 +309,7 @@ class Stc12Option(BaseOption):
|
||||
return not bool(self.msr[2] & 32)
|
||||
|
||||
def set_watchdog(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[2] &= 0xdf
|
||||
self.msr[2] |= 0x20 if not val else 0x00
|
||||
|
||||
@ -303,7 +317,7 @@ class Stc12Option(BaseOption):
|
||||
return not bool(self.msr[2] & 8)
|
||||
|
||||
def set_watchdog_idle(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[2] &= 0xf7
|
||||
self.msr[2] |= 0x08 if not val else 0x00
|
||||
|
||||
@ -322,7 +336,7 @@ class Stc12Option(BaseOption):
|
||||
return not bool(self.msr[3] & 2)
|
||||
|
||||
def set_ee_erase(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[3] &= 0xfd
|
||||
self.msr[3] |= 0x02 if not val else 0x00
|
||||
|
||||
@ -330,13 +344,14 @@ class Stc12Option(BaseOption):
|
||||
return not bool(self.msr[3] & 1)
|
||||
|
||||
def set_pindetect(self, val):
|
||||
val = Utils.to_bool(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)
|
||||
|
||||
@ -359,7 +374,7 @@ class Stc15AOption(BaseOption):
|
||||
return bool(self.msr[0] & 16)
|
||||
|
||||
def set_reset_pin_enabled(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[0] &= 0xef
|
||||
self.msr[0] |= 0x10 if bool(val) else 0x00
|
||||
|
||||
@ -367,7 +382,7 @@ class Stc15AOption(BaseOption):
|
||||
return not bool(self.msr[2] & 32)
|
||||
|
||||
def set_watchdog(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[2] &= 0xdf
|
||||
self.msr[2] |= 0x20 if not val else 0x00
|
||||
|
||||
@ -375,7 +390,7 @@ class Stc15AOption(BaseOption):
|
||||
return not bool(self.msr[2] & 8)
|
||||
|
||||
def set_watchdog_idle(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[2] &= 0xf7
|
||||
self.msr[2] |= 0x08 if not val else 0x00
|
||||
|
||||
@ -394,7 +409,7 @@ class Stc15AOption(BaseOption):
|
||||
return bool(self.msr[1] & 64)
|
||||
|
||||
def set_lvrs(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[1] &= 0xbf
|
||||
self.msr[1] |= 0x40 if val else 0x00
|
||||
|
||||
@ -402,7 +417,7 @@ class Stc15AOption(BaseOption):
|
||||
return bool(self.msr[1] & 128)
|
||||
|
||||
def set_eeprom_lvd(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[1] &= 0x7f
|
||||
self.msr[1] |= 0x80 if val else 0x00
|
||||
|
||||
@ -420,7 +435,7 @@ class Stc15AOption(BaseOption):
|
||||
return not bool(self.msr[12] & 2)
|
||||
|
||||
def set_ee_erase(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[12] &= 0xfd
|
||||
self.msr[12] |= 0x02 if not val else 0x00
|
||||
|
||||
@ -428,13 +443,14 @@ class Stc15AOption(BaseOption):
|
||||
return not bool(self.msr[12] & 1)
|
||||
|
||||
def set_pindetect(self, val):
|
||||
val = Utils.to_bool(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)
|
||||
|
||||
@ -457,13 +473,13 @@ class Stc15Option(BaseOption):
|
||||
)
|
||||
|
||||
if len(msr) > 4:
|
||||
self.options += ("cpu_core_voltage", self.get_core_voltage, self.set_core_voltage),
|
||||
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);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[2] &= 0xef
|
||||
self.msr[2] |= 0x10 if not bool(val) else 0x00
|
||||
|
||||
@ -493,7 +509,7 @@ class Stc15Option(BaseOption):
|
||||
return not bool(self.msr[0] & 32)
|
||||
|
||||
def set_watchdog(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[0] &= 0xdf
|
||||
self.msr[0] |= 0x20 if not val else 0x00
|
||||
|
||||
@ -501,7 +517,7 @@ class Stc15Option(BaseOption):
|
||||
return not bool(self.msr[0] & 8)
|
||||
|
||||
def set_watchdog_idle(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[0] &= 0xf7
|
||||
self.msr[0] |= 0x08 if not val else 0x00
|
||||
|
||||
@ -520,7 +536,7 @@ class Stc15Option(BaseOption):
|
||||
return not bool(self.msr[1] & 64)
|
||||
|
||||
def set_lvrs(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[1] &= 0xbf
|
||||
self.msr[1] |= 0x40 if not val else 0x00
|
||||
|
||||
@ -528,7 +544,7 @@ class Stc15Option(BaseOption):
|
||||
return bool(self.msr[1] & 128)
|
||||
|
||||
def set_eeprom_lvd(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[1] &= 0x7f
|
||||
self.msr[1] |= 0x80 if val else 0x00
|
||||
|
||||
@ -546,7 +562,7 @@ class Stc15Option(BaseOption):
|
||||
return bool(self.msr[3] & 2)
|
||||
|
||||
def set_ee_erase(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[3] &= 0xfd
|
||||
self.msr[3] |= 0x02 if val else 0x00
|
||||
|
||||
@ -554,7 +570,7 @@ class Stc15Option(BaseOption):
|
||||
return not bool(self.msr[3] & 1)
|
||||
|
||||
def set_pindetect(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
val = Utils.to_bool(val)
|
||||
self.msr[3] &= 0xfe
|
||||
self.msr[3] |= 0x01 if not val else 0x00
|
||||
|
||||
@ -599,10 +615,177 @@ class Stc15Option(BaseOption):
|
||||
if self.msr[4] == 0xea: return "low"
|
||||
elif self.msr[4] == 0xf7: return "mid"
|
||||
elif self.msr[4] == 0xfd: return "high"
|
||||
else: return "unknown"
|
||||
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
|
||||
|
1058
stcgal/protocols.py
1058
stcgal/protocols.py
File diff suppressed because it is too large
Load Diff
@ -19,31 +19,43 @@
|
||||
# SOFTWARE.
|
||||
#
|
||||
|
||||
import serial
|
||||
import argparse
|
||||
import serial
|
||||
|
||||
class Utils:
|
||||
"""Common utility functions"""
|
||||
|
||||
@classmethod
|
||||
def to_bool(self, val):
|
||||
def to_bool(cls, val):
|
||||
"""make sensible boolean from string or other type value"""
|
||||
|
||||
if isinstance(val, bool): return val
|
||||
if isinstance(val, int): return bool(val)
|
||||
if len(val) == 0: return False
|
||||
if not val:
|
||||
return False
|
||||
if isinstance(val, bool):
|
||||
return val
|
||||
elif isinstance(val, int):
|
||||
return bool(val)
|
||||
return True if val[0].lower() == "t" or val[0] == "1" else False
|
||||
|
||||
@classmethod
|
||||
def to_int(self, val):
|
||||
def to_int(cls, val):
|
||||
"""make int from any value, nice error message if not possible"""
|
||||
|
||||
try: return int(val, 0)
|
||||
except: raise ValueError("invalid integer")
|
||||
try:
|
||||
return int(val, 0)
|
||||
except (TypeError, ValueError):
|
||||
raise ValueError("invalid integer")
|
||||
|
||||
@classmethod
|
||||
def hexstr(self, bytestr, sep=""):
|
||||
def hexstr(cls, bytestr, sep=""):
|
||||
"""make formatted hex string output from byte sequence"""
|
||||
|
||||
return sep.join(["%02X" % x for x in bytestr])
|
||||
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))
|
||||
|
||||
|
||||
class BaudType:
|
||||
@ -55,5 +67,5 @@ class BaudType:
|
||||
raise argparse.ArgumentTypeError("illegal baudrate")
|
||||
return baud
|
||||
|
||||
def __repr__(self): return "baudrate"
|
||||
|
||||
def __repr__(self):
|
||||
return "baudrate"
|
||||
|
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
19
tests/iap15f2k61s2.yml
Normal file
19
tests/iap15f2k61s2.yml
Normal file
@ -0,0 +1,19 @@
|
||||
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]
|
19
tests/stc12c2052ad.yml
Normal file
19
tests/stc12c2052ad.yml
Normal file
@ -0,0 +1,19 @@
|
||||
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]
|
15
tests/stc12c5a60s2.yml
Normal file
15
tests/stc12c5a60s2.yml
Normal file
@ -0,0 +1,15 @@
|
||||
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]
|
20
tests/stc15f104e.yml
Normal file
20
tests/stc15f104e.yml
Normal file
@ -0,0 +1,20 @@
|
||||
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]
|
19
tests/stc15l104w.yml
Normal file
19
tests/stc15l104w.yml
Normal file
@ -0,0 +1,19 @@
|
||||
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]
|
20
tests/stc15w4k56s4.yml
Normal file
20
tests/stc15w4k56s4.yml
Normal file
@ -0,0 +1,20 @@
|
||||
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]
|
19
tests/stc89c52rc.yml
Normal file
19
tests/stc89c52rc.yml
Normal file
@ -0,0 +1,19 @@
|
||||
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]
|
20
tests/stc8a8k64s4a12.yml
Normal file
20
tests/stc8a8k64s4a12.yml
Normal file
@ -0,0 +1,20 @@
|
||||
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]
|
5
tests/stc8f2k08s2-untrimmed.yml
Normal file
5
tests/stc8f2k08s2-untrimmed.yml
Normal file
@ -0,0 +1,5 @@
|
||||
name: STC8F2K08S2 untrimmed programming test
|
||||
protocol: stc8
|
||||
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
|
||||
responses:
|
||||
- [0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x00, 0x04, 0xFF, 0xFF, 0x8B, 0xFD, 0xFF, 0x27, 0x38, 0xF5, 0x73, 0x73, 0x55, 0x00, 0xF6, 0x41, 0x0A, 0x88, 0x86, 0x6F, 0x8F, 0x08, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0x20, 0x05, 0x3C, 0x18, 0x05, 0x22, 0x32, 0xFF]
|
120
tests/test_fuzzing.py
Normal file
120
tests/test_fuzzing.py
Normal file
@ -0,0 +1,120 @@
|
||||
#
|
||||
# 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(), Loader=yaml.SafeLoader)
|
||||
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()
|
62
tests/test_ihex.py
Normal file
62
tests/test_ihex.py
Normal file
@ -0,0 +1,62 @@
|
||||
#
|
||||
# Copyright (c) 2021 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 unittest
|
||||
import stcgal.ihex
|
||||
|
||||
class IHEXTests(unittest.TestCase):
|
||||
"""Tests for IHEX reader"""
|
||||
|
||||
def test_simple(self):
|
||||
"""Test reading a basic, valid file"""
|
||||
lines = [
|
||||
b":0B00000068656C6C6F5F776F726C645A",
|
||||
b":00000001FF"
|
||||
]
|
||||
bindata = stcgal.ihex.IHex.read(lines).extract_data()
|
||||
self.assertEqual(bindata, b"hello_world")
|
||||
|
||||
def test_empty(self):
|
||||
"""Test reading an empty file"""
|
||||
lines = []
|
||||
bindata = stcgal.ihex.IHex.read(lines).extract_data()
|
||||
self.assertEqual(bindata, b"")
|
||||
|
||||
def test_invalid(self):
|
||||
"""Test invalid encoded data"""
|
||||
lines = [
|
||||
":abc"
|
||||
]
|
||||
with self.assertRaises(ValueError):
|
||||
stcgal.ihex.IHex.read(lines)
|
||||
|
||||
def test_roundtrip(self):
|
||||
"""Test round-trip through encoder/decoder"""
|
||||
bindata = b"12345678"
|
||||
for mode in (8, 16, 32):
|
||||
with self.subTest(mode):
|
||||
hexer = stcgal.ihex.IHex()
|
||||
hexer.set_mode(mode)
|
||||
hexer.insert_data(0, bindata)
|
||||
encoded = hexer.write().encode("ASCII").splitlines()
|
||||
decoded = stcgal.ihex.IHex.read(encoded).extract_data()
|
||||
self.assertEqual(decoded, bindata)
|
164
tests/test_program.py
Normal file
164
tests/test_program.py
Normal file
@ -0,0 +1,164 @@
|
||||
#
|
||||
# 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
|
||||
from stcgal.protocols import StcProtocolException
|
||||
|
||||
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.version = 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)
|
||||
|
||||
@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_stc8_untrimmed(self, out, sleep_mock, serial_mock, write_mock, read_mock):
|
||||
"""Test error with untrimmed MCU"""
|
||||
with open("./tests/stc8f2k08s2-untrimmed.yml") as test_file:
|
||||
test_data = yaml.load(test_file.read(), Loader=yaml.SafeLoader)
|
||||
opts = get_default_opts()
|
||||
opts.trim = 0.0
|
||||
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(), 1)
|
||||
|
||||
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(), Loader=yaml.SafeLoader)
|
||||
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)
|
84
tests/test_utils.py
Normal file
84
tests/test_utils.py
Normal file
@ -0,0 +1,84 @@
|
||||
#
|
||||
# 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")
|
Loading…
Reference in New Issue
Block a user