├── .github └── workflows │ └── python.yml ├── .gitignore ├── README-zh_CN.md ├── README.md ├── doc ├── FAQ.md ├── INSTALL.md ├── MODELS.md ├── PyPI.md ├── USAGE.md ├── reverse-engineering │ ├── dump-mcu.c │ ├── hello.bin │ ├── iap15f2k61s2.txt │ ├── mcu-flags-meaning.ods │ ├── mcu-models+flags.ods │ ├── mcudb_flags.txt │ ├── stc-mcu.txt │ ├── stc11f08xe.txt │ ├── stc12-options.txt │ ├── stc12-protocol.txt │ ├── stc12a-options.txt │ ├── stc12a-protocol.txt │ ├── stc12c2052ad.txt │ ├── stc12c5a60s2.txt │ ├── stc15-options.txt │ ├── stc15-protocol.txt │ ├── stc15-usb-protocol.txt │ ├── stc15a-options.txt │ ├── stc15a-protocol.txt │ ├── stc15l104w.txt │ ├── stc15w4.txt │ ├── stc15w4k56s4.txt │ ├── stc8-new.txt │ ├── stc8-options.txt │ ├── stc8-protocol.txt │ ├── stc89-options.txt │ ├── stc89-protocol.txt │ ├── stc89a-c52rc.txt │ ├── stc89c52rc.txt │ ├── untrimmed.txt │ └── usb15-protocol.txt └── zh_CN │ ├── FAQ.md │ ├── INSTALL.md │ ├── MODELS.md │ ├── PyPI.md │ └── USAGE.md ├── setup.py ├── stcgal.py ├── stcgal ├── __init__.py ├── __main__.py ├── frontend.py ├── ihex.py ├── models.py ├── options.py ├── protocols.py └── utils.py └── tests ├── __init__.py ├── iap15f2k61s2.yml ├── stc12c2052ad.yml ├── stc12c5a60s2.yml ├── stc15f104e.yml ├── stc15l104w.yml ├── stc15w4k56s4.yml ├── stc89c52rc.yml ├── stc8a8k64s4a12.yml ├── stc8f2k08s2-untrimmed.yml ├── test_fuzzing.py ├── test_ihex.py ├── test_program.py └── test_utils.py /.github/workflows/python.yml: -------------------------------------------------------------------------------- 1 | name: Python package 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | python-version: [3.7, 3.8] 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Set up Python ${{ matrix.python-version }} 17 | uses: actions/setup-python@v2 18 | with: 19 | python-version: ${{ matrix.python-version }} 20 | - name: Install dependencies 21 | run: | 22 | python -m pip install --upgrade pip 23 | pip install pyusb coverage coveralls pyserial PyYAML tqdm 24 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 25 | - name: Build package 26 | run: | 27 | python setup.py build 28 | - name: Test with unittest 29 | run: | 30 | coverage run --source=stcgal setup.py test 31 | - name: Coveralls 32 | run: | 33 | coveralls 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | COVERALLS_FLAG_NAME: ${{ matrix.python-version }} 37 | COVERALLS_PARALLEL: true 38 | 39 | coveralls: 40 | name: Finish Coveralls 41 | needs: test 42 | runs-on: ubuntu-latest 43 | container: python:3-slim 44 | steps: 45 | - name: Finished 46 | run: | 47 | pip3 install --upgrade coveralls 48 | coveralls --finish 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.pyc 3 | *.egg-info 4 | *.eggs/ 5 | *.pybuild/ 6 | __pycache__/ 7 | /build 8 | /dist 9 | /deb_dist 10 | /debian/stcgal* 11 | /debian/files 12 | /.vscode 13 | .coverage 14 | coverage.xml 15 | htmlcov/ -------------------------------------------------------------------------------- /README-zh_CN.md: -------------------------------------------------------------------------------- 1 | 文档说明 Explanation 2 | ------------------- 3 | 此文档翻译自README.MD 4 | 5 | This document was translated from README.MD 6 | 7 | 最后修改时间:2020年6月8日 8 | 9 | Last modified time: June 8, 2020 10 | 11 | 12 | stcgal - 用于STC MCU的ISP闪存工具 13 | =============================== 14 | 15 | stcgal是用于[STC MCU Ltd]的命令行闪存编程工具。 16 | 兼容8051微控制器。 17 | 18 | 19 | STC微控制器具有基于UART / USB的引导加载程序(BSL)。 20 | 它采用系统内编程,即基于数据包的协议通过串行链路刷新代码存储器和IAP存储器。 21 | BSL还用于配置各种设备选项。 22 | 不幸的是,该协议没有公开记录,STC仅提供(粗略的)Windows GUI应用程序进行编程 23 | 24 | 25 | stcgal是STC的Windows软件的功能全面的开源替代品。 26 | 它支持多种MCU,非常便携,适合自动下载。 27 | 28 | 特点 29 | -------- 30 | 31 | * 支持STC 89/90/10/11/12/15/8/32系列 32 | * UART和USB BSL支持 33 | * 显示信息 34 | * 确定工作频率 35 | * 程序闪存 36 | * 程序IAP / EEPROM 37 | * 设置设备选项 38 | * 读取唯一的设备ID(STC 10/11/12/15/8) 39 | * 设置RC振荡器频率(STC 15/8) 40 | * 自动电源(使用DTR切换或自定义Shell命令循环) 41 | * 自动UART协议检测 42 | 43 | 快速开始 44 | ---------- 45 | 46 | 安装stcgal(可能需要root /管理员权限): 47 | 48 | pip3 install stcgal 49 | 50 | 呼叫stcgal并显示的用法: 51 | 52 | stcgal -h 53 | 54 | 更多的信息 55 | ------------------- 56 | 57 | [安装方法](doc/zh_CN/INSTALL.md) 58 | 59 | [如何取使用](doc/zh_CN/USAGE.md) 60 | 61 | [常见问题](doc/zh_CN/FAQ.md) 62 | 63 | [支持的MCU型号](doc/zh_CN/MODELS.md) 64 | 65 | 执照 66 | ------- 67 | 68 | stcgal是根据MIT许可发布的。 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![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) 2 | [![Coverage Status](https://coveralls.io/repos/github/grigorig/stcgal/badge.svg?branch=master)](https://coveralls.io/github/grigorig/stcgal?branch=master) 3 | [![PyPI version](https://badge.fury.io/py/stcgal.svg)](https://badge.fury.io/py/stcgal) 4 | 5 | stcgal - STC MCU ISP flash tool 6 | =============================== 7 | 8 | stcgal is a command line flash programming tool for [STC MCU Ltd](http://stcmcu.com/). 9 | 8051 compatible microcontrollers. 10 | 11 | STC microcontrollers have an UART/USB based boot strap loader (BSL). It 12 | utilizes a packet-based protocol to flash the code memory and IAP 13 | memory over a serial link. This is referred to as in-system programming 14 | (ISP). The BSL is also used to configure various (fuse-like) device 15 | options. Unfortunately, this protocol is not publicly documented and 16 | STC only provide a (crude) Windows GUI application for programming. 17 | 18 | stcgal is a full-featured Open Source replacement for STC's Windows 19 | software; it supports a wide range of MCUs, it is very portable and 20 | suitable for automation. 21 | 22 | Features 23 | -------- 24 | 25 | * Support for STC 89/90/10/11/12/15/8/32 series 26 | * UART and USB BSL support 27 | * Display part info 28 | * Determine operating frequency 29 | * Program flash memory 30 | * Program IAP/EEPROM 31 | * Set device options 32 | * Read unique device ID (STC 10/11/12/15/8) 33 | * Trim RC oscillator frequency (STC 15/8) 34 | * Automatic power-cycling with DTR toggle or a custom shell command 35 | * Automatic UART protocol detection 36 | 37 | Quickstart 38 | ---------- 39 | 40 | Install stcgal (might need root/administrator privileges): 41 | 42 | pip3 install stcgal 43 | 44 | Call stcgal and show usage: 45 | 46 | stcgal -h 47 | 48 | Further information 49 | ------------------- 50 | 51 | [Installation](doc/INSTALL.md) 52 | 53 | [How to use stcgal](doc/USAGE.md) 54 | 55 | [Frequently Asked Questions](doc/FAQ.md) 56 | 57 | [List of tested MCU models](doc/MODELS.md) 58 | 59 | License 60 | ------- 61 | 62 | stcgal is published under the MIT license. 63 | -------------------------------------------------------------------------------- /doc/FAQ.md: -------------------------------------------------------------------------------- 1 | Frequently Asked Questions 2 | ========================== 3 | 4 | ### Is it possible to read code (or EEPROM) memory out of a chip? 5 | 6 | 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. 7 | 8 | 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. 9 | 10 | ### Which serial interfaces have been tested with stcgal? 11 | 12 | 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: 13 | 14 | * FT232 family (OS: Linux, Windows) 15 | * CH340/CH341 (OS: Windows, Linux requires Kernel 4.10) 16 | * PL2303 (OS: Windows, Linux) 17 | * CP2102 (OS: Windows, Linux, macOS) 18 | 19 | Interfaces that are known to not work: 20 | 21 | * Raspberry Pi Mini UART (lacks parity support, enable the PL011 UART instead) 22 | 23 | In general, stcgal requires accurate baud rate timings and parity support. 24 | 25 | ### stcgal fails to start with the error `module 'serial' has no attribute 'PARITY_NONE'` or similar 26 | 27 | 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. 28 | 29 | ### stcgal fails to recognize the MCU and is stuck at "Waiting for MCU" 30 | 31 | There are a number of issues that can result in this symptom: 32 | 33 | * 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. 34 | * 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. 35 | * 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```. 36 | * 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. 37 | 38 | ### How can I avoid parasitic powering? 39 | 40 | Various remedies are possible to avoid parasitic powering. 41 | 42 | * 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. 43 | * 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. 44 | * Yet another possibility is to switch GND instead of VCC. This should be a fairly reliable solution in most cases. 45 | 46 | ### RC frequency trimming fails 47 | 48 | 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. 49 | 50 | ### Baud rate switching fails or flash programming fails 51 | 52 | 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. 53 | 54 | ### How can I use the autoreset feature? 55 | 56 | 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: 57 | 58 | ``` 59 | VCC --o o-- MCU GND 60 | | | 61 | .-. | 62 | | | 1k | 63 | | | | 64 | '_' | 65 | | | 66 | | ||-+ 67 | DTR --o --||<- BS170/BSS138 68 | ||-| (N-CH MOSFET) 69 | | 70 | | 71 | GND ---------o 72 | ``` 73 | 74 | 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. 75 | 76 | -------------------------------------------------------------------------------- /doc/INSTALL.md: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | stcgal requires Python 3.5 (or later), pyserial 3.0 or later and 5 | TQDM 4.0.0 or later. USB support is optional and requires pyusb 6 | 1.0.0b2 or later. You can run stcgal directly with the included 7 | ```stcgal.py``` script if the dependencies are already installed. 8 | 9 | There are several options for permanent installation: 10 | 11 | * Use Python3 and ```pip```. Run ```pip3 install stcgal``` to 12 | install the latest release of stcgal globally on your system. 13 | This may require administrator/root permissions for write access 14 | to system directories. 15 | 16 | * Use setuptools. Run ```./setup.py build``` to build and 17 | ```sudo ./setup.py install``` to install stcgal. 18 | -------------------------------------------------------------------------------- /doc/MODELS.md: -------------------------------------------------------------------------------- 1 | Supported MCU models 2 | ==================== 3 | 4 | stcgal should fully support STC 89/90/10/11/12/15/8/32 series MCUs. 5 | 6 | So far, stcgal was tested with the following MCU models: 7 | 8 | STC89/90 series 9 | * STC89C52RC (BSL version: 4.3C/6.6C) 10 | * STC89C54RD+ (BSL version: 4.3C) 11 | * STC90C52RC (BSL version: 4.3C) 12 | * STC90C58RD+ (BSL version: 4.3C) 13 | 14 | STC10/11 series 15 | * STC10F04XE (BSL version: 6.5J) 16 | * STC11F02E (BSL version: 6.5K) 17 | * STC11F08XE (BSL version: 6.5M) 18 | 19 | STC12 series 20 | * STC12C2052 (BSL version: 5.8D) 21 | * STC12C2052AD (BSL version: 5.8D) 22 | * STC12C5608AD (BSL version: 6.0G) 23 | * STC12C5A16S2 (BSL version: 6.2I) 24 | * STC12C5A60S2 (BSL version: 6.2I/7.1I) 25 | * STC12C5204AD (BSL version: 6.6H) 26 | 27 | STC15 series 28 | * STC15F104E (BSL version: 6.7Q) 29 | * STC15F204EA (BSL version: 6.7R) 30 | * STC15L104W (BSL version: 7.1.4Q) 31 | * STC15F104W (BSL version: 7.1.4Q and 7.2.5Q) 32 | * IAP15F2K61S2 (BSL version: 7.1.4S) 33 | * STC15L2K16S2 (BSL version: 7.2.4S) 34 | * IAP15L2K61S2 (BSL version: 7.2.5S) 35 | * STC15W408AS (BSL version: 7.2.4T and 7.2.5T) 36 | * STC15W4K56S4 (BSL version: 7.3.4T and 7.3.7T, UART and USB mode) 37 | 38 | STC8 series 39 | * STC8A8K64S4A12 (BSL version: 7.3.9U and 7.3.12U) 40 | * STC8F2K08S2 (BSL version: 7.3.10U) 41 | * STC8A8K64D4 (BSL version: 7.4.2U) 42 | * STC8G1K08A-8PIN (BSL version: 7.3.12U) 43 | * STC8G1K08-20/16PIN (BSL version: 7.3.12U) 44 | * STC8G1K17-20/16PIN (BSL version: 7.3.12U) 45 | * STC8G2K64S4 (BSL version: 7.3.11U) 46 | * STC8H1K08 (BSL version: 7.3.12U) 47 | * STC8H1K17T (BSL version: 7.4.5U) 48 | * STC8H3K64S2 (BSL version: 7.4.1U) 49 | * STC8H3K64S4 (BSL version: 7.4.1U) 50 | * STC8H4K64TL (BSL version: 7.4.3U) 51 | * STC8H8K64U (BSL version: 7.4.4U) 52 | 53 | STC32 series 54 | * STC32G12K128-Beta (BSL version: 7.4.4U) 55 | 56 | Compatibility reports, both negative and positive, are welcome. 57 | -------------------------------------------------------------------------------- /doc/PyPI.md: -------------------------------------------------------------------------------- 1 | stcgal - STC MCU ISP flash tool 2 | =============================== 3 | 4 | stcgal is a command line flash programming tool for [STC MCU Ltd](http://stcmcu.com/). 5 | 8051 compatible microcontrollers. 6 | 7 | STC microcontrollers have an UART/USB based boot strap loader (BSL). It 8 | utilizes a packet-based protocol to flash the code memory and IAP 9 | memory over a serial link. This is referred to as in-system programming 10 | (ISP). The BSL is also used to configure various (fuse-like) device 11 | options. Unfortunately, this protocol is not publicly documented and 12 | STC only provide a (crude) Windows GUI application for programming. 13 | 14 | stcgal is a full-featured Open Source replacement for STC's Windows 15 | software; it supports a wide range of MCUs, it is very portable and 16 | suitable for automation. 17 | 18 | [See the GitHub page for more information](https://github.com/grigorig/stcgal). -------------------------------------------------------------------------------- /doc/USAGE.md: -------------------------------------------------------------------------------- 1 | Usage 2 | ===== 3 | 4 | Call stcgal with ```-h``` for usage information. 5 | 6 | ``` 7 | usage: stcgal [-h] [-e] [-a] [-A {dtr,rts}] [-r RESETCMD] 8 | [-P {stc89,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto}] 9 | [-p PORT] [-b BAUD] [-l HANDSHAKE] [-o OPTION] [-t TRIM] [-D] 10 | [-V] 11 | [code_image] [eeprom_image] 12 | 13 | stcgal 1.7 - an STC MCU ISP flash tool 14 | (C) 2014-2018 Grigori Goronzy and others 15 | https://github.com/grigorig/stcgal 16 | 17 | positional arguments: 18 | code_image code segment file to flash (BIN/HEX) 19 | eeprom_image eeprom segment file to flash (BIN/HEX) 20 | 21 | options: 22 | -h, --help show this help message and exit 23 | -e, --erase only erase flash memory 24 | -a, --autoreset cycle power automatically by asserting DTR 25 | -A {dtr,rts,dtr_inverted,rts_inverted}, --resetpin {dtr,rts,dtr_inverted,rts_inverted} 26 | pin to hold down when using --autoreset (default: DTR) 27 | -r RESETCMD, --resetcmd RESETCMD 28 | shell command for board power-cycling (instead of DTR 29 | assertion) 30 | -P {stc89,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto}, --protocol {stc89,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto} 31 | protocol version (default: auto) 32 | -p PORT, --port PORT serial port device 33 | -b BAUD, --baud BAUD transfer baud rate (default: 115200) 34 | -l HANDSHAKE, --handshake HANDSHAKE 35 | handshake baud rate (default: 2400) 36 | -o OPTION, --option OPTION 37 | set option (can be used multiple times, see 38 | documentation) 39 | -t TRIM, --trim TRIM RC oscillator frequency in kHz (STC15+ series only) 40 | -D, --debug enable debug output 41 | -V, --version print version info and exit 42 | ``` 43 | 44 | Most importantly, ```-p``` sets the serial port to be used for programming. 45 | 46 | ### Transfer baud rate 47 | 48 | The default value of 115200 Baud is supported by all MCU starting with 49 | the STC15 family, and at least the STC12C5A56S2 before that. For older 50 | MCU, you might have to use ```-b 19200``` for correct operation. 51 | 52 | ### Protocols 53 | 54 | STC MCUs use a variety of related but incompatible protocols for the 55 | BSL. The protocol can be specified with the ```-P``` flag. By default 56 | UART protocol autodetection is used. The mapping between protocols 57 | and MCU series is as follows: 58 | 59 | * ```auto``` Automatic detection of UART based protocols (default) 60 | * ```stc89``` STC89/90 series 61 | * ```stc89a``` STC89/90 series (BSL 7.2.5C) 62 | * ```stc12a``` STC12x052 series and possibly others 63 | * ```stc12b``` STC12x52 series, STC12x56 series and possibly others 64 | * ```stc12``` Most STC10/11/12 series 65 | * ```stc15a``` STC15x104E and STC15x204E(A) series 66 | * ```stc15``` Most STC15 series 67 | * ```stc8``` STC8A8K64S4A12 and STC8F series 68 | * ```stc8d``` All STC8 and STC32 series 69 | * ```stc8g``` STC8G1 and STC8H1 series 70 | * ```usb15``` USB support on STC15W4 series 71 | 72 | The text files in the doc/reverse-engineering subdirectory provide an 73 | overview over the reverse engineered protocols used by the BSLs. For 74 | more details, please read the source code. 75 | 76 | ### Getting MCU information 77 | 78 | Call stcgal without any file to program. It will dump information 79 | about the MCU, e.g.: 80 | 81 | ``` 82 | $ ./stcgal.py -P stc15 83 | Waiting for MCU, please cycle power: done 84 | Target model: 85 | Name: IAP15F2K61S2 86 | Magic: F449 87 | Code flash: 61.0 KB 88 | EEPROM flash: 0.0 KB 89 | Target frequency: 10.046 MHz 90 | Target BSL version: 7.1S 91 | Target wakeup frequency: 34.771 KHz 92 | Target options: 93 | reset_pin_enabled=False 94 | clock_source=internal 95 | clock_gain=high 96 | watchdog_por_enabled=False 97 | watchdog_stop_idle=True 98 | watchdog_prescale=256 99 | low_voltage_reset=True 100 | low_voltage_threshold=3 101 | eeprom_lvd_inhibit=True 102 | eeprom_erase_enabled=False 103 | bsl_pindetect_enabled=False 104 | por_reset_delay=long 105 | rstout_por_state=high 106 | uart2_passthrough=False 107 | uart2_pin_mode=normal 108 | Disconnected! 109 | ``` 110 | 111 | If the identification fails, see the [FAQ](FAQ.md) for troubleshooting. 112 | 113 | ### Program the flash memory 114 | 115 | stcgal supports Intel HEX encoded files as well as binary files. Intel 116 | HEX is autodetected by file extension (.hex, .ihx or .ihex). 117 | 118 | Call stcgal just like before, but provide the path to the code image: 119 | 120 | ``` 121 | $ ./stcgal.py -P stc15 hello.hex 122 | Waiting for MCU, please cycle power: done 123 | Target model: 124 | Name: IAP15F2K61S2 125 | Magic: F449 126 | Code flash: 61.0 KB 127 | EEPROM flash: 0.0 KB 128 | Target frequency: 10.046 MHz 129 | Target BSL version: 7.1S 130 | Target wakeup frequency: 34.771 KHz 131 | Target options: 132 | reset_pin_enabled=False 133 | clock_source=internal 134 | clock_gain=high 135 | watchdog_por_enabled=False 136 | watchdog_stop_idle=True 137 | watchdog_prescale=256 138 | low_voltage_reset=True 139 | low_voltage_threshold=3 140 | eeprom_lvd_inhibit=True 141 | eeprom_erase_enabled=False 142 | bsl_pindetect_enabled=False 143 | por_reset_delay=long 144 | rstout_por_state=high 145 | uart2_passthrough=False 146 | uart2_pin_mode=normal 147 | Loading flash: 80 bytes (Intel HEX) 148 | Trimming frequency: 10.046 MHz 149 | Switching to 19200 baud: done 150 | Erasing flash: done 151 | Writing 256 bytes: .... done 152 | Setting options: done 153 | Target UID: 0D000021022632 154 | Disconnected! 155 | ``` 156 | 157 | You can also program the EEPROM part of the memory, if applicable. Add 158 | the EEPROM image path to the commandline after the flash image path. 159 | 160 | stcgal uses a conservative baud rate of 19200 bps by 161 | default. Programming can be sped up by choosing a faster baud rate 162 | with the flag ```-b```. 163 | 164 | ### Device options 165 | 166 | stcgal dumps a number of target options. These can be modified as 167 | well. Provide one (or more) ```-o``` flags followed by a key-value 168 | pair on the commandline to adjust these settings. For instance, you can 169 | enable the external crystal as clock source: 170 | 171 | ``` 172 | $ ./stcgal.py -P stc15 -o clock_source=external hello.bin 173 | ``` 174 | 175 | Please note that device options can only be set when flash memory is 176 | programmed! 177 | 178 | #### Option keys 179 | 180 | Not all parts support all options. The protocols or parts that support each option are listed in the description. 181 | 182 | Option key | Possible values | Protocols/Models | Description 183 | ------------------------------|-------------------|---------------------|------------ 184 | ```cpu_6t_enabled``` | true/false | STC89 only | 6T fast mode 185 | ```bsl_pindetect_enabled``` | true/false | All | BSL only enabled when P3.2/P3.3 or P1.0/P1.1 (depends on model) are low 186 | ```eeprom_erase_enabled``` | true/false | All | Erase EEPROM with next programming cycle 187 | ```clock_gain``` | low/high | All with XTAL pins | Clock gain for external crystal 188 | ```ale_enabled``` | true/false | STC89 only | ALE pin enabled if true, normal GPIO if false 189 | ```xram_enabled``` | true/false | STC89 only | Use internal XRAM (STC89 only) 190 | ```watchdog_por_enabled``` | true/false | All | Watchdog state after power-on reset (POR) 191 | ```low_voltage_reset``` | low/high | STC12A/STC12 | Low-voltage reset level (low: ~3.3V, high: ~3.7V) 192 | ```low_voltage_reset``` | true/false | STC12 | Enable RESET2 pin low voltage detect 193 | ```low_voltage_reset``` | true/false | STC15A | Enable low-voltage reset (brownout) 194 | ```clock_source``` | internal/external | STC12A+ with XTAL | Use internal (RC) or external (crystal) clock 195 | ```watchdog_stop_idle``` | true/false | STC12A+ | Stop watchdog in IDLE mode 196 | ```watchdog_prescale``` | 2,4,8,...,256 | STC12A+ | Watchdog timer prescaler, must be a power of two. 197 | ```reset_pin_enabled``` | true/false | STC12+ | RESET pin enabled if true, normal GPIO if false 198 | ```oscillator_stable_delay``` | 4096,...,32768 | STC11F series only | Crystal stabilization delay in clocks. Must be a power of two. 199 | ```por_reset_delay``` | short/long | STC12+ | Power-on reset (POR) delay 200 | ```low_voltage_threshold``` | 0...7 | STC15A+ | Low-voltage detection threshold. Model specific. 201 | ```eeprom_lvd_inhibit``` | true/false | STC15A+ | Ignore EEPROM writes in low-voltage situations 202 | ```rstout_por_state``` | low/high | STC15+ | RSTOUT/RSTSV pin state after power-on reset 203 | ```uart1_remap``` | true/false | STC8 | Remap UART1 pins (P3.0/P3.1) to UART2 pins (P3.6/P3.7) 204 | ```uart2_passthrough``` | true/false | STC15+ | Pass-through UART1 to UART2 pins (for single-wire UART mode) 205 | ```uart2_pin_mode``` | push-pull/normal | STC15+ | Output mode of UART2 TX pin 206 | ```cpu_core_voltage``` | low/mid/high | STC15W+ | CPU core voltage (low: ~2.7V, mid: ~3.3V, high: ~3.6V) 207 | ```epwm_open_drain``` | true/false | STC8 | Use open-drain pin mode for EPWM pins after power-on reset 208 | ```program_eeprom_split``` | 512 - 65024 | STC8A8 w/ 64 KB | Select split between code flash and EEPROM flash (in 512 byte blocks) 209 | 210 | ### Frequency trimming 211 | 212 | If the internal RC oscillator is used (```clock_source=internal```), 213 | stcgal can execute a trim procedure to adjust it to a given value. This 214 | is only supported by STC15 series and newer. The trim values are stored 215 | with device options. Use the ```-t``` flag to request trimming to a certain 216 | value. Generally, frequencies between 4000 and 30000 kHz can be achieved. 217 | If trimming fails, stcgal will abort. 218 | 219 | ### Automatic power-cycling 220 | 221 | STC's microcontrollers require a power-on reset to invoke the bootloader, 222 | which can be inconvenient. stcgal can use the DTR control signal of a 223 | serial interface to automate this. The DTR signal is asserted for 224 | approximately 500 ms when the autoreset feature is enabled with the 225 | ```-a``` flag. This requires external circuitry to actually switch the 226 | power. In some cases, when the microcontroller draws only little power, 227 | it is possible to directly supply power from the DTR signal. 228 | 229 | As an alternative to DTR, you can use a custom shell command or an external 230 | script (via -r option) to reset the device. You should specify the command 231 | along with -a option. Do not forget the quotes! 232 | 233 | Example: 234 | 235 | ``` 236 | $ ./stcgal.py -P stc15 -a -r "echo 1 > /sys/class/gpio/gpio666/value" 237 | ``` 238 | or 239 | 240 | ``` 241 | $ ./stcgal.py -P stc15 -a -r "./powercycle.sh" 242 | ``` 243 | 244 | ### Exit status 245 | 246 | The exit status is 0 if no error occured while executing stcgal. Any 247 | error, such as a protocol error or I/O error, results in an exit 248 | status of 1. If the the user aborted stcgal by pressing CTRL-C, 249 | that results in an exit status of 2. 250 | 251 | ### USB support 252 | 253 | STC15W4 series have an USB-based BSL that can be optionally 254 | used. USB support in stcgal is experimental and might change in the 255 | future. USB mode is enabled by using the ```usb15``` protocol. The 256 | port (```-p```) flag as well as the baudrate options are ignored for 257 | the USB protocol. RC frequency trimming is not supported. 258 | -------------------------------------------------------------------------------- /doc/reverse-engineering/dump-mcu.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-2-Clause 3 | * 4 | * Copyright (c) 2022 Vincent DEFERT. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | /** 31 | * This program automates the procedure explained below and generates 32 | * on the standard output the content of the 'models' list of models.py. 33 | * 34 | * It takes the name of the stc-isp executable as argument. 35 | */ 36 | /** 37 | * Manual procedure to read MCU definitions from a new STC-ISP executable 38 | * ======================================================================== 39 | * 40 | * We want to extract 2 tables from the executable, one with MCU names and 41 | * the other with their characteristics, let's call them "Name Table" and 42 | * "Info Table" respectively. 43 | * 44 | * The Info Table appears first in the executable and contains references 45 | * to the MCU name in the Name Table. Each entry in the Name Table is 16 46 | * bytes long, 32 for the Info Table. New entries are prepended to the 47 | * Info Table, and appended to the Name Table. Of course, both have the 48 | * same number of entries. 49 | * 50 | * This means that the Name Table is very easy to locate, as well as the 51 | * end of the Info Table, but not its beginning, which must be calculated. 52 | * 53 | * Finally, the field of an Info Table entry that references the MCU name 54 | * is expressed as a memory address, not a file position, so we'll need to 55 | * determine the base memory address of the name table. 56 | * 57 | * 1. Dump the content of the executable in a text file. 58 | * 59 | * hexdump -C stc-isp-v6.89G.exe > stc-isp-v6.89G.txt 60 | * 61 | * 2. Locate the first entry of the Name Table. 62 | * 63 | * Search for the following byte sequence: 64 | * 53 54 43 39 30 4c 45 35 31 36 41 44 00 00 00 00 65 | * (i.e. nul-terminated "STC90LE516AD" string). 66 | * 67 | * Let's call this file position NTS (Name Table Start). 68 | * 69 | * 3. Locate the end of the Name Table. 70 | * 71 | * Search for the following byte sequence: 72 | * 55 4e 4b 4e 4f 57 4e 00 25 30 36 58 00 00 00 00 73 | * (i.e. nul-terminated "UNKNOWN" and "%06X" strings). 74 | * 75 | * Let's call this file position NTE (Name Table End). 76 | * 77 | * 4. Find the end of the Info Table. 78 | * 79 | * Search for the following byte sequence (fixed last entry): 80 | * 05 46 01 00 xx xx xx xx 90 f1 00 00 00 f8 00 00 81 | * 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 82 | * 83 | * Bytes marked as 'xx' must be ignored while searching 84 | * 85 | * [Note: searching for '90 f1 00 00 00 f8 00 00' is sufficient.] 86 | * 87 | * It should be followed by 32 zeroed bytes. Let's call the file position 88 | * of the first zeroed byte ITE (Info Table End). 89 | * 90 | * 5. Find the beginning of the Info Table. 91 | * 92 | * The Info Table start with a block of 32 zeroed bytes except bytes 93 | * 4-7 which point at NTE, i.e. an info block pointing at the 'UNKNOWN' 94 | * MCU name. It's the only reliable way to determine the location of 95 | * the Info Table. 96 | * 97 | * Our first valid info block will thus be the offset of the Unknown 98 | * block + 32. Let's call this file position ITS (Info Table Start). 99 | * 100 | * 6. Calculate the number of MCU definitions (i.e. Info Table entries). 101 | * 102 | * NB_MCU = (ITE - ITS) / 32 103 | * 104 | * 7. Determine the base memory address of the name table. 105 | * 106 | * Let's suppose 'xx xx xx xx' is '9c f7 4a 00'. As it belongs to the Info 107 | * Table entry describing the first item of the Name Table, we directly 108 | * have what we're looking for, i.e. 0x004af79c. 109 | * 110 | * NTBA = littleEndianOf32bitUnsignedInt('xx xx xx xx') 111 | * 112 | * The index in the Name Table corresponding to a given Info Table item 113 | * is thus: 114 | * 115 | * NAME_IDX = (nameAddressFieldOfInfoTableItem - NTBA) / 0x10 116 | * 117 | * NOTE: for some reason, the Info Table entries of the STC08XE-3V and 118 | * STC08XE-5V each have 2 distinct mcuId, which gives 1115 Info Table 119 | * entries for 1113 strings in the Name Table. 120 | */ 121 | #include 122 | #include 123 | #include 124 | #include 125 | 126 | // Must be updated with the "UNKNOWN" name offset before use. 127 | static uint8_t infoTableStartSignature[] = { 128 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 129 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 130 | 0x00, 0x00, 0x00, 0x00, 131 | }; 132 | 133 | // 0x90, 0xf1 is the magic number of the STC90LE516AD 134 | // We test only the last 24 byte of its 32-byte entry, as they are 135 | // sufficiently discriminating and do not depend on a particular 136 | // executable release. 137 | static const uint8_t infoTableEndSignature[] = { 138 | 0x90, 0xf1, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 139 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 140 | 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 141 | }; 142 | 143 | // NUL-terminated "STC90LE516AD" followed by 3 NUL bytes 144 | static const uint8_t nameTableStartSignature[] = { 145 | 0x53, 0x54, 0x43, 0x39, 0x30, 0x4c, 0x45, 0x35, 146 | 0x31, 0x36, 0x41, 0x44, 0x00, 0x00, 0x00, 0x00, 147 | }; 148 | 149 | // NUL-terminated "UNKNOWN" and "%06X" followed by 3 NUL bytes 150 | static const uint8_t nameTableEndSignature[] = { 151 | 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x00, 152 | 0x25, 0x30, 0x36, 0x58, 0x00, 0x00, 0x00, 0x00, 153 | }; 154 | 155 | typedef struct { 156 | uint32_t flags; 157 | uint32_t nameAddr; 158 | uint32_t mcuId; 159 | uint32_t flashSize; 160 | uint32_t eepromSize; 161 | uint32_t eepromStartAddr; // STC89 & STC90 only. 0 means IAP. 162 | uint32_t totalSize; 163 | uint32_t unknown2; 164 | } MCUInfo; 165 | 166 | // Bit 1 is 1 for MCU which can accept 5V power supply voltage, be it 167 | // exclusively or not, and 0 for low-voltage only MCU (around 3.3V). 168 | #define FLAG_ACCEPT_5V_SUPPLY_VOLTAGE 0x00000002 169 | 170 | // Bit 3 is 1 for so-called "IAP" MCU, meaning the start address of the 171 | // flash portion used for EEPROM emulation can be configured. 172 | #define FLAG_CONFIGURABLE_EEPROM_SIZE 0x00000008 173 | 174 | // Bit 7 is 1 for MCU with an adjustable internal RC oscillator, i.e. 175 | // that supports calibration. When bits 7 and 8 are both 0, the MCU has 176 | // no IRCO at all (external crystal only). 177 | #define FLAG_CONFIGURABLE_IRCO_FREQ 0x00000080 178 | 179 | // Bit 8 is 1 for MCU with a fixed-frequency internal RC oscillator 180 | // (the old IRC* models). 181 | #define FLAG_FIXED_FREQUENCY_IRCO 0x00000100 182 | 183 | // Bit 12 is 1 for MCS-251 MCU, i.e. with a flash size that can be 184 | // larger than 64KB. 185 | #define FLAG_IS_MCS251_MCU 0x00001000 186 | 187 | #define SEARCH_BUFFER_LEN 8192 188 | #define MCU_NAME_LEN 16 189 | 190 | #define NO_MATCH -1 191 | #define FOUND -2 192 | 193 | // May help to guess the meaning of new flags as they are added. 194 | 195 | static void toBits(uint32_t n, char *result) { 196 | *result = '\0'; 197 | int pos = 0; 198 | 199 | for (uint32_t mask = 0x80000000; mask; mask >>= 1, pos++) { 200 | if (pos) { 201 | strcat(result, ","); 202 | } 203 | 204 | if (n & mask) { 205 | strcat(result, "1"); 206 | } else { 207 | strcat(result, "0"); 208 | } 209 | } 210 | } 211 | 212 | static void printCSVHeader(FILE *csvFile) { 213 | if (csvFile != NULL) { 214 | fprintf(csvFile, "name,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,flags (hex),mcuId,flashSize,eepromSize,eepromStartAddr,totalSize,unknown2\n"); 215 | } 216 | } 217 | 218 | static void printCSVRow(FILE *csvFile, const MCUInfo *info, const char *name) { 219 | char flags[64]; 220 | 221 | if (csvFile != NULL) { 222 | toBits(info->flags, flags); 223 | 224 | fprintf( 225 | csvFile, 226 | "%s,%s,0x%08x,0x%04x,%u,%u,0x%08x,%u,0x%08x\n", 227 | name, 228 | flags, 229 | info->flags, 230 | (uint16_t) info->mcuId, 231 | info->flashSize, 232 | info->eepromSize, 233 | info->eepromStartAddr, 234 | info->totalSize, 235 | info->unknown2 236 | ); 237 | } 238 | } 239 | 240 | static const char *toBool(uint32_t flags, uint32_t mask) { 241 | return (flags & mask) ? "True" : "False"; 242 | } 243 | 244 | static void printMCUModel(const MCUInfo *info, const char *name) { 245 | printf( 246 | " MCUModel(name='%s', magic=0x%04x, total=%u, code=%u, eeprom=%u, iap=%s, calibrate=%s, mcs251=%s),\n", 247 | name, 248 | (uint16_t) info->mcuId, 249 | info->totalSize, 250 | info->flashSize, 251 | info->eepromSize, 252 | toBool(info->flags, FLAG_CONFIGURABLE_EEPROM_SIZE), 253 | toBool(info->flags, FLAG_CONFIGURABLE_IRCO_FREQ), 254 | toBool(info->flags, FLAG_IS_MCS251_MCU) 255 | ); 256 | } 257 | 258 | static void printUsage(const char *pgmName) { 259 | printf("Usage: %s []\n", pgmName); 260 | printf("\n"); 261 | printf("- STC-ISP_executable is the file from which MCU models must be extracted.\n"); 262 | printf("Their list will be printed on the standard output.\n"); 263 | printf("\n"); 264 | printf("- The optional CSV_output_file will receive the MCU flags detail of each model\n"); 265 | printf("to facilitate reverse engineering efforts.\n"); 266 | printf("\n"); 267 | printf("Example: %s stc-isp-v6.91Q.exe MCUFlags.csv > MCUModels.txt\n", pgmName); 268 | } 269 | 270 | int main(int argc, const char **argv) { 271 | int rc = 1; 272 | MCUInfo *infoTable = NULL; 273 | char *nameTable = NULL; 274 | int mcuCount = 0; 275 | uint32_t infoTableStartOffset = 0; 276 | uint32_t infoTableEndOffset = 0; 277 | uint32_t nameTableStartOffset = 0; 278 | uint32_t nameTableEndOffset = 0; 279 | uint32_t baseAddr = 0; 280 | int nameTableSize = 0; 281 | 282 | if (argc < 2) { 283 | fprintf(stderr, "ERROR: missing argument\n"); 284 | printUsage(argv[0]); 285 | exit(1); 286 | } 287 | 288 | FILE *exeFile = fopen(argv[1], "rb"); 289 | FILE *csvFile = NULL; 290 | 291 | if (exeFile != NULL) { 292 | if (argc > 2) { 293 | csvFile = fopen(argv[2], "wt"); 294 | } 295 | 296 | rc = 2; 297 | uint8_t *buffer = (uint8_t *) malloc(SEARCH_BUFFER_LEN); 298 | 299 | if (buffer != NULL) { 300 | rc = 3; 301 | int infoTableEndMatch = NO_MATCH; 302 | int nameTableStartMatch = NO_MATCH; 303 | int nameTableEndMatch = NO_MATCH; 304 | uint32_t fileOffset = 0; 305 | int bytesRead = 0; 306 | 307 | while ((bytesRead = fread(buffer, 1, SEARCH_BUFFER_LEN, exeFile)) != 0) { 308 | for (int curByte = 0; curByte < SEARCH_BUFFER_LEN; curByte++) { 309 | int noMatch = 1; 310 | 311 | if (infoTableEndMatch > NO_MATCH) { 312 | if (infoTableEndSignature[infoTableEndMatch + 1] == buffer[curByte]) { 313 | infoTableEndMatch++; 314 | noMatch = 0; 315 | 316 | if (infoTableEndMatch == (sizeof(infoTableEndSignature) -1)) { 317 | infoTableEndMatch = FOUND; 318 | break; 319 | } 320 | } else { 321 | infoTableEndMatch = NO_MATCH; 322 | } 323 | } 324 | 325 | if (nameTableStartMatch > NO_MATCH) { 326 | if (nameTableStartSignature[nameTableStartMatch + 1] == buffer[curByte]) { 327 | nameTableStartMatch++; 328 | noMatch = 0; 329 | 330 | if (nameTableStartMatch == (sizeof(nameTableStartSignature) -1)) { 331 | nameTableStartMatch = FOUND; 332 | break; 333 | } 334 | } else { 335 | nameTableStartMatch = NO_MATCH; 336 | } 337 | } 338 | 339 | if (nameTableEndMatch > NO_MATCH) { 340 | if (nameTableEndSignature[nameTableEndMatch + 1] == buffer[curByte]) { 341 | nameTableEndMatch++; 342 | noMatch = 0; 343 | 344 | if (nameTableEndMatch == (sizeof(nameTableEndSignature) - 1)) { 345 | nameTableEndMatch = FOUND; 346 | break; 347 | } 348 | } else { 349 | nameTableEndMatch = NO_MATCH; 350 | } 351 | } 352 | 353 | if (noMatch) { 354 | if (infoTableEndMatch == NO_MATCH && infoTableEndSignature[0] == buffer[curByte]) { 355 | infoTableEndMatch = 0; 356 | infoTableEndOffset = fileOffset + curByte; 357 | } else if (nameTableStartMatch == NO_MATCH && nameTableStartSignature[0] == buffer[curByte]) { 358 | nameTableStartMatch = 0; 359 | nameTableStartOffset = fileOffset + curByte; 360 | } else if (nameTableEndMatch == NO_MATCH && nameTableEndSignature[0] == buffer[curByte]) { 361 | nameTableEndMatch = 0; 362 | nameTableEndOffset = fileOffset + curByte; 363 | } 364 | } 365 | } 366 | 367 | if (infoTableEndMatch == FOUND && nameTableStartMatch == FOUND && nameTableEndMatch == FOUND) { 368 | rc = 0; 369 | break; 370 | } 371 | 372 | fileOffset += SEARCH_BUFFER_LEN; 373 | } 374 | 375 | if (rc == 0) { 376 | // Point to the byte immediately following the table's last entry. 377 | infoTableEndOffset += sizeof(infoTableEndSignature); 378 | // Read last item of Info Table 379 | fseek(exeFile, infoTableEndOffset - sizeof(MCUInfo), SEEK_SET); 380 | MCUInfo lastItem; 381 | fread(&lastItem, sizeof(MCUInfo), 1, exeFile); 382 | // We need it now in order to calculate the memory address 383 | // corresponding to the UNKNOWN name. 384 | // We'll also need baseAddr later, anyway. 385 | baseAddr = lastItem.nameAddr; 386 | 387 | rc = 4; 388 | int infoTableStartMatch = NO_MATCH; 389 | uint32_t fileOffset = 0; 390 | int bytesRead = 0; 391 | *((uint32_t *)(infoTableStartSignature)) = (baseAddr - nameTableStartOffset) + nameTableEndOffset; 392 | fseek(exeFile, 0, SEEK_SET); 393 | 394 | while ((bytesRead = fread(buffer, 1, SEARCH_BUFFER_LEN, exeFile)) != 0) { 395 | for (int curByte = 0; curByte < SEARCH_BUFFER_LEN; curByte++) { 396 | if (infoTableStartMatch > NO_MATCH) { 397 | if (infoTableStartSignature[infoTableStartMatch + 1] == buffer[curByte]) { 398 | infoTableStartMatch++; 399 | 400 | if (infoTableStartMatch == (sizeof(infoTableStartSignature) - 1)) { 401 | infoTableStartMatch = FOUND; 402 | break; 403 | } 404 | } else { 405 | infoTableStartMatch = NO_MATCH; 406 | } 407 | } 408 | 409 | if (infoTableStartMatch == NO_MATCH && infoTableStartSignature[0] == buffer[curByte]) { 410 | infoTableStartMatch = 0; 411 | infoTableStartOffset = fileOffset + curByte; 412 | } 413 | } 414 | 415 | if (infoTableStartMatch == FOUND) { 416 | // Point to the first entry following the Unknown one. 417 | infoTableStartOffset += sizeof(MCUInfo) - 4; 418 | // Calculate number of entries while we're at it 419 | mcuCount = (infoTableEndOffset - infoTableStartOffset) / sizeof(MCUInfo); 420 | rc = 0; 421 | break; 422 | } 423 | 424 | fileOffset += SEARCH_BUFFER_LEN; 425 | } 426 | } 427 | 428 | free(buffer); 429 | 430 | if (rc == 0) { 431 | nameTableSize = nameTableEndOffset - nameTableStartOffset; 432 | 433 | nameTable = (char *) malloc(nameTableSize); 434 | 435 | if (nameTable == NULL) { 436 | rc = 5; 437 | } 438 | } 439 | 440 | if (rc == 0) { 441 | fseek(exeFile, nameTableStartOffset, SEEK_SET); 442 | fread(nameTable, nameTableSize, 1, exeFile); 443 | 444 | infoTable = (MCUInfo *) malloc(infoTableEndOffset - infoTableStartOffset); 445 | 446 | if (infoTable != NULL) { 447 | fseek(exeFile, infoTableStartOffset, SEEK_SET); 448 | fread(infoTable, infoTableEndOffset - infoTableStartOffset, 1, exeFile); 449 | 450 | } else { 451 | rc = 6; 452 | free(nameTable); 453 | } 454 | } 455 | } 456 | 457 | fclose(exeFile); 458 | } 459 | 460 | if (rc == 0) { 461 | printCSVHeader(csvFile); 462 | 463 | for (int mcu = 0; mcu < mcuCount; mcu++) { 464 | const char *mcuName = &nameTable[infoTable[mcu].nameAddr - baseAddr]; 465 | 466 | if (strncmp(mcuName, "STC12C54", 8) == 0 || strncmp(mcuName, "STC12LE54", 9) == 0) { 467 | // STC12x54xx always have 12KB EEPROM 468 | infoTable[mcu].eepromSize = 12 * 1024; 469 | } 470 | 471 | printCSVRow(csvFile, &infoTable[mcu], mcuName); 472 | printMCUModel(&infoTable[mcu], mcuName); 473 | } 474 | 475 | free(infoTable); 476 | free(nameTable); 477 | } 478 | 479 | if (csvFile != NULL) { 480 | fclose(csvFile); 481 | } 482 | 483 | return rc; 484 | } 485 | -------------------------------------------------------------------------------- /doc/reverse-engineering/hello.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grigorig/stcgal/fdf5fdd60515a260bb303dcf7b251c2b2671f91c/doc/reverse-engineering/hello.bin -------------------------------------------------------------------------------- /doc/reverse-engineering/iap15f2k61s2.txt: -------------------------------------------------------------------------------- 1 | 2015-11-22 07:09:10.387121: PC 2 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 3 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 4 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 5 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 6 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 8 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 9 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 10 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 11 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 12 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 13 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 14 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 15 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 16 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 17 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 18 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 19 | 7F 7F 7F 7F 7F 7F 20 | 2015-11-22 07:09:14.705892: MCU 21 | 46 B9 68 00 2B 50 87 D3 75 9C F5 3B 17 FF FF FF 22 | FF FF 09 81 00 00 71 53 00 F4 49 04 06 58 9C 02 23 | 0E 14 17 19 19 00 F4 F4 04 D2 10 44 16 24 | 2015-11-22 07:09:14.834040: PC 25 | 46 B9 6A 00 20 00 0B 00 C0 80 C0 FF C0 00 80 80 26 | 80 FF 80 00 40 80 40 FF 40 00 00 80 00 00 00 0A 27 | 12 16 FE FE FE FE FE FE FE FE FE FE FE 28 | 2015-11-22 07:09:15.033876: MCU 29 | 46 B9 68 00 20 00 0B 03 37 04 9A 06 02 06 6B 09 30 | 27 0B E8 0D 0A 12 5A 17 9B 14 8F 1C 96 00 00 05 31 | 91 16 32 | 2015-11-22 07:09:15.076930: PC 33 | 46 B9 6A 00 20 00 0C 75 80 76 80 77 80 78 80 79 34 | 80 7A 80 74 40 75 40 76 40 77 40 78 40 79 40 0A 35 | AA 16 FE FE FE FE FE FE FE FE FE FE FE FE 36 | 2015-11-22 07:09:15.283813: MCU 37 | 46 B9 68 00 20 00 0C 09 04 09 09 09 0E 09 0E 09 38 | 18 09 1D 12 00 12 0F 12 19 12 23 12 2D 12 37 02 39 | 43 16 40 | 2015-11-22 07:09:15.326972: PC 41 | 46 B9 6A 00 20 00 0C 70 80 71 80 72 80 73 80 74 42 | 80 75 80 74 40 75 40 76 40 77 40 78 40 79 40 0A 43 | 8C 16 FE FE FE FE FE FE FE FE FE FE FE FE 44 | 2015-11-22 07:09:15.533848: MCU 45 | 46 B9 68 00 20 00 0C 08 E1 08 EB 08 F5 08 FA 08 46 | FF 09 04 12 00 12 0A 12 19 12 23 12 2D 12 37 06 47 | 99 16 48 | 2015-11-22 07:09:15.602052: PC 49 | 46 B9 6A 00 0E 01 74 40 FD C0 80 72 81 04 5D 16 50 | 2015-11-22 07:09:15.625739: MCU 51 | 46 B9 68 00 07 01 00 70 16 52 | 2015-11-22 07:09:15.663175: PC 53 | 46 B9 6A 00 07 05 00 76 16 54 | 2015-11-22 07:09:15.677251: MCU 55 | 46 B9 68 00 07 05 00 74 16 56 | 2015-11-22 07:09:15.706149: PC 57 | 46 B9 6A 00 08 03 00 00 75 16 58 | 2015-11-22 07:09:19.156240: MCU 59 | 46 B9 68 00 0E 03 0D 00 00 21 02 26 32 01 01 16 60 | 2015-11-22 07:09:19.194154: PC 61 | 46 B9 6A 00 89 22 00 00 02 00 08 12 00 3F 80 FE 62 | 75 81 07 12 00 4C E5 82 60 03 02 00 03 E4 78 FF 63 | F6 D8 FD 02 00 03 AE 82 AF 83 8E 04 8F 05 1E BE 64 | FF 01 1F EC 4D 60 0F 7C 90 7D 01 1C BC FF 01 1D 65 | EC 4D 70 F7 80 E4 22 90 03 E8 12 00 1E E5 80 F4 66 | F5 80 80 F3 75 82 00 22 FF FF FF FF FF FF FF FF 67 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 68 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 69 | FF FF FF FF FF FF FF FF 51 E8 16 70 | 2015-11-22 07:09:19.366679: MCU 71 | 46 B9 68 00 08 02 54 00 C6 16 72 | 2015-11-22 07:09:19.383521: PC 73 | 46 B9 6A 00 89 02 00 80 FF FF FF FF FF FF FF FF 74 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 75 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 76 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 77 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 78 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 79 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 80 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 81 | FF FF FF FF FF FF FF FF 80 F5 16 82 | 2015-11-22 07:09:19.566903: MCU 83 | 46 B9 68 00 08 02 54 00 C6 16 84 | 2015-11-22 07:09:19.583260: PC 85 | 46 B9 6A 00 89 02 01 00 FF FF FF FF FF FF FF FF 86 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 87 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 88 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 89 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 90 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 91 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 92 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 93 | FF FF FF FF FF FF FF FF 80 76 16 94 | 2015-11-22 07:09:19.776710: MCU 95 | 46 B9 68 00 08 02 54 00 C6 16 96 | 2015-11-22 07:09:19.793705: PC 97 | 46 B9 6A 00 89 02 01 80 FF FF FF FF FF FF FF FF 98 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 99 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 100 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 101 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 102 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 103 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 104 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 105 | FF FF FF FF FF FF FF FF 80 F6 16 106 | 2015-11-22 07:09:19.972466: MCU 107 | 46 B9 68 00 08 02 54 00 C6 16 108 | 2015-11-22 07:09:20.007204: PC 109 | 46 B9 6A 00 49 04 00 00 FF FF FF 00 FF FF 00 FF 110 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 111 | FF A8 FF AD FF 40 FF FD 03 FF FF FF FF FF FF FF 112 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 113 | FF FF FF 74 BF F7 BB 9F 38 9E 16 114 | 2015-11-22 07:09:20.132323: MCU 115 | 46 B9 68 00 08 04 54 00 C8 16 116 | 117 | -------------------------------------------------------------------------------- /doc/reverse-engineering/mcu-flags-meaning.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grigorig/stcgal/fdf5fdd60515a260bb303dcf7b251c2b2671f91c/doc/reverse-engineering/mcu-flags-meaning.ods -------------------------------------------------------------------------------- /doc/reverse-engineering/mcu-models+flags.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grigorig/stcgal/fdf5fdd60515a260bb303dcf7b251c2b2671f91c/doc/reverse-engineering/mcu-models+flags.ods -------------------------------------------------------------------------------- /doc/reverse-engineering/mcudb_flags.txt: -------------------------------------------------------------------------------- 1 | STC15F103 2 | 00064F50 63 C3 08 00 2C FC 47 00 9B F2 00 00 00 0C 00 00 c...,.G......... 3 | 00064F60 00 08 00 00 00 00 00 00 00 20 00 00 07 03 00 00 ......... ...... 4 | 5 | STC15L103 6 | 00065110 61 C3 08 00 90 FB 47 00 DB F2 00 00 00 0C 00 00 a.....G......... 7 | 00065120 00 08 00 00 00 00 00 00 00 20 00 00 07 03 00 00 ......... ...... 8 | 9 | STC15F104E 10 | 00065190 E3 02 08 00 AC B1 47 00 94 F2 00 00 00 10 00 00 ......G......... 11 | 000651A0 00 04 00 00 00 00 00 00 00 20 00 00 07 00 00 00 ......... ...... 12 | 13 | STC15L104W 14 | X Y Z 15 | 00065050 E1 C3 08 00 B8 B1 47 00 D4 F2 00 00 00 10 00 00 ......G......... 16 | 00065060 00 04 00 00 00 00 00 00 00 20 00 00 07 03 00 00 ......... ...... 17 | 18 | STC15L104E 19 | 000651B0 E1 02 08 00 94 B1 47 00 D4 F2 00 00 00 10 00 00 ......G......... 20 | 000651C0 00 04 00 00 00 00 00 00 00 20 00 00 07 00 00 00 ......... ...... 21 | 22 | 23 | byte X bit 1: F vs L? low => L part, high => F part 24 | byte Z: protocol/model generation number? 25 | 26 | IAP15F2K61S2 27 | 00063750 AF 0B 09 00 08 06 48 00 49 F4 00 00 00 F4 00 00 ......H.I....... 28 | 00063760 00 00 00 00 00 00 00 00 00 00 01 00 07 00 00 00 ................ 29 | 30 | STC15F2K08S2 31 | 00063650 A3 0B 09 00 78 06 48 00 01 F4 00 00 00 20 00 00 ....x.H...... .. 32 | 00063660 00 D4 00 00 00 00 00 00 00 00 01 00 07 00 00 00 ................ 33 | 34 | STC15F2K32S2 35 | 000636B0 A3 0B 09 00 48 06 48 00 04 F4 00 00 00 80 00 00 ....H.H......... 36 | 000636C0 00 74 00 00 00 00 00 00 00 00 01 00 07 00 00 00 .t.............. 37 | 38 | STC15F2K60S2 39 | 00063730 A3 0B 09 00 64 B2 47 00 08 F4 00 00 00 F0 00 00 ....d.G......... 40 | 00063740 00 04 00 00 00 00 00 00 00 00 01 00 07 00 00 00 ................ 41 | 42 | IRC15F2K63S2 43 | 00063770 BF 0C 09 00 F8 05 48 00 4A F4 00 00 00 FE 00 00 ......H.J....... 44 | 00063780 00 00 00 00 00 00 00 00 00 00 01 00 07 00 00 00 ................ 45 | 46 | IRC15F1K63S 47 | 00064470 BE 8C 09 00 20 00 48 00 20 F4 00 00 00 FE 00 00 .... .H. ....... 48 | 00064480 00 00 00 00 00 00 00 00 00 00 01 00 07 00 00 00 ................ 49 | 50 | IRC15W207S 51 | 000648B0 B7 CC 0A 00 AC FE 47 00 56 F5 00 00 00 1E 00 00 ......G.V....... 52 | 000648C0 00 00 00 00 00 00 00 00 00 20 00 00 07 00 00 00 ......... ...... 53 | 54 | STC15H4K56S4 55 | 00063610 AF 8B 0E 00 98 06 48 00 07 F6 00 00 00 E0 00 00 ......H......... 56 | 00063620 00 00 00 00 00 00 00 00 00 00 01 00 07 00 00 00 ................ 57 | 58 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc-mcu.txt: -------------------------------------------------------------------------------- 1 | Analysis of STC-ISP 6.63 for MCU database 2 | The executable obviously contains a table with MCU data. 3 | It can be easily found because we already know some MCU IDs. 4 | 5 | I assume the BSL is actually stored in a (protected) area of the flash memory. 6 | That is why STC MCUs have these odd user accessible memory sizes. With BSL 6.x, 7 | it looks like the uppermost 3 KB are reserved on regular controllers, and 2 KB 8 | on IAP controllers. 9 | 10 | 11 | 12 | D364 (STC11F08XE) 13 | 14 | 00050990 c1 48 00 00 4c 3f 46 00 64 d3 00 00 00 20 00 00 |.H..L?F.d.... ..| 15 | ^ ^ MCU ID ^ code flash size (32 bit le) 16 | ^ pointer to name string 17 | ^ feature flags? 18 | 19 | NOTE: the upper word of the mcu id actually contains something else for STC12C54xx 20 | series, and the eeprom size is broken. 21 | 22 | 000509a0 00 d8 00 00 00 00 00 00 00 00 01 00 00 00 00 00 |................| 23 | ^ total flash size (incl. reserved space) 24 | (32 bit le) 25 | ^ eeprom size (32 bit le) 26 | doesn't really add up with datasheet, but 27 | it *does* add up with the amount of total flash minus bsl! 28 | parts without eeprom have zero here 29 | apparently we need to subtract 1 KB 30 | 31 | 32 | 33 | D3E4 (STC11L08XE) 34 | 35 | 00051090 c0 48 00 00 ac 3c 46 00 e4 d3 00 00 00 20 00 00 |.H...F.D.... ..| 43 | 00050ac0 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 |................| 44 | 45 | 46 | 47 | D17E (STC12C5A60S2) 48 | 49 | 0004ec30 81 08 00 00 e8 4b 46 00 7e d1 00 00 00 f0 00 00 |.....KF.~.......| 50 | 0004ec40 00 08 00 00 00 00 00 00 00 00 01 00 00 00 00 00 |................| 51 | 52 | 53 | 54 | E202 (STC11F02) 55 | 56 | 00050510 c1 68 00 00 fc 40 46 00 02 e2 00 00 00 08 00 00 |.h...@F.........| 57 | 00050520 00 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00 |......... ......| 58 | 59 | 60 | 61 | E222 (STC11F02E) 62 | 63 | 00050470 c1 68 00 00 38 41 46 00 22 e2 00 00 00 08 00 00 |.h..8AF.".......| 64 | 00050480 00 10 00 00 00 00 00 00 00 20 00 00 00 00 00 00 |......... ......| 65 | 66 | 67 | 68 | F110 (STC89C516RD+) 69 | 70 | 00053350 01 cc 00 00 c8 2d 46 00 10 f1 00 00 00 f8 00 00 |.....-F.........| 71 | 00053360 00 00 00 00 00 f8 00 00 00 00 01 00 00 00 00 00 |................| 72 | ^ the old STC89 controllers use this field, 73 | which is empty for the others. 74 | always seems to be equal to code flash size. 75 | 76 | F401 (STC15F2K08S2) 77 | 78 | 0004e270 d1 05 03 00 68 4f 46 00 01 f4 00 00 00 20 00 00 |....hOF...... ..| 79 | 0004e280 00 d4 00 00 00 00 00 00 00 00 01 00 07 00 00 00 |................| 80 | ^ some new 15 series 81 | extra data, not sure 82 | what it is 83 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc11f08xe.txt: -------------------------------------------------------------------------------- 1 | MCU: STC11F08XE 2 | Data: hello.bin 3 | Handshake: 9600 4 | Transfer: 9600 5 | Clock: 20 MHz 6 | 7 | 2014-01-06 17:13:42.017505: host2mcu 8 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 9 | 7F 7F 7F 7F 10 | 2014-01-06 17:13:42.315631: mcu2host 11 | 46 B9 68 00 39 50 04 BC 04 BD 04 BD 04 BC 04 BC 12 | 04 BD 04 BC 04 BC 65 4C 00 D3 64 8C BF 7F F7 FF 13 | FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 | 00 6B 0B D3 00 6A 82 80 11 4F 16 15 | 2014-01-06 17:13:42.455472: host2mcu 16 | 46 B9 6A 00 0D 50 00 00 36 01 D3 64 02 35 16 17 | 2014-01-06 17:13:42.479849: mcu2host 18 | 46 B9 68 00 07 8F 00 FE 16 19 | 2014-01-06 17:13:42.504527: host2mcu 20 | 46 B9 6A 00 0D 8F C0 7E 3F FE A0 83 04 A4 16 21 | 2014-01-06 17:13:42.768346: mcu2host 22 | 46 B9 68 00 0E 8F C0 7E 3F FE A0 83 04 04 A7 16 23 | 2014-01-06 17:13:42.987584: host2mcu 24 | 46 B9 6A 00 0C 8E C0 7E 3F FE A0 04 1F 16 25 | 2014-01-06 17:13:43.244111: mcu2host 26 | 46 B9 68 00 0D 84 C0 7E 3F FE A0 04 04 18 16 27 | 2014-01-06 17:13:43.286557: host2mcu 28 | 46 B9 6A 00 8C 84 00 00 02 00 00 20 00 00 00 00 29 | 00 00 00 00 00 00 00 00 80 7F 7E 7D 7C 7B 7A 79 30 | 78 77 76 75 74 73 72 71 70 6F 6E 6D 6C 6B 6A 69 31 | 68 67 66 65 64 63 62 61 60 5F 5E 5D 5C 5B 5A 59 32 | 58 57 56 55 54 53 52 51 50 4F 4E 4D 4C 4B 4A 49 33 | 48 47 46 45 44 43 42 41 40 3F 3E 3D 3C 3B 3A 39 34 | 38 37 36 35 34 33 32 31 30 2F 2E 2D 2C 2B 2A 29 35 | 28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 1A 19 36 | 18 17 16 15 14 13 12 11 10 0F 0E 21 81 16 37 | 2014-01-06 17:13:43.718954: mcu2host 38 | 46 B9 68 00 0E 00 00 08 00 8E 00 A8 2E 01 E2 16 39 | 2014-01-06 17:13:43.758507: host2mcu 40 | 46 B9 6A 00 8D 00 00 00 00 00 00 80 02 00 08 12 41 | 00 3F 80 FE 75 81 07 12 00 4C E5 82 60 03 02 00 42 | 03 E4 78 FF F6 D8 FD 02 00 03 AE 82 AF 83 8E 04 43 | 8F 05 1E BE FF 01 1F EC 4D 60 0F 7C 90 7D 01 1C 44 | BC FF 01 1D EC 4D 70 F7 80 E4 22 90 03 E8 12 00 45 | 1E E5 80 F4 F5 80 80 F3 75 82 00 22 00 00 00 00 46 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 47 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 48 | 00 00 00 00 00 00 00 00 00 00 00 00 22 7A 16 49 | 2014-01-06 17:13:44.050030: mcu2host 50 | 46 B9 68 00 08 00 03 00 73 16 51 | 2014-01-06 17:13:44.063502: host2mcu 52 | 46 B9 6A 00 8D 00 00 00 00 80 00 80 00 00 00 00 53 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 54 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 56 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 57 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 58 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 | 00 00 00 00 00 00 00 00 00 00 00 00 01 F7 16 61 | 2014-01-06 17:13:44.261910: mcu2host 62 | 46 B9 68 00 08 00 00 00 70 16 63 | 2014-01-06 17:13:44.279527: host2mcu 64 | 46 B9 6A 00 8D 00 00 00 01 00 00 80 00 00 00 00 65 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 66 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 67 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 69 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 71 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 72 | 00 00 00 00 00 00 00 00 00 00 00 00 01 78 16 73 | 2014-01-06 17:13:44.486933: mcu2host 74 | 46 B9 68 00 08 00 00 00 70 16 75 | 2014-01-06 17:13:44.503472: host2mcu 76 | 46 B9 6A 00 8D 00 00 00 01 80 00 80 00 00 00 00 77 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 79 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 81 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 82 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 83 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 84 | 00 00 00 00 00 00 00 00 00 00 00 00 01 F8 16 85 | 2014-01-06 17:13:44.698788: mcu2host 86 | 46 B9 68 00 08 00 00 00 70 16 87 | 2014-01-06 17:13:44.716462: host2mcu 88 | 46 B9 6A 00 0D 69 00 00 36 01 D3 64 02 4E 16 89 | 2014-01-06 17:13:44.755837: mcu2host 90 | 46 B9 68 00 07 8D 00 FC 16 91 | 2014-01-06 17:13:44.786562: host2mcu 92 | 46 B9 6A 00 1B 8D BF 7F F7 FF FF FF FF FF FF FF 93 | FF FF FF FF FF FF 01 30 9A 92 11 97 16 94 | 2014-01-06 17:13:44.843366: mcu2host 95 | 46 B9 68 00 24 50 BF 7F F7 FF FF 03 FF 65 4C BF 96 | 7F F7 FF FF FF FF 01 00 6B 0B D3 00 6A 82 80 00 97 | 00 00 00 0F A9 16 98 | 2014-01-06 17:13:44.968518: host2mcu 99 | 46 B9 6A 00 07 82 00 F3 16 100 | 101 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc12-options.txt: -------------------------------------------------------------------------------- 1 | Model-specific configuration registers 2 | Placement of configuration values 3 | 4 | "~" means the bit is a negated boolean. Sometimes values overlap, 5 | depending on MCU model. 6 | 7 | In STC10/11/12 series, the first 4 MCS bytes have active 8 | values. Generally, unused bits should be set to 1. 9 | 10 | 11 | MCS0 12 | ---- 13 | 14 | MSB 7 6 5 4 3 2 1 0 LSB 15 | ~RS2LV OSC1 OSC0 RSPEN 16 | ~LVD 17 | 18 | RSPEN := RESET pin enable 19 | ~RS2LV := RESET2 pin low voltage detect enable 20 | ~LVD := low voltage detect enable 21 | OSC0, OSC1 := oscillator stabilization delay 22 | 23 | OSC1 OSC0 delay 24 | 0 0 4096 25 | 0 1 8192 26 | 1 0 16384 27 | 1 1 32768 28 | 29 | 30 | MCS1 31 | ---- 32 | 33 | MSB 7 6 5 4 3 2 1 0 LSB 34 | ~PORD OSCG CLKSRC 35 | 36 | ~PORD := power-on-reset (POR) delay (0 = long, 1 = short) 37 | OSCG := high oscillator gain 38 | CLKSRC := clock source (0 = internal RC, 1 = external crystal) 39 | 40 | 41 | MCS2 42 | ---- 43 | 44 | MSB 7 6 5 4 3 2 1 0 LSB 45 | ~WDEN ~WDSTP WDPS2 WDPS1 WDPS0 46 | 47 | ~WDEN := watchdog enable after power-on-reset 48 | ~WDSTP := stop watchdog counter in idle mode 49 | WDPS2...WDPS0 := watchdog counter prescaler 50 | 51 | WDPS2 WDPS1 WDPS0 divisior 52 | 0 0 0 2 53 | 0 0 1 4 54 | 0 1 0 8 55 | 0 1 1 16 56 | 1 0 0 32 57 | 1 0 1 64 58 | 1 1 0 128 59 | 1 1 1 256 60 | 61 | 62 | MCS3 63 | ---- 64 | 65 | MSB 7 6 5 4 3 2 1 0 LSB 66 | ~EREE ~BSLD 67 | 68 | ~EREE := enable eeprom erase next time MCU is programmed 69 | ~BSLD := enable BSL pin detect; i.e. BSL is only enabled if P1.0/P1.1 70 | (or others, depends on MCU model) are held low on POR. 71 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc12-protocol.txt: -------------------------------------------------------------------------------- 1 | STC10/11/12 reverse engineering 2 | 3 | Initialisation/Synchronisation 4 | ------------------------------ 5 | 6 | Send a constant stream of 0x7f bytes, and wait for an initial response 7 | by the MCU. 8 | 9 | Basic frame format 10 | ------------------ 11 | 12 | M0 M1 DR L0 L1 D0 ... Dn C0 C1 ME 13 | 14 | M0 := 0x46 15 | M1 := 0xb9 16 | DR := 0x6a if host2mcu else 0x68 17 | L := 16 bit big endian packet length, counted from DR to ME 18 | C := 16 big endian modular sum from DR to Dn 19 | ME := 0x16 20 | 21 | D0..Dn is the packet payload 22 | 23 | In most cases, the first byte of the payload marks the type of packet 24 | or type of command. Responses by the MCU often use this type to tell 25 | the programmer software which kind of command should follow. For 26 | instance, after the baudrate handshake, the MCU replies with a 27 | type 0x84 packet, and 0x84 is used for "erase" command packets from 28 | the host. 29 | 30 | Fun fact: The start marker (0x46, 0xb9) interpreted as UTF-16 is the 31 | Unicode character U+46B9, which is an unusual CJK ideograph (䚹) 32 | which translates as "to prepare" or "all ready" into English. How 33 | fitting! This might not be a coincidence. 34 | 35 | Packets host2mcu 36 | ---------------- 37 | 38 | 1. Initiate baudrate handshake 39 | 40 | Payload: 0x50, 0x07, 0x00, 0x36, 0x01, ID0, ID1 41 | ^ is 0x00 with current STC software and 11F08XE, what gives? 42 | 43 | ID0 = MCU ID, byte 1 44 | ID1 = MCU ID, byte 2 45 | 46 | 2. Test baudrate setting 47 | 48 | Payload: 0x8f, 0xc0, brt, 0x3f, brt_csum, delay, iap 49 | 50 | brt := MCU baudrate timer compare 51 | brt_csum := (2 * (256 - brt)) & 0xff 52 | delay := delay after baudrate change (0x40 seems to be fine), 53 | STC software always seems to use 0xa0 54 | iap := MCU IAP wait state register value 55 | 56 | 3. Switch to baudrate setting 57 | 58 | Payload: 0x8e, 0xc0, brt, 0x3f, brt_csum, delay, iap 59 | ^ current STC software *omits* this here! 60 | Almost the same as the test packet. 61 | 62 | 4. Erase flash memory 63 | 64 | Payload: 0x84, 0xff, 0x00, blks, 0x00, 0x00, size, 65 | ^ no idea what that is for, current STC software uses 0x00 66 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 67 | 0x00, 0x00, 0x00, 0x00, 0x00, 68 | 0x80, ..., 0x0e 69 | 70 | blks := 256 byte blocks to clear 71 | size := total number of 256 byte blocks (size of flash memory) 72 | 73 | The 0x80..0x0e sequence seems to be some kind of magic code 74 | to stop flaky connections and the like from erasing the flash 75 | by accident. 76 | 77 | "size" specifies the number of flash memory blocks. if blks > size, 78 | eeprom will be erased. 79 | 80 | Note that while erase size is specified in 256 byte blocks, the IAP 81 | memory actually has 512 bytes physical erase block size, and the BSL 82 | expects 512 byte aligned erase commands! 83 | 84 | 5. Program flash memory 85 | 86 | Payload: 0x00, 0x00, 0x00, addr0, addr1, size0, size1, D0, ..., Dn 87 | 88 | addr0, addr1 := big-endian 16 bit address 89 | size0, size1 := big-endian 16 bit block size, always 128 90 | D0...Dn := block data 91 | 92 | Current STC software always seems to write at least 4 128 byte blocks 93 | for some reason. Data is zero-padded. 94 | 95 | Current STC software always writes a sequential set of memory. Since 96 | flash and eeprom are essentially the same, any free space between 97 | flash to be written and eeprom to be written is padded with zeros, 98 | and then the whole batch is sent at once. 99 | 100 | 6. Finish flash programming 101 | 102 | Payload: 0x69, 0x00, 0x00, 0x36, 0x01, ID0, ID1 103 | ^ kSTC-ISP uses 0x07 104 | 105 | This should be sent after all flash programming is done. I am not 106 | entirely sure why, though. Programming also works without it. 107 | 108 | 7. Set options 109 | 110 | Payload: 0x8d, MS0, ..., MS15, CLK0, CLK1, CLK2, CLK3 111 | 112 | MS0...MS15 := configuration registers specific to MCU model, 113 | not documented here. 114 | 115 | CLK0...CLK3 := 32 bit big endian measured clock, in Hz 116 | 117 | 8. Reset MCU 118 | 119 | Payload: 0x82 120 | 121 | 122 | Packets mcu2host 123 | ---------------- 124 | 125 | 1. Info packet 126 | 127 | Payload: 0x50, SYNC00, SYNC01, ..., SYNC70, SYNC71, 128 | V1, V2, 0x00, ID0, ID1, 0x8c, 129 | MS0, ..., MS7, 130 | UID0, ..., UID6, 131 | unknown bytes follow 132 | 133 | SYNC* := sequence of 8 16-bit big-endian counter values, recorded 134 | from the initial 0x7f sync sequence. this can be used to 135 | determine the MCU clock frequency. 136 | 137 | V1 := version number, two digits packed BCD. 138 | V2 := stepping, one ASCII character. 139 | ID0 := MCU model ID, byte 1 140 | ID1 := MCU model ID, byte 2 141 | UID0...UID6 := 7 bytes of unique id 142 | 143 | UID is only sent by some BSL versions, others send zero bytes. 144 | 145 | 2. Acknowledge baudrate handshake start 146 | 147 | Payload: 0x8f 148 | 149 | This means the programming software should erase the flash memory as 150 | the next step. 151 | 152 | 3. Acknowledge baudrate test 153 | 154 | Payload: request packet payload with some pad byte appended to payload 155 | 156 | 4. Acknowledge baudrate switch 157 | 158 | Payload: request packet payload with some pad byte appended to payload, and 159 | first payload byte changed to 0x84 160 | 161 | 5. Acknowledge erase 162 | 163 | Payload: 0x00, [UID0, ..., UID6] 164 | 165 | The UID is optional, not sent by all BSL versions. 166 | 167 | 6. Acknowledge block write 168 | 169 | Payload: 0x00, csum 170 | 171 | csum := 8 bit modular sum of flash block data 172 | 173 | 7. Acknowledge finish flash writing 174 | 175 | Payload: 0x8d 176 | 177 | This means the programming software should set options as the next 178 | step. 179 | 180 | 8. Acknowledge set options 181 | 182 | Payload: 0x50, MS0, ..., MS4, 0x03, 0xff, V1, V2, MS0, ..., MS7, 183 | UID0, ..., UID6, 184 | unknown bytes follow 185 | 186 | Some of the model-specific bytes are repeated twice (MS0-MS4). 187 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc12a-options.txt: -------------------------------------------------------------------------------- 1 | Model-specific configuration registers 2 | Placement of configuration values 3 | 4 | "~" means the bit is a negated boolean. Sometimes values overlap, 5 | depending on MCU model. 6 | 7 | In STC12A series, the first 7 MCS bytes have active 8 | values. Generally, unused bits should be set to 1. 9 | 10 | MCS0 11 | ---- 12 | 13 | MSB 7 6 5 4 3 2 1 0 LSB 14 | CLKSRC 15 | 16 | CLKSRC := clock source (0 = internal RC, 1 = external crystal) 17 | 18 | 19 | MCS1 20 | ---- 21 | 22 | MSB 7 6 5 4 3 2 1 0 LSB 23 | ~WDEN ~WDSTP WDPS2 WDPS1 WDPS0 24 | 25 | ~WDEN := watchdog enable after power-on-reset 26 | ~WDSTP := stop watchdog counter in idle mode 27 | 28 | WDPS2 WDPS1 WDPS0 divisior 29 | 0 0 0 2 30 | 0 0 1 4 31 | 0 1 0 8 32 | 0 1 1 16 33 | 1 0 0 32 34 | 1 0 1 64 35 | 1 1 0 128 36 | 1 1 1 256 37 | 38 | 39 | MCS2 40 | ---- 41 | 42 | MSB 7 6 5 4 3 2 1 0 LSB 43 | ~EERE ~BSLD 44 | 45 | ~EREE := enable eeprom erase next time MCU is programmed 46 | ~BSLD := enable BSL pin detect; i.e. BSL is only enabled if P1.0/P1.1 47 | (or others, depends on MCU model) are held low on POR. 48 | 49 | 50 | 51 | MCS3 (at index 6!) 52 | ------------------ 53 | 54 | MSB 7 6 5 4 3 2 1 0 LSB 55 | LVD 56 | 57 | LVD := low voltage detection threshold 58 | 59 | LVD threshold 60 | 0 3.7V 61 | 1 3.3V 62 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc12a-protocol.txt: -------------------------------------------------------------------------------- 1 | STC12A 2 | 3 | This is an early STC12 protocol variant; It seems to be used on STC12Cx052 and 4 | possibly other models. It is a mix of STC89 and STC12 protocol versions. 5 | 6 | Differences to STC12: 7 | 8 | * Uses NONE parity instead of EVEN parity. 9 | 10 | * Checksum calculations are different: only a single-byte modular sum is used. 11 | 12 | * Baudrate handshake isn't initiated with a type 0x50 packet; this is simply 13 | skipped. 14 | 15 | * After the handshake a special ping-pong sequence of 0x80 type packets needs 16 | to be sent. 17 | This doesn't appear to serve any purpose - possibly this is just done to 18 | verify that the connection works reliably. STC12 doesn't require it anymore 19 | because parity and the improved checksum ensure correct operation. 20 | 21 | * Erase is acknowledged with type 0x80 packet instead of type 0x00 22 | 23 | * After flash programming, there is no finish packet, type 0x69, sent; this 24 | is simply skipped. 25 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc12c2052ad.txt: -------------------------------------------------------------------------------- 1 | host2mcu: 2 | 3 | FF 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 4 | 2014-01-28 22:49:54.086500: 5 | 46 B9 6A 00 0C 8F C0 79 3F FE 28 85 28 16 6 | 2014-01-28 22:49:54.662532: 7 | 46 B9 6A 00 0B 8E C0 79 3F FE 28 A1 16 8 | 2014-01-28 22:49:55.051469: 9 | 46 B9 6A 00 0C 80 00 00 36 01 F2 12 31 16 10 | 2014-01-28 22:49:55.144473: 11 | 46 B9 6A 00 0C 80 00 00 36 01 F2 12 31 16 12 | 2014-01-28 22:49:55.250473: 13 | 46 B9 6A 00 0C 80 00 00 36 01 F2 12 31 16 14 | 2014-01-28 22:49:55.357505: 15 | 46 B9 6A 00 0C 80 00 00 36 01 F2 12 31 16 16 | 2014-01-28 22:49:55.463497: 17 | 46 B9 6A 00 0C 80 00 00 36 01 F2 12 31 16 18 | 2014-01-28 22:49:55.585442: 19 | 46 B9 6A 00 8B 84 00 00 02 00 00 08 00 00 00 00 20 | 00 00 00 00 00 00 00 00 80 7F 7E 7D 7C 7B 7A 79 21 | 78 77 76 75 74 73 72 71 70 6F 6E 6D 6C 6B 6A 69 22 | 68 67 66 65 64 63 62 61 60 5F 5E 5D 5C 5B 5A 59 23 | 58 57 56 55 54 53 52 51 50 4F 4E 4D 4C 4B 4A 49 24 | 48 47 46 45 44 43 42 41 40 3F 3E 3D 3C 3B 3A 39 25 | 38 37 36 35 34 33 32 31 30 2F 2E 2D 2C 2B 2A 29 26 | 28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 1A 19 27 | 18 17 16 15 14 13 12 11 10 0F 0E 68 16 28 | 2014-01-28 22:49:56.680538: 29 | 46 B9 6A 00 8C 00 00 00 00 00 00 80 02 00 08 12 30 | 00 3F 80 FE 75 81 07 12 00 4C E5 82 60 03 02 00 31 | 03 E4 78 FF F6 D8 FD 02 00 03 AE 82 AF 83 8E 04 32 | 8F 05 1E BE FF 01 1F EC 4D 60 0F 7C 90 7D 01 1C 33 | BC FF 01 1D EC 4D 70 F7 80 E4 22 90 03 E8 12 00 34 | 1E E5 80 F4 F5 80 80 F3 75 82 00 22 00 00 00 00 35 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 37 | 00 00 00 00 00 00 00 00 00 00 00 00 79 16 38 | 2014-01-28 22:49:57.362467: 39 | 46 40 | 2014-01-28 22:49:57.384798: 41 | B9 6A 00 8C 00 00 00 00 80 00 80 00 00 00 00 00 42 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 43 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 44 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 45 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 46 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 47 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 48 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 | 00 00 00 00 00 00 00 00 00 00 00 F6 16 50 | 2014-01-28 22:49:58.078540: 51 | 46 B9 6A 00 8C 00 00 00 01 00 00 80 00 00 00 00 52 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 53 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 54 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 56 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 57 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 58 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 | 00 00 00 00 00 00 00 00 00 00 00 00 77 16 60 | 2014-01-28 22:49:58.770492: 61 | 46 B9 6A 00 8C 00 00 00 01 80 00 80 00 00 00 00 62 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 63 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 66 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 67 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 69 | 00 00 00 00 00 00 00 00 00 00 00 00 F7 16 70 | 2014-01-28 22:49:59.539453: 71 | 46 B9 6A 00 26 8D FD F7 F7 FF BF 00 4F 2A 12 BF 72 | FF FD F7 FF FF FF FF F7 FF FF FF FF FF FF FF 00 73 | 4F 2A 12 FF FF FF 77 16 74 | 2014-01-28 22:49:59.833427: 75 | 46 B9 6A 00 06 50 C0 16 76 | 2014-01-28 22:50:00.066242: 77 | 46 B9 6A 00 06 82 F2 16 78 | 79 | 80 | mcu2host: 81 | 82 | 2014-01-28 22:53:43.948052: 83 | 46 B9 68 00 28 00 04 EC 04 EC 04 EC 04 EC 04 EC 84 | 04 EC 04 EB 04 EB 58 44 00 F2 12 83 FD F7 F7 FF 85 | FF FF BF FF FD F7 F7 FF C1 16 86 | 2014-01-28 22:53:44.501730: 87 | 46 B9 68 00 0C 8F C0 79 3F FE 28 85 26 16 88 | 2014-01-28 22:53:45.072735: 89 | 46 B9 68 00 0B 8E C0 79 3F FE 28 9F 16 90 | 2014-01-28 22:53:45.217069: 91 | 46 B9 68 00 06 80 EE 16 92 | 2014-01-28 22:53:45.323215: 93 | 46 B9 68 00 06 80 EE 16 94 | 2014-01-28 22:53:45.429706: 95 | 46 B9 68 00 06 80 EE 16 96 | 2014-01-28 22:53:45.536344: 97 | 46 B9 68 00 06 80 EE 16 98 | 2014-01-28 22:53:45.642186: 99 | 46 B9 68 00 06 80 EE 16 100 | 2014-01-28 22:53:46.704094: 101 | 46 B9 68 00 06 80 EE 16 102 | 2014-01-28 22:53:47.393661: 103 | 46 B9 68 00 07 80 03 F2 16 104 | 2014-01-28 22:53:48.101694: 105 | 46 B9 68 00 07 80 00 EF 16 106 | 2014-01-28 22:53:48.816598: 107 | 46 B9 68 00 07 80 00 EF 16 108 | 2014-01-28 22:53:49.485851: 109 | 46 B9 68 00 07 80 00 EF 16 110 | 2014-01-28 22:53:49.784437: 111 | 46 B9 68 00 06 80 EE 16 112 | 2014-01-28 22:53:49.881792: 113 | 46 B9 68 00 1B 10 C0 16 F7 FF BF 03 FF 58 44 FD 114 | F7 F7 FF FF FF BF FF FD F7 F7 FF 4C 16 115 | 2014-01-28 22:53:50.119724: 116 | 46 B9 68 00 06 80 EE 16 117 | 118 | 119 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc12c5a60s2.txt: -------------------------------------------------------------------------------- 1 | MCU: STC12C5A60S2 2 | Data: hello.bin 3 | Handshake: 9600 4 | Transfer: 9600 5 | Clock: 20 MHz 6 | 7 | 2014-01-06 17:19:52.426530: host2mcu 8 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 9 | 7F 7F 7F 7F 10 | 2014-01-06 17:19:52.722646: mcu2host 11 | 46 B9 68 00 31 50 04 BD 04 BC 04 BC 04 BD 04 BC 12 | 04 BC 04 BC 04 BC 62 49 00 D1 7E 8C FF 7F F7 FF 13 | FF FF 00 00 00 03 00 B0 02 2E 6B 00 CD 80 00 00 14 | 11 7E 16 15 | 2014-01-06 17:19:52.846519: host2mcu 16 | 46 B9 6A 00 0D 50 00 00 36 01 D1 7E 02 4D 16 17 | 2014-01-06 17:19:52.893712: mcu2host 18 | 46 B9 68 00 07 8F 00 FE 16 19 | 2014-01-06 17:19:52.928824: host2mcu 20 | 46 B9 6A 00 0D 8F C0 7E 3F FE A0 83 04 A4 16 21 | 2014-01-06 17:19:53.209386: mcu2host 22 | 46 B9 68 00 0E 8F C0 7E 3F FE A0 83 04 04 A7 16 23 | 2014-01-06 17:19:53.424544: host2mcu 24 | 46 B9 6A 00 0C 8E C0 7E 3F FE A0 04 1F 16 25 | 2014-01-06 17:19:53.679264: mcu2host 26 | 46 B9 68 00 0D 84 C0 7E 3F FE A0 04 04 18 16 27 | 2014-01-06 17:19:53.724472: host2mcu 28 | 46 B9 6A 00 8C 84 00 00 02 00 00 F0 00 00 00 00 29 | 00 00 00 00 00 00 00 00 80 7F 7E 7D 7C 7B 7A 79 30 | 78 77 76 75 74 73 72 71 70 6F 6E 6D 6C 6B 6A 69 31 | 68 67 66 65 64 63 62 61 60 5F 5E 5D 5C 5B 5A 59 32 | 58 57 56 55 54 53 52 51 50 4F 4E 4D 4C 4B 4A 49 33 | 48 47 46 45 44 43 42 41 40 3F 3E 3D 3C 3B 3A 39 34 | 38 37 36 35 34 33 32 31 30 2F 2E 2D 2C 2B 2A 29 35 | 28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 1A 19 36 | 18 17 16 15 14 13 12 11 10 0F 0E 22 51 16 37 | 2014-01-06 17:19:55.505307: mcu2host 38 | 46 B9 68 00 07 00 00 6F 16 39 | 2014-01-06 17:19:55.537548: host2mcu 40 | 46 B9 6A 00 8D 00 00 00 00 00 00 80 02 00 08 12 41 | 00 3F 80 FE 75 81 07 12 00 4C E5 82 60 03 02 00 42 | 03 E4 78 FF F6 D8 FD 02 00 03 AE 82 AF 83 8E 04 43 | 8F 05 1E BE FF 01 1F EC 4D 60 0F 7C 90 7D 01 1C 44 | BC FF 01 1D EC 4D 70 F7 80 E4 22 90 03 E8 12 00 45 | 1E E5 80 F4 F5 80 80 F3 75 82 00 22 00 00 00 00 46 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 47 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 48 | 00 00 00 00 00 00 00 00 00 00 00 00 22 7A 16 49 | 2014-01-06 17:19:55.968298: mcu2host 50 | 46 B9 68 00 08 00 03 00 73 16 51 | 2014-01-06 17:19:55.986526: host2mcu 52 | 46 B9 6A 00 8D 00 00 00 00 80 00 80 00 00 00 00 53 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 54 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 56 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 57 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 58 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 | 00 00 00 00 00 00 00 00 00 00 00 00 01 F7 16 61 | 2014-01-06 17:19:56.412372: mcu2host 62 | 46 B9 68 00 08 00 00 00 70 16 63 | 2014-01-06 17:19:56.430530: host2mcu 64 | 46 B9 6A 00 8D 00 00 00 01 00 00 80 00 00 00 00 65 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 66 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 67 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 69 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 71 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 72 | 00 00 00 00 00 00 00 00 00 00 00 00 01 78 16 73 | 2014-01-06 17:19:56.865930: mcu2host 74 | 46 B9 68 00 08 00 00 00 70 16 75 | 2014-01-06 17:19:56.884481: host2mcu 76 | 46 B9 6A 00 8D 00 00 00 01 80 00 80 00 00 00 00 77 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 79 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 81 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 82 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 83 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 84 | 00 00 00 00 00 00 00 00 00 00 00 00 01 F8 16 85 | 2014-01-06 17:19:57.288219: mcu2host 86 | 46 B9 68 00 08 00 00 00 70 16 87 | 2014-01-06 17:19:57.306515: host2mcu 88 | 46 B9 6A 00 0D 69 00 00 36 01 D1 7E 02 66 16 89 | 2014-01-06 17:19:57.369302: mcu2host 90 | 46 B9 68 00 07 8D 00 FC 16 91 | 2014-01-06 17:19:57.412492: host2mcu 92 | 46 B9 6A 00 1B 8D FF 7F F7 FF FF FF FF FF FF FF 93 | FF FF FF FF FF FF 01 30 5A 49 11 4E 16 94 | 2014-01-06 17:19:57.511742: mcu2host 95 | 46 B9 68 00 24 50 FF 7F F7 FF FF 03 FF 62 49 FF 96 | 7F F7 FF FF FF FF 01 00 03 00 B0 02 2E 6B 00 CD 97 | 80 00 00 10 09 16 98 | 2014-01-06 17:19:57.672474: host2mcu 99 | 46 B9 6A 00 07 82 00 F3 16 100 | 101 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc15-options.txt: -------------------------------------------------------------------------------- 1 | STC15 series MCS bytes 2 | ====================== 3 | 4 | MCS3 is like early STC15 MCS1. 5 | MCS2 is like early STC15 MCS2. 6 | MCS4 is like early STC15 MCS0 but with additions. 7 | MCSX is like early STC15 MCS12. 8 | MCSY is new in STC15W4 series 9 | 10 | baseline 11 | B5 FF F7 BB 9F 12 | 13 | long por disabled 14 | B6 FF F7 BB 1F 15 | --> MCS4 bit 7 controls POR delay. low => short, high => long 16 | 17 | reset pin as io disabled 18 | B8 FF F7 BB 8F 19 | --> MCS4 bit 4 controls reset pin. low => reset is normal, high => reset is io 20 | 21 | low voltage reset disabled 22 | B6 FF F7 FB 9F 23 | --> MCS3 bit 6 controls low voltage reset. low => lv reset enabled, high => disabled 24 | 25 | lvd threshold 2.61v 26 | B8 FF F7 BA 9F 27 | lvd threshold 2.82v 28 | B5 FF F7 B9 9F 29 | lvd threshold 3.08v 30 | B6 FF F7 B8 9F 31 | 32 | --> MCS3 bits 0-2 control LVD threshold setting. exact mapping not yet clear. 33 | 34 | eeprom lv inhibit disabled 35 | B7 FF F7 3B 9F 36 | --> MCS3 bit 7 controls eeprom lv inhibit. high => eeprom lv inhibit enabled, low => disabled 37 | 38 | watchdog after reset enabled 39 | B6 FF D7 BB 9F 40 | --> MCS2 bit 5 controls watchdog after reset. high => disabled, low => enabled 41 | 42 | watchdog prescaler 128 43 | B4 FF F6 BB 9F 44 | watchdog prescaler 64 45 | B5 FF F5 BB 9F 46 | watchdog prescaler 32 47 | B5 FF F4 BB 9F 48 | watchdog prescaler 2 49 | B6 FF F0 BB 9F 50 | --> MCS2 bits 0-2 control watchdog prescaler. mapping is similar to early STC15. 51 | 52 | wdt stop in idle disabled 53 | B7 FF FF BB 9F 54 | 55 | erase eeprom next programming 56 | B4 FF F7 BB 9F 57 | --> it's somewhere else! it's bit 1 of the extra MCSX byte that is typically 0xfd. low => erase eeprom disabled, high => erase eeprom enabled 58 | 59 | 60 | p3.3 por state enabled 61 | B9 FF F7 BB 97 62 | --> MCS4 bit 3 controls the p3.3 state. high => p3.3 high, low => p3.3 low 63 | 64 | p3.1 passthrough from p3.0 enabled 65 | B5 FF F7 BB DF 66 | --> MCS4 bit 2 controls the p3.1 passthrough. low => passthrough disabled, high => passthrough enabled 67 | 68 | p3.1 push pull enabled 69 | B5 FF F7 BB BF 70 | --> MCS4 bit 1 controls p3.1 push pull. low => quasi-bidi, high => push-pull 71 | 72 | bsl pindetect enabled 73 | B5 FF F7 BB BF 74 | --> somewhere else, MCSX bit 0. low => pindetect enabled, high => pindetect disabled. 75 | 76 | 77 | external oscillator enabled (IAP15F2K61S2) 78 | 9C 7F F7 BB 9E 79 | --> MCS4 bit 0 controls external oscillator. low => use external crystal, high => use RC. 80 | 81 | external oscillator enabled + clock gain low (IAP15F2K61S2) 82 | 9C 7F F7 BB 9C 83 | --> MCS 4 bit controls clock gain. high => high clock gain, low => low clock gain. 84 | 85 | 86 | cpu core supply level (MCSY) 87 | 88 | in status packet: 89 | 90 | 2.68v 91 | 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 92 | 93 | 3.33v 94 | 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 95 | 96 | 3.63v 97 | 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 98 | 99 | 3.73v 100 | 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 101 | ^^ 102 | MCSY 103 | 104 | voltage: ff -> 3.73v 105 | fd -> 3.63v 106 | f7 -> 3.33v 107 | ea -> 2.68v 108 | 109 | in set options packet: 110 | 111 | 46 B9 6A 00 4B 04 00 00 5A A5 FF FF FF 00 FF FF 112 | 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 113 | 00 00 FF A8 FF EE FF E0 FF FD 03 FF FF FF FF FF 114 | ^^ 115 | MCSP 116 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 117 | FF FD FF FF FF 75 BF F7 BC 9F 3A 80 16 118 | ^^ 119 | MCSY 120 | 121 | password setting 122 | 123 | the password is sent with packet type 0x07 and checked before erase with packet type 0x05. setting the password uses two fields. 124 | index 22 of the option block encodes the password length in bytes (MCSP, see above). bit 3 in MCS3 decides whether the password 125 | will be checked. if the bit is set, no password check occurs. if it is reset, a password check occurs. 126 | 127 | quick dump from USB-ISP packets: 128 | 129 | set: foobar 130 | 0000 ff ff ff 00 ff ff 00 05 ff ff ff ff ff ff ff 07 ................ 131 | 0010 ff ff ff ff ff ff ff 07 ff 06 01 ff 6e ff 36 58 ............n.6X 132 | 0020 ff 00 ff f5 03 ff ff 0c ff ff ff ff ff ff ff 07 ................ 133 | 0030 ff ff ff ff ff ff ff 07 ff ff ff ff ff ff ec 1a ................ 134 | 0040 ff ff ff 99 7f f7 bc 38 9f 61 .......8.a 135 | 136 | reset: 137 | 0000 ff ff ff 00 ff ff 00 05 ff ff ff ff ff ff ff 07 ................ 138 | 0010 ff ff ff ff ff ff ff 07 ff 00 01 ff 6e ff 36 5e ............n.6^ 139 | 0020 ff 00 ff fd 03 ff ff 04 ff ff ff ff ff ff ff 07 ................ 140 | 0030 ff ff ff ff ff ff ff 07 ff ff ff ff ff ff ec 1a ................ 141 | 0040 ff ff ff 99 7f f7 bc 38 9f 61 .......8.a 142 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc15-protocol.txt: -------------------------------------------------------------------------------- 1 | STC15 protocol 2 | ============== 3 | 4 | high level 5 | ---------- 6 | 7 | -> pulse 8 | <- info packet 9 | 10 | -> freq challenges round 1 11 | <- freq responses 12 | 13 | -> freq challenges round 2 14 | <- freq responses 15 | 16 | -> baud switch 17 | <- ack 18 | 19 | -> prepare 20 | <- ack 21 | 22 | -> erase 23 | <- ack + uid 24 | 25 | -> write first block 26 | <- ack 27 | 28 | -> write block 2 29 | <- ack 30 | 31 | ... 32 | 33 | -> write block n 34 | <- ack 35 | 36 | -> option packet 37 | <- ack 38 | 39 | 40 | info packet 41 | ----------- 42 | 43 | 6 MHz: 44 | 46 B9 68 00 2B 50 66 3C 93 BA F7 BB 9F 00 5B 68 00 FD 00 00 00 00 71 51 03 F2 D4 04 06 58 BA 02 2A 31 32 38 30 80 14 10 04 D9 0D 02 16 45 | 46 | 12 MHz: 47 | 46 B9 68 00 2B 50 66 3C 93 BA F7 BB 9F 00 B6 F5 80 FD 00 00 00 00 71 51 03 F2 D4 04 06 58 BA 02 2A 31 32 38 30 80 14 10 04 D9 0E 6A 16 48 | 49 | 33 MHz: 50 | 46 B9 68 00 2B 50 66 3C 93 BA F7 B9 9F 01 F7 C2 80 FD 00 00 00 00 71 51 03 F2 D4 04 06 58 BA 02 2A 31 32 38 30 80 14 10 04 D9 0E 77 16 51 | 52 | 30 MHz: 53 | 46 B9 68 00 2B 50 66 3C 93 BA F7 B9 9F 01 C9 9E 00 FD 7F FF FD FF 71 51 03 F2 D4 04 06 58 BA 02 2A 31 32 38 30 80 14 10 04 D9 11 1F 16 54 | ^^^^^ ^^^^^^^^^^^ 55 | timer freq freq big endian 56 | value in hz 32 bit value 57 | ^^^^^^^^ ^^ 58 | MCS2-4 MCSX 59 | ^^ 60 | factory calibration adjust for 24 MHz (range 0x40)? 61 | 62 | STC15W4K56S4: 63 | 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 64 | ^^ 65 | core voltage (MCSY) 66 | 67 | IAP15F2K61S2: 68 | external osc: 69 | 46 B9 68 00 2B 50 87 D3 75 9C F7 BB 9E 01 77 70 80 FD 06 57 00 00 71 53 00 F4 49 04 06 58 9C 02 0E 14 17 19 19 00 F4 F4 04 D2 0E 8A 16 70 | ^^^^^ 71 | frequency count for external (1) 72 | 73 | (1) if external clock is active, frequency can be calculated like: 74 | CLOCK = BAUD * COUNT 75 | 76 | internal 11.052 MHz: 77 | 46 B9 68 00 2B 50 87 D3 75 9C F7 BB 9F 00 A8 AD 40 FD 09 FE 00 00 71 53 00 F4 49 04 06 58 9C 02 0E 14 17 19 19 00 F4 F4 04 D2 0F 62 16 78 | 79 | 80 | i.e. operating frequency is not sampled from host pulses! it's actually much more 81 | convenient, it is simply returned as an integer value in hz. same for the wakeup 82 | timer. 83 | 84 | baud switch packet 85 | ------------------ 86 | 87 | 46 B9 6A 00 0E 01 8C 40 F6 FD F2 7C 83 05 29 16 88 | ^^^^^ ^^^^^ ^^ 89 | (1) (2) (3) 90 | ^^^^^ 91 | prog calib. values 92 | (1) baud value (65535 - clk / baud) (SW UART) 93 | (65535 - clk / baud / 4) (HW UART) 94 | (2) some timer value (65535 - (clk / baud) * 1.5) 95 | (3) constant? IAP delay? 96 | 97 | 98 | trim challenge packet 99 | --------------------- 100 | 101 | two challenges are sent, UART seems to be used as clock reference 102 | 103 | 33.1 MHz @ 9600 bps: 104 | -> 46 B9 6A 00 20 00 0B 00 C0 80 C0 FF C0 00 80 80 80 FF 80 00 40 80 40 FF 40 00 00 80 00 00 00 0A 12 16 92 92 92 92 105 | 106 | 4 MHz @ 9600 bps: 107 | -> 46 B9 6A 00 20 00 0B 00 C0 80 C0 FF C0 00 80 80 80 FF 80 00 40 80 40 FF 40 00 00 80 00 00 00 0A 12 16 92 92 92 92 108 | 109 | 6 MHz @ 9600 bps: 110 | -> 46 B9 6A 00 20 00 0B 00 C0 80 C0 FF C0 00 80 80 80 FF 80 00 40 80 40 FF 40 00 00 80 00 00 00 0A 12 16 92 92 92 92 111 | <- 46 B9 68 00 20 00 0B 03 05 04 4F 05 9E 06 20 08 B9 0B 57 0C 60 11 6A 16 5B 13 5E 1A D4 00 00 05 91 16 112 | 113 | -> 46 B9 6A 00 20 00 0C B4 C0 B5 C0 B6 C0 B7 C0 B8 C0 B9 C0 8C 40 8D 40 8E 40 8F 40 90 40 91 40 0E 34 16 92 92 92 92 114 | <- 46 B9 68 00 20 00 0C 04 DB 04 DB 04 DB 04 E0 04 E5 04 E5 11 EC 11 F6 12 05 12 05 12 0F 12 14 08 60 16 115 | 116 | 12 MHz @ 9600 bps: 117 | -> 46 B9 6A 00 20 00 0B 00 C0 80 C0 FF C0 00 80 80 80 FF 80 00 40 80 40 FF 40 00 00 80 00 00 00 0A 12 16 92 92 92 92 118 | <- 46 B9 68 00 20 00 0B 03 05 04 4F 05 99 06 20 08 B4 0B 52 0C 65 11 6F 16 56 13 5E 1A D4 00 00 05 87 16 119 | 120 | -> 46 B9 6A 00 20 00 0C B0 80 B1 80 B2 80 B3 80 B4 80 B5 80 8B 40 8C 40 8D 40 8E 40 8F 40 90 40 0C 96 16 92 92 92 92 121 | <- 46 B9 68 00 20 00 0C 09 B8 09 BD 09 C2 09 C7 09 C7 09 D1 11 DD 11 EC 11 FB 12 00 12 0A 12 0F 08 A6 16 122 | ^^^^^ 123 | number of challenges used (here: 12) 124 | 125 | looks like two byte calibration values are used; second byte is the rough value, first byte is fine adjust 126 | first round selects a rough range 127 | second round refines inside that range and another (for programming speed) 128 | 129 | (CLOCK / (BAUD/2)) = COUNTER 130 | => CLOCK = COUNTER * (BAUD/2) 131 | 132 | the first packet always uses a fixed set of challenges. 133 | first calibration byte of chosen frequency is stored in options. the second calibration byte is stored added together 134 | with the value 0x3f in the next option byte. 135 | a factory frequency value (24 MHz) is available in the info packet. 136 | the calibration value for the programming frequency (always range 0x40) is transmitted with the baud change packet. 137 | 138 | 139 | option packet 140 | ------------- 141 | 142 | 46 B9 6A 00 49 04 00 00 FF FF FF 00 FF FF 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 FF 5B FF 68 FF 00 143 | ^^^^^^^^^^^^^^^^^^^^ 144 | frequency in hz, with FF bytes inbetween 145 | 146 | FF FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF B5 FF F7 BB 9F 3A 48 16 147 | ^ ^^^^^^^^^^^^^^ 148 | MCSX ^^ MCS0-4 149 | MCSY 150 | (STC15W4) 151 | 152 | MCS bytes 153 | --------- 154 | 155 | ### MCS0 156 | 157 | RC calibration adjust 158 | 159 | ### MCS1 160 | 161 | 0x3f + RC calibration range (0x00, 0x40, 0x80, 0xc0) 162 | 163 | ### MCS2 - MCS4, MCSX and MCSY 164 | 165 | See stc15-options.txt 166 | 167 | 168 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc15-usb-protocol.txt: -------------------------------------------------------------------------------- 1 | STC15 series USB ISP protocol 2 | ============================= 3 | 4 | General principle 5 | ----------------- 6 | 7 | - host does OUT and IN control transfers for write and read 8 | - IN transfer with wLength = 132, wValue = 0, wIndex = 0, bRequest = 0 are used for all reads 9 | - OUT transfers with with specific bRequest, wValue, wIndex are used for writes 10 | 11 | 12 | Packet coding 13 | ------------- 14 | 15 | - packets from MCU 16 | always start with 0x46 0xb9, similar to serial protocols 17 | third byte is packet length, followed by data bytes 18 | checksum at the end: 8 bit modular sum 19 | 20 | - packets from host 21 | no header bytes 22 | bRequest sets packet type 23 | wValue, wIndex interpretation according to packet type 24 | 8 bit modular checksum for every 7 bytes, interleaved 25 | 26 | - packet types derived from the serial protocol 27 | 28 | Specific packet information 29 | --------------------------- 30 | 31 | - flash data 32 | wIndex specifies write address 33 | wValue is 0xa55a 34 | bRequest is 0x22 for first packet, 0x02 for the following ones 35 | unusually encoded: a total of 128 bytes per packet, 36 | with every 7 byte checksummed in some way, 37 | for a total of 18x7 byte segments and a final 2 byte segment 38 | checksum: 8 bit modular sum 39 | 40 | - option packet 41 | generally same as with serial protocol, some header stuff omitted 42 | wIndex is 0 43 | wValue is 0xa55a 44 | bRequest is 4 45 | seems to use the same checksumming scheme as flash writes 46 | 47 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc15a-options.txt: -------------------------------------------------------------------------------- 1 | Model-specific configuration registers 2 | Placement of configuration values 3 | 4 | "~" means the bit is a negated boolean. Sometimes values overlap, 5 | depending on MCU model. 6 | 7 | In STC15 series, the first 13 MCS bytes have active values. Generally, 8 | unused bits should be set to 1. 9 | 10 | MCS0 11 | ---- 12 | 13 | MSB 7 6 5 4 3 2 1 0 LSB 14 | RSPEN 15 | 16 | RSPEN := RESET pin enable 17 | 18 | 19 | MCS1 20 | ---- 21 | 22 | MSB 7 6 5 4 3 2 1 0 LSB 23 | EEIH LVRS LVD2 LVD1 LVD0 24 | 25 | EEIH := inhibit EEPROM writes in low-voltage conditions enable 26 | LVRS := low-voltage reset enable 27 | LVD2...LVD0 := low voltage detection threshold 28 | 29 | LVD2 LVD1 LVD0 value 30 | 0 0 0 setting 0 (e.g. 3.14V) 31 | 0 0 1 setting 1 (e.g. 3.28V) 32 | 0 1 0 setting 2 (e.g. 3.43V) 33 | 0 1 1 setting 3 (e.g. 3.61V) 34 | 1 0 0 setting 4 (e.g. 3.82V) 35 | 1 0 1 setting 5 (e.g. 4.05V) 36 | 1 1 0 unknown 37 | 1 1 1 unknown 38 | 39 | The exact voltages depend on MCU model. 40 | 41 | 42 | MCS2 43 | ---- 44 | 45 | MSB 7 6 5 4 3 2 1 0 LSB 46 | ~WDEN ~WDSTP WDPS2 WDPS1 WDPS0 47 | 48 | ~WDEN := watchdog enable after power-on-reset 49 | ~WDSTP := stop watchdog counter in idle mode 50 | WDPS2...WDPS0 := watchdog counter prescaler 51 | 52 | WDPS2 WDPS1 WDPS0 divisior 53 | 0 0 0 2 54 | 0 0 1 4 55 | 0 1 0 8 56 | 0 1 1 16 57 | 1 0 0 32 58 | 1 0 1 64 59 | 1 1 0 128 60 | 1 1 1 256 61 | 62 | This is completely similar to STC12. 63 | 64 | 65 | MCS3...MCS11 66 | ------------ 67 | 68 | All bytes set to 0xff. 69 | 70 | 71 | MCS12 72 | ----- 73 | 74 | MSB 7 6 5 4 3 2 1 0 LSB 75 | ~EREE ~BSLD 76 | 77 | ~EREE := enable eeprom erase next time MCU is programmed 78 | ~BSLD := enable BSL pin detect; i.e. BSL is only enabled if P1.0/P1.1 79 | (or others, depends on MCU model) are held low on POR. 80 | 81 | This is like MCS3 of STC12. 82 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc15a-protocol.txt: -------------------------------------------------------------------------------- 1 | STC15 reverse engineering 2 | 3 | Note: so far only based on STC15F104E! This protocol has been renamed ot STC15A. 4 | 5 | Basic differences between STC12 and STC15 6 | 7 | * Initial MCU response is an ack (0x80) packet. Host needs to respond 8 | with the same ack and pulse 0x7f again, then MCU sends the info 9 | packet. 10 | 11 | * Frequency timings sent with info packet are different; the calculation 12 | is the same but only four timings are sent, followed by two other 13 | unknown timings and two zero words. 14 | 15 | * A new handshake is used to tune the RC oscillator for a given 16 | frequency. 17 | 18 | * The baudrate isn't changed with a complicated handshake, it is just 19 | switched to with a 0x8e type packet. 20 | This may be different on other MCUs that have a hardware UART. 21 | 22 | * Transfers use 64 bytes block size. 23 | Possibly that's because the 15F104E only has 128 bytes RAM. It 24 | might use bigger blocks on MCUs with more RAM. 25 | 26 | * Position of many option bits has changed, and more bits are used. 27 | 28 | 29 | The RC oscillator calibration 30 | 31 | Theory of operation: 32 | * Host sends a sequence of challenges. These are values to be 33 | programmed into an internal RC oscillator calibration register. 34 | * Host sends 0x7f pulses 35 | * MCU sends back responses, which are the runtime of the baudrate 36 | timing counter (similar to the info packet) 37 | * Host repeats this with finer trimmed challenge values. 38 | * Host determines calibration value with the lowest error. 39 | * Host sends baudrate switch packet 40 | * Host sends option packet to program frequency after flash programming 41 | 42 | The STC software uses a fixed set of coarse grained trim values to 43 | try. These are: 44 | 45 | sequence clock (MHz) 46 | 0x1800 0x1880 0x1880 0x18ff [4, 7.5] 47 | 0x1880 0x18ff 0x5800 0x5880 (7.5, 10] 48 | 0x5800 0x5880 0x5880 0x58ff (10, 15] 49 | 0x5880 0x58ff 0x9800 0x9880 (15, 21] 50 | 0x9800 0x9880 0x9880 0x98ff (21, 31] 51 | 0xd800 0xd880 0xd880 0xd8b4 (31, 40] 52 | 53 | In addition it sends a sequence for the programming speed: 54 | 0x5800 0x5880 for normal speed and 0x9800 0x9880 for high 55 | speed programming. 56 | 57 | Then, by linear interpolation, it choses a suitable range of 58 | fine-tuning trim values to try according to the counter values sent 59 | by the MCU. 60 | 61 | The programming speed trim value is only determined by linear 62 | interpolation of the two trim challenges sent in the first round of 63 | calibration. This seems to be good enough. 64 | 65 | 66 | New packets host2mcu 67 | -------------------- 68 | 69 | 1. RC calibration challenge 70 | 71 | Payload: 0x65, T0, .., T6, 0xff, 0xff, 0x06, CNT, 72 | TR00, TR01, 0x02, 0x00, 73 | TR10, TR11, 0x02, 0x00, 74 | ... 75 | 76 | T0...T6 := trim constants, from info packet 77 | CNT := number of calibration challenges (max 11) 78 | TRxx := calibration challenge trim values 79 | 80 | 2. Baudrate switch 81 | 82 | Payload: 0x8e, TR0, TR1, BDIV, 0xa1, 0x64, FC, 83 | 0x00, IAP, 0x20, 0xff, 0x00 84 | 85 | TR0, TR1 := trim value for programming frequency 86 | (normal = 11.0592 MHz, highspeed = 22.1184 MHz) 87 | BDIV := baud rate divider (normal: baud = 115200 / BDIV, highspeed: baud = 230400 / BDIV) 88 | FC := some frequency constant, normal: 0xdc, highspeed: 0xb8 89 | IAP := IAP delay, normal: 0x83, highspeed: 0x81 90 | 91 | 92 | 93 | Communication dump with notes 94 | ----------------------------- 95 | 96 | Firmware version: 6.7Q 97 | Magic: F294 98 | UID: 0A00002802C4EB 99 | 100 | This seems to work differently from what we've seen on STC10/11/12 series with 101 | firmware 6.2/6.5. 102 | 103 | Get status packet 104 | ----------------- 105 | 106 | mcu2host: 107 | 108 | 2014-01-09 11:35:17.917063: 109 | 46 B9 68 00 07 80 00 EF 16 110 | 2014-01-09 11:35:18.056583: 111 | 46 B9 68 00 40 50 02 B0 02 B0 02 AF 02 B0 02 E6 112 | 02 E7 00 00 00 00 67 51 FF F2 94 8C EF 3B F5 58 113 | 34 FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 114 | FF FF FF FF FF FF FF FF 58 50 0C 94 21 FF 29 21 115 | 82 16 116 | 117 | host2mcu: 118 | 119 | 2014-01-09 11:37:13.000352: 120 | 7F 7F 7F 7F 46 B9 6A 00 07 80 00 F1 16 7F 7F 7F 121 | 7F 122 | 2014-01-09 11:37:13.298358: 123 | 46 B9 6A 00 07 82 00 F3 16 124 | 125 | * MCU first sends an ACK packet (0x80), 126 | which needs to be replied to with the same ACK (0x80) by the host. 127 | after that host needs to pulse (send 0x7f until reply) again 128 | 129 | * STC software then adjust the frequency of the RC, after that the handshake 130 | is done. 131 | 132 | Program hello.bin 133 | ----------------- 134 | 135 | host2mcu: 136 | 137 | FF 7F 7F 7F 7F 46 B9 6A 00 07 80 00 F1 16 7F 7F 138 | 7F 7F 7F 7F 139 | 2014-01-09 11:46:06.334342: 140 | 46 B9 6A 00 0D 50 00 00 36 01 F2 94 02 84 16 141 | ^ Initiate baudrate handshake, like STC12 142 | 143 | 144 | 46 145 | B9 6A 00 2A 65 58 50 0C 95 21 FF 2B FF FF 06 06 146 | 58 00 02 00 58 80 02 00 58 80 02 00 58 FF 02 00 147 | 58 00 02 00 58 80 02 00 0A 32 16 148 | ^ This is a new type of packet (0x65), presumably 149 | for frequency adjustment 150 | 151 | 152 | 7F 7F 7F 7F 7F 153 | 7F 7F 7F 7F 7F 7F 7F 154 | 46 B9 6A 00 3E 65 58 50 0C 155 | 95 21 FF 2B FF FF 06 0B 58 24 02 00 58 25 02 00 156 | 58 26 02 00 58 27 02 00 58 28 02 00 58 29 02 00 157 | 58 2A 02 00 58 2B 02 00 58 2C 02 00 58 2D 02 00 158 | 58 2E 02 00 0B 51 16 159 | ^ Same new packet again! 160 | 161 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 162 | 7F 7F 7F 7F 7F 7F 46 B9 6A 00 12 8E 58 29 0C A1 163 | 64 DC 12 83 20 FF 00 05 2C 16 164 | ^ Straight jumps to setting the new baudrate, 165 | instead of testing it like in earlier firmware. 166 | 167 | 2014-01-09 11:46:07.466357: 168 | 46 B9 6A 00 3B 84 FF 00 02 00 00 10 00 00 00 00 169 | 00 00 00 00 00 00 00 00 80 7F 7E 7D 7C 7B 7A 79 170 | 78 77 76 75 74 73 72 71 70 6F 6E 6D 6C 6B 6A 69 171 | 68 67 66 65 64 63 62 61 60 5F 11 09 16 172 | ^ erase flash 173 | 174 | 2014-01-09 11:46:08.322346: 175 | 46 B9 6A 00 4D 00 00 00 00 00 00 40 02 00 08 12 176 | 00 3F 80 FE 75 81 07 12 00 4C E5 82 60 03 02 00 177 | 03 E4 78 FF F6 D8 FD 02 00 03 AE 82 AF 83 8E 04 178 | 8F 05 1E BE FF 01 1F EC 4D 60 0F 7C 90 7D 01 1C 179 | BC FF 01 1D EC 4D 70 F7 80 E4 22 90 1A 85 16 180 | 181 | 46 182 | B9 6A 00 4D 00 00 00 00 40 00 40 03 E8 12 00 1E 183 | E5 80 F4 F5 80 80 F3 75 82 00 22 00 00 00 00 00 184 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 185 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 186 | 00 00 00 00 00 00 00 00 00 00 00 08 AC 16 187 | 188 | 46 B9 189 | 6A 00 4D 00 00 00 00 80 00 40 00 00 00 00 00 00 190 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 191 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 192 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 193 | 00 00 00 00 00 00 00 00 00 00 01 77 16 194 | 195 | 46 B9 6A 196 | 00 4D 00 00 00 00 C0 00 40 00 00 00 00 00 00 00 197 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 198 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 199 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 200 | 00 00 00 00 00 00 00 00 00 01 B7 16 201 | 202 | 46 B9 6A 00 203 | 4D 00 00 00 01 00 00 40 00 00 00 00 00 00 00 00 204 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 205 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 206 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 207 | 00 00 00 00 00 00 00 00 00 F8 16 208 | 209 | 46 B9 6A 00 4D 210 | 00 00 00 01 40 00 40 00 00 00 00 00 00 00 00 00 211 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 212 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 213 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 214 | 00 00 00 00 00 00 00 01 38 16 215 | 216 | 46 B9 6A 00 4D 00 217 | 00 00 01 80 00 40 00 00 00 00 00 00 00 00 00 00 218 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 219 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 220 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 221 | 00 00 00 00 00 00 01 78 16 222 | 223 | 46 B9 6A 00 4D 00 00 224 | 00 01 C0 00 40 00 00 00 00 00 00 00 00 00 00 00 225 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 226 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 227 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 228 | 00 00 00 00 00 01 B8 16 229 | 230 | ^ flash write packets. curiously they use 231 | a smaller block size, 64 bytes. 232 | 233 | 46 B9 6A 00 0D 69 00 00 234 | 36 01 F2 94 02 9D 16 235 | ^ finish packet 236 | 237 | 2014-01-09 11:46:09.571449: 238 | 46 B9 6A 00 1A 8D EF FC F7 58 29 FF FF FF FF FF 239 | FF FF FF FF FF FF FF FF FF 12 66 16 240 | ^ set options packet 241 | 242 | 2014-01-09 11:46:09.774383: 243 | 46 B9 6A 00 07 82 00 F3 16 244 | ^ reset packet 245 | 246 | mcu2host: 247 | 248 | 2014-01-09 11:49:50.004984: 249 | 46 B9 68 00 07 80 00 EF 16 250 | ^ ACK 251 | 252 | 2014-01-09 11:49:50.166675: 253 | 46 B9 68 00 40 50 02 9C 02 9C 02 9C 02 9C 02 E6 254 | 02 E7 00 00 00 00 67 51 FF F2 94 8C EF FC F7 58 255 | 29 FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 256 | FF FF FF 12 FF FF FF FF 58 50 0C 95 21 FF 2B 21 257 | 01 16 258 | ^ status packet 259 | 260 | 46 B9 68 00 07 8F 00 FE 16 261 | ^ acknowledge handshake 262 | 263 | 2014-01-09 11:49:50.566935: 264 | 46 B9 68 00 2A 65 58 50 0C 95 21 FF 2B FF FF 06 265 | 06 58 00 02 4A 58 80 03 45 58 80 03 46 58 FF 04 266 | 3D 58 00 02 4A 58 80 03 45 0B D6 16 267 | ^ reply to first new 0x65 packet 268 | 269 | 2014-01-09 11:49:50.941928: 270 | 46 B9 68 00 3E 65 58 50 0C 95 21 FF 2B FF FF 06 271 | 0B 58 24 02 92 58 25 02 94 58 26 02 97 58 27 02 272 | 9A 58 28 02 9A 58 29 02 9C 58 2A 02 9F 58 2B 02 273 | A2 58 2C 02 A1 58 2D 02 A4 58 2E 02 A8 12 0A 16 274 | ^ reply to second 0x65 packet 275 | 276 | 2014-01-09 11:49:51.391860: 277 | 46 B9 68 00 13 84 58 29 0C A1 64 DC 12 83 20 FF 278 | ^ new packet type (0x84) 279 | 280 | 00 05 05 26 16 281 | 2014-01-09 11:49:52.253370: 282 | 46 B9 68 00 0E 00 0A 00 00 28 02 C4 EB 02 59 16 283 | ^ acknowledge erase 284 | 285 | 2014-01-09 11:49:52.393369: 286 | 46 B9 68 00 08 00 8E 00 FE 16 287 | 2014-01-09 11:49:52.518566: 288 | 46 B9 68 00 08 00 75 00 E5 16 289 | 2014-01-09 11:49:52.643749: 290 | 46 B9 68 00 08 00 00 00 70 16 291 | 2014-01-09 11:49:52.772755: 292 | 46 B9 68 00 08 00 00 00 70 16 293 | 2014-01-09 11:49:52.905131: 294 | 46 B9 68 00 08 00 00 00 70 16 295 | 2014-01-09 11:49:53.047673: 296 | 46 B9 68 00 08 00 00 00 70 16 297 | 2014-01-09 11:49:53.170668: 298 | 46 B9 68 00 08 00 00 00 70 16 299 | 2014-01-09 11:49:53.299131: 300 | 46 B9 68 00 08 00 00 00 70 16 301 | ^ acknowlegde flash writes 302 | 303 | 2014-01-09 11:49:53.460551: 304 | 46 B9 68 00 07 8D 00 FC 16 305 | ^ acknowledge finish flash programming 306 | 307 | | last three bytes of UID 308 | 46 B9 68 00 2F 50 02 309 | C4 EB 58 29 03 FF 67 51 EF FC F7 58 29 FF FF FF 310 | FF FF FF FF FF FF FF FF FF FF FF 12 FF FF FF FF 311 | 00 00 00 00 00 00 00 1A 36 16 312 | ^ acknowledge set options 313 | 314 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc15l104w.txt: -------------------------------------------------------------------------------- 1 | 2015-11-20 01:39:38.554555: PC 2 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 3 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 4 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 5 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 6 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 8 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 9 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 10 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 11 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 12 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 13 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 14 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 15 | 2015-11-20 01:39:41.744739: MCU 16 | 46 B9 68 00 2B 50 66 3C 93 BA F7 BB 9F 00 5B 68 17 | 00 FD 00 00 00 00 71 51 03 F2 D4 04 06 58 BA 02 18 | 2A 31 32 38 30 80 14 10 04 D9 0D 02 16 19 | 2015-11-20 01:39:41.839211: PC 20 | 46 B9 6A 00 20 00 0B 00 C0 80 C0 FF C0 00 80 80 21 | 80 FF 80 00 40 80 40 FF 40 00 00 80 00 00 00 0A 22 | 12 16 92 92 92 92 23 | 2015-11-20 01:39:41.932603: MCU 24 | 46 B9 68 00 20 00 0B 03 0A 04 4F 05 9E 06 20 08 25 | B9 0B 5C 0C 6A 11 7E 16 79 13 77 1A B1 00 00 05 26 | CD 16 27 | 2015-11-20 01:39:41.975503: PC 28 | 46 B9 6A 00 20 00 0C B4 C0 B5 C0 B6 C0 B7 C0 B8 29 | C0 B9 C0 89 40 8A 40 8B 40 8C 40 8D 40 8E 40 0E 30 | 22 16 92 92 92 92 31 | 2015-11-20 01:39:42.058079: MCU 32 | 46 B9 68 00 20 00 0C 04 D6 04 DB 04 E0 04 E0 04 33 | E0 04 E5 11 E2 11 F1 11 FB 12 05 12 0A 12 19 09 34 | 41 16 35 | 2015-11-20 01:39:42.106052: PC 36 | 46 B9 6A 00 0E 01 8C 40 F6 FD F2 7C 83 05 29 16 37 | 2015-11-20 01:39:42.130699: MCU 38 | 46 B9 68 00 07 01 00 70 16 39 | 2015-11-20 01:39:42.355652: PC 40 | 46 B9 6A 00 07 05 00 76 16 41 | 2015-11-20 01:39:42.369748: MCU 42 | 46 B9 68 00 07 05 00 74 16 43 | 2015-11-20 01:39:42.385566: PC 44 | 46 B9 6A 00 08 03 00 00 75 16 45 | 2015-11-20 01:39:42.762099: MCU 46 | 46 B9 68 00 0E 03 0C 00 00 17 01 A0 E0 02 1D 16 47 | 2015-11-20 01:39:42.793627: PC 48 | 46 B9 6A 00 49 22 00 00 02 00 08 12 00 3F 80 FE 49 | 75 81 07 12 00 4C E5 82 60 03 02 00 03 E4 78 FF 50 | F6 D8 FD 02 00 03 AE 82 AF 83 8E 04 8F 05 1E BE 51 | FF 01 1F EC 4D 60 0F 7C 90 7D 01 1C BC FF 01 1D 52 | EC 4D 70 F7 80 E4 22 90 1A 63 16 53 | 2015-11-20 01:39:42.898503: MCU 54 | 46 B9 68 00 08 02 54 00 C6 16 55 | 2015-11-20 01:39:42.915747: PC 56 | 46 B9 6A 00 49 02 00 40 03 E8 12 00 1E E5 80 F4 57 | F5 80 80 F3 75 82 00 22 00 00 00 00 00 00 00 00 58 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 | 00 00 00 00 00 00 00 00 08 6A 16 61 | 2015-11-20 01:39:43.020455: MCU 62 | 46 B9 68 00 08 02 54 00 C6 16 63 | 2015-11-20 01:39:43.036976: PC 64 | 46 B9 6A 00 49 02 00 80 00 00 00 00 00 00 00 00 65 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 66 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 67 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 | 00 00 00 00 00 00 00 00 01 35 16 69 | 2015-11-20 01:39:43.142916: MCU 70 | 46 B9 68 00 08 02 54 00 C6 16 71 | 2015-11-20 01:39:43.159889: PC 72 | 46 B9 6A 00 49 02 00 C0 00 00 00 00 00 00 00 00 73 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 74 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 75 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 76 | 00 00 00 00 00 00 00 00 01 75 16 77 | 2015-11-20 01:39:43.249802: MCU 78 | 46 B9 68 00 08 02 54 00 C6 16 79 | 2015-11-20 01:39:43.266503: PC 80 | 46 B9 6A 00 49 02 01 00 00 00 00 00 00 00 00 00 81 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 82 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 83 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 84 | 00 00 00 00 00 00 00 00 00 B6 16 85 | 2015-11-20 01:39:43.366446: MCU 86 | 46 B9 68 00 08 02 54 00 C6 16 87 | 2015-11-20 01:39:43.383638: PC 88 | 46 B9 6A 00 49 02 01 40 00 00 00 00 00 00 00 00 89 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 90 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 91 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 92 | 00 00 00 00 00 00 00 00 00 F6 16 93 | 2015-11-20 01:39:43.477298: MCU 94 | 46 B9 68 00 08 02 54 00 C6 16 95 | 2015-11-20 01:39:43.494433: PC 96 | 46 B9 6A 00 49 02 01 80 00 00 00 00 00 00 00 00 97 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 98 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 99 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 100 | 00 00 00 00 00 00 00 00 01 36 16 101 | 2015-11-20 01:39:43.600474: MCU 102 | 46 B9 68 00 08 02 54 00 C6 16 103 | 2015-11-20 01:39:43.617482: PC 104 | 46 B9 6A 00 49 02 01 C0 00 00 00 00 00 00 00 00 105 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 106 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 107 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 108 | 00 00 00 00 00 00 00 00 01 76 16 109 | 2015-11-20 01:39:43.721087: MCU 110 | 46 B9 68 00 08 02 54 00 C6 16 111 | 2015-11-20 01:39:43.746765: PC 112 | 46 B9 6A 00 49 04 00 00 FF FF FF 00 FF FF 00 FF 113 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 114 | FF 5B FF 68 FF 00 FF FD FF FF FF FF FF FF FF FF 115 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 116 | FF FF FF B6 FF F7 BB 9F 3A 49 16 117 | 2015-11-20 01:39:43.863822: MCU 118 | 46 B9 68 00 08 04 54 00 C8 16 -------------------------------------------------------------------------------- /doc/reverse-engineering/stc15w4.txt: -------------------------------------------------------------------------------- 1 | fresh chip, RC frequency untuned, caught with stcgal 2 | 3 | 2015-12-10 23:39:46.886233: PC 4 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 5 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 6 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 8 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 9 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 10 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 11 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 12 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 13 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 14 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 15 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 16 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 17 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 18 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 19 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 20 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 21 | 2015-12-10 23:39:50.989044: MCU 22 | 46 B9 68 00 34 50 8D FF 73 96 F5 7B 9F FF FF FF 23 | FF FF 25 EF 00 00 73 54 00 F5 28 04 06 70 96 02 24 | 15 19 1C 1E 23 00 EC E0 04 D7 F8 73 BF FF FF 15 25 | 09 25 60 16 92 16 26 | 2015-12-10 23:39:51.231028: PC 27 | 46 B9 6A 00 07 82 00 F3 16 28 | 29 | Checking target MCU ... 30 | MCU type: STC15W4K56S4 31 | F/W version: 7.3.4T 32 | 33 | Current H/W Option: 34 | . Current system clock source is internal IRC oscillator 35 | . IRC is unadjusted 36 | . Oscillator gain is HIGH 37 | . Wakeup Timer frequency: 36.351KHz 38 | . Do not detect the level of P3.2 and P3.3 next download 39 | . Power-on reset, use the extra power-on delay 40 | . RESET pin behaves as I/O pin 41 | . Interrupt while detect a Low-Voltage 42 | . Thresh voltage level of the built-in LVD : 2.78 V 43 | . Permit EEPROM operation under Low-Voltag 44 | . CPU-Core supply level : 3.38 V 45 | . Hardware do not enable Watch-Dog-Timer 46 | . Watch-Dog-Timer pre-scalar : 64 47 | . Watch-Dog-Timer stop count in idle mode 48 | . Program can modify the Watch-Dog-Timer scalar 49 | . Erase user EEPROM area at next download 50 | . Do not control 485 at next download 51 | . Do not check user password next download 52 | . TXD is independent IO 53 | . TXD pin as quasi-bidirectional mode after reset 54 | . P2.0 output HIGH level after reset 55 | 56 | . MCU type: STC15W4K56S4 57 | F/W version: 7.3.4T 58 | 59 | Complete ! 60 | 61 | Waiting for MCU, please cycle power: done 62 | Target model: 63 | Name: STC15W4K56S4 64 | Magic: F528 65 | Code flash: 56.0 KB 66 | EEPROM flash: 3.0 KB 67 | Target frequency: 0.000 MHz 68 | Target BSL version: 7.3.4T 69 | Target wakeup frequency: 36.351 KHz 70 | Target options: 71 | reset_pin_enabled=False 72 | clock_source=internal 73 | clock_gain=high 74 | watchdog_por_enabled=False 75 | watchdog_stop_idle=True 76 | watchdog_prescale=64 77 | low_voltage_reset=False 78 | low_voltage_threshold=3 79 | eeprom_lvd_inhibit=False 80 | eeprom_erase_enabled=True 81 | bsl_pindetect_enabled=False 82 | por_reset_delay=long 83 | rstout_por_state=high 84 | uart2_passthrough=False 85 | uart2_pin_mode=normal 86 | Disconnected! 87 | 88 | 89 | cpu core supply level 90 | 91 | 2.68v 92 | 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 93 | 94 | 3.33v 95 | 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 96 | 97 | 3.63v 98 | 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 99 | 100 | 3.73v 101 | 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 102 | ^^ 103 | core voltage 104 | voltage: ff -> 3.73v 105 | fd -> 3.63v 106 | f7 -> 3.33v 107 | ea -> 2.68v 108 | 109 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc15w4k56s4.txt: -------------------------------------------------------------------------------- 1 | 2015-12-10 23:47:44.198341: PC 2 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 3 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 4 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 5 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 6 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 8 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 9 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 10 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 11 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 12 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 13 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 14 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 15 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 16 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 17 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 18 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 19 | 2015-12-10 23:47:48.400692: MCU 20 | 46 B9 68 21 | 2015-12-10 23:47:48.411946: PC 22 | 7F 23 | 2015-12-10 23:47:48.414811: MCU 24 | 00 34 50 25 | 2015-12-10 23:47:48.427644: PC 26 | 7F 27 | 2015-12-10 23:47:48.428894: MCU 28 | 8D FF 73 96 F5 7B 9F FF FF FF FF FF 27 ED 00 00 29 | 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 30 | EC E0 04 D7 F8 73 BF FF FF 15 09 25 60 16 92 16 31 | 2015-12-10 23:47:48.725370: PC 32 | 46 B9 6A 00 20 00 0B 00 C0 80 C0 FF C0 00 80 80 33 | 80 FF 80 00 40 80 40 FF 40 00 00 80 00 00 00 0A 34 | 12 16 FE FE FE FE FE FE FE FE FE FE FE FE FE 35 | 2015-12-10 23:47:49.088353: MCU 36 | 46 B9 68 37 | 2015-12-10 23:47:49.099586: PC 38 | FE 39 | 2015-12-10 23:47:49.102589: MCU 40 | 00 20 00 41 | 2015-12-10 23:47:49.115089: PC 42 | FE 43 | 2015-12-10 23:47:49.116479: MCU 44 | 0B 0D 21 12 BC 18 3E 1A 05 24 FA 2F B3 34 D1 4A 45 | 52 5E C0 52 DB 73 1A 00 00 08 7D 16 46 | 2015-12-10 23:47:49.266317: PC 47 | 46 B9 6A 00 20 00 0C 71 80 72 80 73 80 74 80 75 48 | 80 76 80 6F 40 70 40 71 40 72 40 73 40 74 40 0A 49 | 74 16 FE FE FE FE FE FE FE FE FE FE FE FE FE FE 50 | 2015-12-10 23:47:49.650397: MCU 51 | 46 B9 68 52 | 2015-12-10 23:47:49.661888: PC 53 | FE 54 | 2015-12-10 23:47:49.664523: MCU 55 | 00 20 00 56 | 2015-12-10 23:47:49.677636: PC 57 | FE 58 | 2015-12-10 23:47:49.678633: MCU 59 | 0C 23 BF 23 D3 23 E7 23 F6 24 0F 24 23 47 73 47 60 | B9 47 E1 48 09 48 36 48 59 09 5B 16 61 | 2015-12-10 23:47:49.944529: PC 62 | 46 B9 6A 00 0E 01 72 40 F6 FF 80 73 81 04 94 16 63 | 2015-12-10 23:47:50.045100: MCU 64 | 46 B9 68 00 07 01 00 70 16 65 | 2015-12-10 23:47:50.116096: PC 66 | 46 B9 6A 00 0B 05 00 00 5A A5 01 79 16 67 | 2015-12-10 23:47:50.190036: MCU 68 | 46 B9 68 00 07 05 00 74 16 69 | 2015-12-10 23:47:50.255407: PC 70 | 46 B9 6A 00 0B 03 00 00 5A A5 01 77 16 71 | 2015-12-10 23:47:53.130695: MCU 72 | 46 B9 68 00 0E 03 F5 28 00 A5 03 27 49 02 AE 16 73 | 2015-12-10 23:47:53.210814: PC 74 | 46 B9 6A 00 8B 22 00 00 5A A5 01 04 01 36 75 81 75 | 07 12 00 6A E5 82 60 03 02 00 02 E4 78 FF F6 D8 76 | FD 01 02 AF 82 8F 06 1F EE 60 0F 7D 90 7E 01 1D 77 | BD FF 01 1E ED 4E 70 F7 80 EB 22 AF 82 DF FE 22 78 | E5 B0 F4 F5 B0 75 82 05 11 31 75 82 D0 11 19 E5 79 | B0 F4 F5 B0 75 82 64 11 19 E5 B0 F4 F5 B0 75 82 80 | 64 11 19 E5 B0 F4 F5 B0 75 82 64 11 19 E5 B0 F4 81 | F5 B0 80 D6 75 82 00 22 FF FF FF FF FF FF FF FF 82 | FF FF FF FF FF FF FF FF FF FF 49 E8 16 83 | 2015-12-10 23:47:54.003906: MCU 84 | 46 B9 68 00 08 02 54 00 C6 16 85 | 2015-12-10 23:47:54.068777: PC 86 | 46 B9 6A 00 8B 02 00 80 5A A5 FF FF FF FF FF FF 87 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 88 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 89 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 90 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 91 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 92 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 93 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 94 | FF FF FF FF FF FF FF FF FF FF 81 F6 16 95 | 2015-12-10 23:47:54.867956: MCU 96 | 46 B9 68 00 08 02 54 00 C6 16 97 | 2015-12-10 23:47:54.932281: PC 98 | 46 B9 6A 00 8B 02 01 00 5A A5 FF FF FF FF FF FF 99 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 100 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 101 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 102 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 103 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 104 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 105 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 106 | FF FF FF FF FF FF FF FF FF FF 81 77 16 107 | 2015-12-10 23:47:55.732519: MCU 108 | 46 B9 68 00 08 02 54 00 C6 16 109 | 2015-12-10 23:47:55.796791: PC 110 | 46 B9 6A 00 8B 02 01 80 5A A5 FF FF FF FF FF FF 111 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 112 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 113 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 114 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 115 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 116 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 117 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 118 | FF FF FF FF FF FF FF FF FF FF 81 F7 16 119 | 2015-12-10 23:47:56.536325: MCU 120 | 46 B9 68 00 08 02 54 00 C6 16 121 | 2015-12-10 23:47:56.616743: PC 122 | 46 B9 6A 00 4B 04 00 00 5A A5 FF FF FF 00 FF FF 123 | 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 124 | 00 00 FF A8 FF 91 FF 20 FF FD 03 FF FF FF FF FF 125 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 126 | FF EC FF FF FF 74 BF F7 BC 9F 39 51 16 127 | 2015-12-10 23:47:57.070169: MCU 128 | 46 B9 68 00 08 04 54 00 C8 16 129 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc8-new.txt: -------------------------------------------------------------------------------- 1 | Cycling power: done 2 | 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 3 | -> Packet data: 46 B9 6A 00 07 FF 01 70 16 4 | done 5 | Target model: 6 | Name: STC8F2K08S2 7 | Magic: F641 8 | Code flash: 8.0 KB 9 | EEPROM flash: 56.0 KB 10 | Target frequency: 0.000 MHz 11 | Target BSL version: 7.3.10U 12 | Target wakeup frequency: 34.950 KHz 13 | Target ref. voltage: 1340 mV 14 | Target mfg. date: 2018-05-22 15 | Target options: 16 | reset_pin_enabled=False 17 | clock_gain=high 18 | watchdog_por_enabled=False 19 | watchdog_stop_idle=True 20 | watchdog_prescale=64 21 | low_voltage_reset=False 22 | low_voltage_threshold=2 23 | eeprom_erase_enabled=True 24 | bsl_pindetect_enabled=False 25 | por_reset_delay=long 26 | rstout_por_state=high 27 | uart1_remap=False 28 | uart2_passthrough=False 29 | uart2_pin_mode=normal 30 | epwm_open_drain=False 31 | program_eeprom_split=29440 32 | Disconnected! 33 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc8-options.txt: -------------------------------------------------------------------------------- 1 | MCS bytes 2 | ========= 3 | 4 | 46 b9 6a 00 33 04 00 00 5a a5 ff ff ff 00 ff ff 5 | 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 6 | 00 ff 01 31 20 80 34 00 01 ff ff ff ff ff 8b bf 7 | ^^^^^^^^^^^ ^^ ^^ ^^ ^^ 8 | frequency clkdiv 5) 1) 3) 9 | ^^^^^ 10 | trim? 11 | f7 fe 1f cc 16 12 | ^^ ^^ 13 | 4) 2) 14 | 15 | 1) not stricty related to some register 16 | aka MCS1 17 | bit 0: ? always 1 18 | bit 1: oscillator high gain 19 | bit 2: EPWM push-pull enabled 20 | bit 3: p2.0 state after boot 21 | bit 4: TXD signal source from RXD 22 | bit 5: p3.7 push-pull enabled 23 | bit 6: UART1 remap enabled 24 | bit 7: long power-on reset delay 25 | 26 | 2) not strictly related to some register 27 | aka MCS4 28 | eeprom size / code space upper limit (in pages) 29 | only seems to apply to devices with max. flash size 30 | e.g. fe -> 63.5K, e0 -> 56K 31 | 32 | 3) like RSTCFG? inverted? 33 | aka MCS2 34 | bit 0: LVD0 35 | bit 1: LVD1 36 | bit 2: ? always 1 37 | bit 3: ? always 1 38 | bit 4: ~reset pin enabled 39 | bit 5: ? always 1 40 | bit 6: ~enable lvd reset 41 | bit 7: ? always 1 42 | 43 | LVD: 44 | 2.20V -> 0xbf 45 | 2.40V -> 0xbe 46 | 2.70V -> 0xbd 47 | 3.00V -> 0xbc 48 | 49 | 4) like WDT_CONTR 50 | aka MCS3 51 | bit 0: WDPS0 52 | bit 1: WDPS1 53 | bit 2: WDPS2 54 | bit 3: ~stop wdt in idle 55 | bit 4: ? always 1 56 | bit 5: ~enable wdt on por 57 | bit 6: ? always 1 58 | bit 7: ? always 1 59 | 60 | WDPS like in datasheet 61 | 62 | 5) 63 | aka MCS0 64 | bit 0: ? ~BSLD / bootloader enabled 65 | bit 1: erase eeprom enabled 66 | bit 2: ? 67 | bit 3: ? 68 | bit 4: ? 69 | bit 5: ? 70 | bit 6: ? 71 | bit 7: ? -------------------------------------------------------------------------------- /doc/reverse-engineering/stc8-protocol.txt: -------------------------------------------------------------------------------- 1 | Overview of changes 2 | ------------------- 3 | 4 | The following changes have been observed compared to STC15: 5 | 6 | - Many differences in the status packet 7 | - At least some differences in MCS 8 | - Different challenge 9 | - no separate program speed 10 | - clock division was introduced; calibration always in the ~20-30 MHz range, lower clocks 11 | use division 12 | - the meaning of the calibration ranges and trim has changed 13 | 14 | The good: 15 | 16 | - Erase, Program, etc. operations are apparently unchanged. :) 17 | 18 | 19 | Status packet 20 | ------------- 21 | 22 | 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 23 | ^^^^^ wakeup clock ^^^^^ reference voltage 24 | ^^^^^^^^ mfg. date 25 | 26 | Clock set to 20 MHz by STC-ISP (encoding is different compared to STC15): 27 | 28 | 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 29 | 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 30 | ^^^^^ some 24 MHz reference or other clk measurement? 31 | ^^^^^ trim/adjust? 32 | ^^ clkdiv 33 | ^^^^^^^^^^^ clk 34 | 35 | MCS bytes 36 | 37 | 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 38 | ^^^^^^^^ ^^^^^ 39 | 40 | Disconnect 41 | ---------- 42 | 43 | Uses FF command byte. 44 | 45 | 46 | Basic challenge operation 47 | ------------------------- 48 | 49 | Host sends a challenge of some kind, followed by 0xfe pulsing 50 | 51 | 46 B9 6A 00 0C 00 02 00 00 80 00 00 F8 16 52 | 53 | Much simpler than in STC15 54 | 55 | MCU sends back some response: 56 | 57 | 46 B9 68 00 0C 00 02 36 AD 4E 83 02 2A 16 58 | 59 | Host now sends some longer challenge, followed by more pulses: 60 | 61 | 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 62 | 63 | MCU sends back some response: 64 | 65 | 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 66 | 67 | Host now seems to initiate a baud switch or something like that 68 | 69 | 46 B9 6A 00 0E 01 00 00 FF CC 01 7C 80 03 41 16 70 | 71 | MCU acknowlegdes it: 72 | 73 | 46 B9 68 00 07 01 00 70 16 74 | 75 | Now the MCU switches to the new baud rate. 76 | 77 | 78 | Challenges observed 79 | ------------------- 80 | 81 | 6 MHz: 82 | 83 | 46B96A0020000C 1400 1401 1402 1403 1500 1501 1502 1503 1600 1601 1602 1603 01A416 84 | 85 | 5.5 MHz: 86 | 87 | 46B96A0020000C 5C00 5C01 5C02 5C03 5D00 5D01 5D02 5D03 5E00 5E01 5E02 5E03 050416 88 | 89 | 90 | 11 MHz: 91 | 92 | 46B96A0020000C 5B00 5B01 5B02 5B03 5C00 5C01 5C02 5C03 5D00 5D01 5D02 5D03 04F816 93 | 94 | 20 MHz: 95 | 96 | 46B96A0020000C 3600 3601 3602 3603 3700 3701 3702 3703 3800 3801 3802 3803 033C16 97 | 98 | 24 MHz: 99 | 100 | 46B96A0020000C 7C00 7C01 7C02 7C03 7D00 7D01 7D02 7D03 7E00 7E01 7E02 7E03 068416 101 | 102 | 27 MHz: 103 | 104 | 46B96A0020000C B000 B001 B002 B003 B100 B101 B102 B103 B200 B201 B202 B203 08F416 105 | 106 | 107 | Ranges vs trim value 108 | -------------------- 109 | 110 | 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 111 | 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 112 | 113 | first byte determines general trim value... range of ~16 to ~30 MHz, the second byte (00..03) is a fine adjustment. 114 | 115 | 116 | Clock division? 117 | --------------- 118 | 119 | 5.5 MHz vs 11 Mhz: challenge is about the same. it's likely some kind of clock divider is used! 120 | 121 | 5.5 Mhz switch: 01 00 00 FF CC 01 5C 80 clkdiv = 4? 122 | 11 MHz switch: 01 00 00 FF CC 01 5B 80 clkdiv = 2? 123 | 22 MHz switch: 01 00 00 FF CC 01 5C 80 clkdiv = 1? 124 | 125 | 22 Mhz option packet: 0400005AA5FFFFFF00FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF01516D405D0201FFFDFFFFFF8BBFF7FE 126 | 11 MHz option packet: 0400005AA5FFFFFF00FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF00A8AF985D0102FFFDFFFFFF8BBFF7FE 127 | 5.5 MHz option packet: 0400005AA5FFFFFF00FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF005462585D0004FFFDFFFFFF8BBFF7FE 128 | ^^ clkdiv? 129 | ^^^^^^^^ clkspeed 130 | 131 | Always 24 MHz for programming 132 | ----------------------------- 133 | 134 | Calibration for anything but 24 Mhz (and around that) fails when switching baud. Another observation is that there is no 135 | programming speed being calibrated anymore. This may suggest that a fixed speed is used for programming. 136 | 137 | Adjusting BRT calculation to 24 MHz in the switch packet seems to work. So it is really using 24 MHz by default; 138 | probably some pre-calibrated value. -------------------------------------------------------------------------------- /doc/reverse-engineering/stc89-options.txt: -------------------------------------------------------------------------------- 1 | Model-specific configuration registers 2 | Placement of configuration values 3 | 4 | "~" means the bit is a negated boolean. Sometimes values overlap, 5 | depending on MCU model. 6 | 7 | In STC89 series, there is only a single MCS byte. 8 | 9 | MCS0 10 | ---- 11 | 12 | MSB 7 6 5 4 3 2 1 0 LSB 13 | ~WDEN XRAM ALE OSCG ~EERE ~BSLD 0 ~CPU6T 14 | 15 | ~WDEN := watchdog enable after power-on-reset 16 | XRAM := enable access to internal XRAM 17 | ALE := enable ALE pin function (otherwise, it's just regular GPIO) 18 | OSCG := high oscillator gain 19 | ~EREE := enable eeprom erase next time MCU is programmed 20 | ~BSLD := enable BSL pin detect; i.e. BSL is only enabled if P1.0/P1.1 21 | (or others, depends on MCU model) are held low on POR. 22 | ~CPU6T := enable double speed (6T cycles instead of 12T cycles) mode 23 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc89-protocol.txt: -------------------------------------------------------------------------------- 1 | STC89 2 | 3 | This is the first generation protocol of STC MCUs. 4 | 5 | Differences to STC12: 6 | 7 | * Uses NONE parity instead of EVEN parity. 8 | 9 | * Status packet is sent without frame start magic. 10 | 11 | * Checksum calculations are different: a single-byte modular sum is used. 12 | 13 | * Baudrate handshake isn't initiated with a type 0x50 packet; this is simply 14 | skipped. 15 | 16 | * After the handshake a special ping-pong sequence of 0x80 type packets needs 17 | to be sent. 18 | This doesn't appear to serve any purpose - possibly this is just done to 19 | verify that the connection works reliably. STC12 doesn't require it anymore 20 | because parity and the improved checksum ensure correct operation. 21 | 22 | * Erase is acknowledged with type 0x80 packet instead of type 0x00 23 | 24 | * After flash programming, there is no finish packet, type 0x69, sent; this 25 | is simply skipped. 26 | 27 | * Baudrate handshake 28 | - Uses normal speed (/32) UART timing in 12T mode and double speed (/16) 29 | in 6T mode 30 | - IAP delay has some differences (see datasheet) 31 | 32 | * Erase procedure 33 | - A different magic sequence is used 34 | (6 bytes with value 0x33) 35 | - Only a single size is supplied 36 | - response code has type 0x80 37 | 38 | * Options 39 | - Only a single option byte exists 40 | 41 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc89a-c52rc.txt: -------------------------------------------------------------------------------- 1 | 001046: Read (UP): 2021-01-09 15:37:44.9125552 +0.0085328 2 | 46 b9 68 00 29 50 fd 84 1e 11 4d 05 8e 96 27 7c F.h.)P....M...'| 3 | ^ 4 | cpu_6t 5 | 04 47 01 7f 40 81 72 43 00 f0 51 05 80 00 ff ff .G..@.rC..Q..... 6 | ^ ^ ^ ^ 7 | freq_counte | | | 8 | bl_version | 9 | bl_stepping | 10 | bl_minor 11 | 12 | 13 | ff ff 38 20 20 02 19 60 0d a0 16 ..8 ..`... 14 | 15 | 16 | 001057: Write (DOWN): 2021-01-09 15:37:44.9814096 +0.0129872 17 | 46 b9 6a 00 0a 01 ff fd 82 02 f3 16 F.j......... 18 | ^ 19 | handshake 20 | 21 | 22 | 001072: Read (UP): 2021-01-09 15:37:45.0836096 +0.0115168 23 | 46 b9 68 00 07 01 00 70 16 F.h....p. 24 | 25 | 001113: Write (DOWN): 2021-01-09 15:37:45.1352048 +0.0171904 26 | 46 b9 6a 00 0b 05 00 00 46 b9 01 79 16 F.j.....F..y. 27 | ^ 28 | ping-pong 29 | 30 | 31 | 001116: Read (UP): 2021-01-09 15:37:45.1392768 +0.0017200 32 | 46 b9 68 00 07 05 00 74 16 F.h....t. 33 | 34 | 35 | 001127: Write (DOWN): 2021-01-09 15:37:45.1502464 +0.0109472 36 | 46 b9 6a 00 0b 03 00 00 46 b9 01 77 16 F.j.....F..w. 37 | ^ 38 | erase_flash ? 39 | 40 | 41 | 001170: Read (UP): 2021-01-09 15:37:45.4729040 +0.0099696 42 | 46 b9 68 00 0e 03 f0 51 c5 f2 06 7c 14 04 07 16 F.h....Q...|.... 43 | ^ 44 | mcu id 45 | 46 | 47 | 001181: Write (DOWN): 2021-01-09 15:37:45.4791856 +0.0062576 48 | 46 b9 6a 00 8b 32 00 00 46 b9 02 00 08 12 00 3f F.j..2..F......? 49 | ^ ^ 50 | write address 51 | write data 52 | 80 fe 75 81 07 12 00 4c e5 82 60 03 02 00 03 e4 ..u....L..`..... 53 | 78 ff f6 d8 fd 02 00 03 ae 82 af 83 8e 04 8f 05 x............... 54 | 1e be ff 01 1f ec 4d 60 0f 7c 90 7d 01 1c bc ff ......M`.|.}.... 55 | 01 1d ec 4d 70 f7 80 e4 22 90 03 e8 12 00 1e e5 ...Mp..."....... 56 | 80 f4 f5 80 80 f3 75 82 00 22 ff ff ff ff ff ff ......u.."...... 57 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 58 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 59 | ff ff ff ff ff ff ff ff ff ff 52 f9 16 ..........R.. 60 | 61 | 62 | 001188: Read (UP): 2021-01-09 15:37:45.5301744 +0.0047088 63 | 46 b9 68 00 08 02 54 00 c6 16 F.h...T... 64 | ^ 65 | write done 66 | 67 | 68 | 001199: Write (DOWN): 2021-01-09 15:37:45.5575264 +0.0273248 69 | 46 b9 6a 00 0c 04 00 00 46 b9 fd 02 76 16 F.j.....F...v. 70 | ^ 71 | write msr 72 | 73 | 74 | 001202: Read (UP): 2021-01-09 15:37:45.5625296 +0.0018304 75 | 46 b9 68 00 08 04 54 00 c8 16 F.h...T... 76 | unknown 77 | 78 | 001213: Write (DOWN): 2021-01-09 15:37:45.5712992 +0.0087472 79 | 46 b9 6a 00 07 ff 01 70 16 F.j....p. 80 | unknown 81 | -------------------------------------------------------------------------------- /doc/reverse-engineering/stc89c52rc.txt: -------------------------------------------------------------------------------- 1 | status packet: 2 | 3 | 2014-01-23 14:23:03.132734: 4 | 68 00 3B 00 25 E6 25 E6 25 E6 25 E6 25 E6 25 E6 5 | 25 E2 25 E6 43 43 FC F0 02 82 00 00 00 00 00 00 6 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 00 00 00 00 00 00 00 00 00 ED 16 8 | 9 | - no frame start? 10 | 11 | 12 | programming hello.bin @ 2400 bps 13 | 14 | host2mcu: 15 | 16 | 2014-01-23 14:28:02.284628: 17 | 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 18 | 2014-01-23 14:28:02.723598: 19 | 46 B9 6A 00 0C 8F FD F8 02 10 28 81 B5 16 20 | ^reload 21 | ^SMOD 22 | ^SMOD checksum 23 | ^reload checksum 24 | ^delay 25 | ^IAP delay 26 | 27 | 2014-01-23 14:28:03.301552: 28 | 46 B9 6A 00 0B 8E FD F8 02 10 28 32 16 29 | 2014-01-23 14:28:03.675670: 30 | 46 B9 6A 00 0C 80 00 00 36 01 F0 02 1F 16 31 | 2014-01-23 14:28:03.781613: 32 | 46 B9 6A 00 0C 80 00 00 36 01 F0 02 1F 16 33 | 2014-01-23 14:28:03.887556: 34 | 46 B9 6A 00 0C 80 00 00 36 01 F0 02 1F 16 35 | 2014-01-23 14:28:03.994608: 36 | 46 B9 6A 00 0C 80 00 00 36 01 F0 02 1F 16 37 | 2014-01-23 14:28:04.101595: 38 | 46 B9 6A 00 0C 80 00 00 36 01 F0 02 1F 16 39 | 2014-01-23 14:28:04.223628: 40 | 46 B9 6A 00 0D 84 01 33 33 33 33 33 33 2E 16 41 | 2014-01-23 14:28:04.568604: 42 | 46 B9 6A 00 8C 00 00 00 00 00 00 80 02 00 08 12 43 | 00 3F 80 FE 75 81 07 12 00 4C E5 82 60 03 02 00 44 | 03 E4 78 FF F6 D8 FD 02 00 03 AE 82 AF 83 8E 04 45 | 8F 05 1E BE FF 01 1F EC 4D 60 0F 7C 90 7D 01 1C 46 | BC FF 01 1D EC 4D 70 F7 80 E4 22 90 03 E8 12 00 47 | 1E E5 80 F4 F5 80 80 F3 75 82 00 22 00 00 00 00 48 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50 | 00 00 00 00 00 00 00 00 00 00 00 00 79 16 51 | 2014-01-23 14:28:05.255560: 52 | 46 B9 6A 00 8C 00 00 00 00 80 00 80 00 00 00 00 53 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 54 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 56 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 57 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 58 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 | 00 00 00 00 00 00 00 00 00 00 00 00 F6 16 61 | 2014-01-23 14:28:05.929634: 62 | 46 B9 6A 00 8C 00 00 00 01 00 00 80 00 00 00 00 63 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 66 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 67 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 69 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 | 00 00 00 00 00 00 00 00 00 00 00 00 77 16 71 | 2014-01-23 14:28:06.615585: 72 | 46 B9 6A 00 8C 00 00 00 01 80 00 80 00 00 00 00 73 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 74 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 75 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 76 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 77 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 79 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 | 00 00 00 00 00 00 00 00 00 00 00 00 F7 16 81 | 2014-01-23 14:28:07.348584: 82 | 46 B9 6A 00 0A 8D FC FF F6 FF F1 16 83 | 2014-01-23 14:28:07.488602: 84 | 46 B9 6A 00 06 50 C0 16 85 | 2014-01-23 14:28:07.675520: 86 | 46 B9 6A 87 | 2014-01-23 14:28:07.716596: 88 | 00 06 82 F2 16 89 | 90 | mcu2host: 91 | 92 | 2014-01-23 14:29:19.694735: 93 | 68 00 3B 00 25 E6 25 E6 25 E6 25 E6 25 E6 25 E6 94 | 25 E6 25 E6 43 43 FC F0 02 82 00 00 00 00 00 00 95 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 96 | 00 00 00 00 00 00 00 00 00 F1 16 97 | ^ 6 clk vs 12 clk? 98 | 99 | 2014-01-23 14:29:20.314923: 100 | 46 B9 68 00 0C 8F FD F8 02 10 28 81 B3 16 101 | 2014-01-23 14:29:20.884524: 102 | 46 B9 68 00 0B 8E FD F8 02 10 28 30 16 103 | 2014-01-23 14:29:21.045797: 104 | 46 B9 68 00 06 80 EE 16 105 | 2014-01-23 14:29:21.151802: 106 | 46 B9 68 00 06 80 EE 16 107 | 2014-01-23 14:29:21.261384: 108 | 46 B9 68 00 06 80 EE 16 109 | 2014-01-23 14:29:21.368230: 110 | 46 B9 68 00 06 80 EE 16 111 | 2014-01-23 14:29:21.474767: 112 | 46 B9 68 00 06 80 EE 16 113 | 2014-01-23 14:29:21.807191: 114 | 46 B9 68 00 06 80 EE 16 115 | 2014-01-23 14:29:22.533512: 116 | 46 B9 68 00 07 80 03 F2 16 117 | 2014-01-23 14:29:23.239793: 118 | 46 B9 68 00 07 80 00 EF 16 119 | 2014-01-23 14:29:23.914122: 120 | 46 B9 68 00 07 80 00 EF 16 121 | 2014-01-23 14:29:24.595625: 122 | 46 B9 68 00 07 80 00 EF 16 123 | 2014-01-23 14:29:24.725387: 124 | 46 B9 68 00 0A 8D FC FF F6 FF EF 16 125 | 2014-01-23 14:29:24.845962: 126 | 46 B9 68 00 10 10 C0 16 F6 FF F1 03 FF 43 43 FC 127 | C8 16 128 | 2014-01-23 14:29:25.064892: 129 | 46 B9 68 00 06 80 EE 16 130 | 131 | -------------------------------------------------------------------------------- /doc/reverse-engineering/untrimmed.txt: -------------------------------------------------------------------------------- 1 | Cycling power: done 2 | Waiting for MCU: done 3 | Protocol detected: stc8 4 | Target model: 5 | Name: STC8F2K08S2 6 | Magic: F641 7 | Code flash: 8.0 KB 8 | EEPROM flash: 56.0 KB 9 | Target frequency: 0.000 MHz 10 | Target BSL version: 7.3.10U 11 | Target wakeup frequency: 34.950 KHz 12 | Target ref. voltage: 1340 mV 13 | Target mfg. date: 2018-05-22 14 | Target options: 15 | reset_pin_enabled=False 16 | clock_gain=high 17 | watchdog_por_enabled=False 18 | watchdog_stop_idle=True 19 | watchdog_prescale=64 20 | low_voltage_reset=False 21 | low_voltage_threshold=2 22 | eeprom_erase_enabled=True 23 | bsl_pindetect_enabled=False 24 | por_reset_delay=long 25 | rstout_por_state=high 26 | uart1_remap=False 27 | uart2_passthrough=False 28 | uart2_pin_mode=normal 29 | epwm_open_drain=False 30 | program_eeprom_split=29440 31 | Loading flash: 80 bytes (Intel HEX) 32 | <- 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 33 | Protocol error: uncalibrated, please provide a trim value 34 | -> Packet data: 46 B9 6A 00 07 FF 01 70 16 35 | Disconnected! 36 | -------------------------------------------------------------------------------- /doc/reverse-engineering/usb15-protocol.txt: -------------------------------------------------------------------------------- 1 | STC15 series USB ISP protocol 2 | ============================= 3 | 4 | - host does OUT and IN control transfers for write and read 5 | - IN transfer with wLength = 132, wValue = 0, wIndex = 0, bRequest = 0 are used for all reads 6 | - OUT transfers with arbitrary size are used for writes 7 | 8 | - packets from MCU 9 | always start with 0x46 0xb9, similar to serial protocols 10 | third byte is packet length 11 | followed by data bytes 12 | 8 bit checksum at the end, looks like 8 bit modular subtraction 13 | 14 | - packet types 15 | most likely derived from the serial protocol, at least partially 16 | 17 | info packet 18 | - same as with serial protocol 19 | 20 | option packet 21 | - generally same as with serial protocol, some header stuff omitted 22 | 23 | - flash data 24 | wIndex specifies write address 25 | wValue is 0xa55a 26 | bRequest is 0x22 for first packet, 0x02 for the following ones 27 | 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 28 | checksum: 8 bit inverted modular sum 29 | 30 | - option packet 31 | wIndex is 0 32 | wValue is 0xa55a 33 | bRequest is 4 34 | seems to use the same checksumming scheme 35 | 36 | -------------------------------------------------------------------------------- /doc/zh_CN/FAQ.md: -------------------------------------------------------------------------------- 1 | 文档说明 Explanation 2 | ------------------------ 3 | 此文档翻译自FAQ.md 4 | 5 | This document was translated from FAQ.md 6 | 7 | 最后修改时间:2020年6月8日 8 | 9 | Last modified time: June 8, 2020 10 | 11 | 常见问题 12 | ====================================== 13 | 14 | ### 问题1:是否可以从芯片中读取代码(或EEPROM)存储器? 15 | 16 | 从设计上讲,这是STC的引导加载程序协议无法实现的。 STC将此视为安全功能。目前没有已知的解决方法。有关更多详细信息和讨论,请参见问题7。 17 | 18 | ### 问题2:哪些串行接口已通过stcgal测试过? 19 | 20 | stcgal应该可以与波特率为16550的UART兼容。 21 | 但是,如今,基于USB模拟的UART是典型的情况。 22 | 以下是已通过stcgal成功测试的USB模拟UART接口芯片: 23 | 24 | * FT232系列(操作系统:Linux,Windows) 25 | * CH340 / CH341(操作系统:Windows,Linux需要内核4.10) 26 | * PL2303(操作系统:Windows,Linux) 27 | * CP2102(操作系统:Windows,Linux,macOS) 28 | 29 | 已知不起作用的接口: 30 | 31 | * Raspberry Pi Mini UART(缺少奇偶校验支持,请启用PL011 UART) 32 | 33 | ### 问题3:stcgal 启动失败同时显示 `module 'serial' has no attribute 'PARITY_NONE'` 等类似信息 34 | 35 | PyPI软件包“ serial”(数据序列库)和PyPI软件包“ pyserial”(stcgal所需的串行端口访问库)之间存在模块名称冲突。 36 | 您必须卸载'serial'软件包(`pip3 uninstall serial`)并重新安装'pyserial'(`pip3 install --force-reinstall pyserial`)才能解决此问题。 37 | 目前没有其他已知的解决方案。 38 | 39 | ### 问题4:stcgal无法识别MCU,并停留在“Waiting for MCU”中 40 | 41 | 有许多问题可能导致此症状: 42 | * 电气问题和错误连接。确保正确连接了RX / TX,GND和VCC。 43 | 如果您不使用自动复位功能,还应确保仅在stcgal启动后才接通电源,因为引导加载程序仅在上电复位时被调用。 44 | * 通过I / O引脚供电。 45 | 即使未连接VCC,也可以通过I / O引脚(例如RX / TX)为MCU供电。 46 | 在这种情况下,上电复位逻辑不起作用。请参阅下一个问题。 47 | * erial接口不兼容。由于各种原因,一些基于USB的UART与STC MCU的兼容性很差。 48 | 您可以尝试使用选项`-l 1200`将握手波特率从标准2400波特降低到1200波特,在某些情况下可以解决这些问题。 49 | 50 | ### 问题5:如何避免MCU从I/O引脚供电? 51 | 可以采取各种补救措施来避免MCU从I/O引脚供电。 52 | * 您可以尝试在MCU VCC和GND之间连接一个电阻(<1k),以使注入的电源短路,并希望将电压降至欠压值以下。 53 | * 另一种选择是在可能注入功率的I / O线上插入串联电阻。例如,在RX / TX线上尝试一个类似1k的值。 54 | * 还有另一种可能性是切换GND而不是VCC。 55 | 在大多数情况下,这应该是一个相当可靠的解决方案。 56 | 57 | ### 问题6:RC频率调整失败 58 | 首先,请确保指定的频率使用正确的单位。频率以kHz为单位指定,安全范围约为5000 kHz-30000 kHz。 59 | 此外,频率调整使用UART时钟作为时钟参考,因此UART不兼容或时钟不准确也会导致频率调整问题。如果可能的话, 60 | 尝试另一个UART芯片。 61 | 62 | ### 问题7:波特率切换失败或闪存编程失败 63 | 特别是在高编程波特率,例如, 115200波特。尝试降低波特率,或使用默认的19200波特率。 64 | 某些USB UART也会由于时序不正确而引起问题,这可能会导致各种问题。 65 | 66 | ### 问题8:如何使用自动重置功能? 67 | 标准自动重置功能的工作原理与Arduino类似。 DTR是低电平有效信号,在stcgal启动时置位500 ms,然后在其余的编程序列中置为无效。 68 | 在标准USB UART上,这将导致500 ms的低脉冲,然后是高相位。 stcgal作者推荐以下电路: 69 | ``` 70 | VCC --o o-- MCU GND 71 | | | 72 | .-. | 73 | | | 1k | 74 | | | | 75 | '_' | 76 | | | 77 | | ||-+ 78 | DTR --o --||<- BS170/BSS138 79 | ||-| (N-CH MOSFET) 80 | | 81 | | 82 | GND ---------o 83 | ``` 84 | 该电路使用一个N沟道MOSFET作为开关来切换MCU的GND。 VCC直接连接。这避免了寄生供电问题。上拉电阻可确保在DTR输入悬空时接通MCU。 85 | -------------------------------------------------------------------------------- /doc/zh_CN/INSTALL.md: -------------------------------------------------------------------------------- 1 | 文档说明 Explanation 2 | ------------------------ 3 | 此文档翻译自INSTALL.md 4 | 5 | This document was translated from INSTALL.md 6 | 7 | 最后修改时间:2020年6月8日 8 | 9 | Last modified time: June 8, 2020 10 | 11 | 安装说明 12 | ============ 13 | 14 | stcgal需要Python 3.2(或更高版本),pyserial 3.0或更高版本以及TQDM 4.0.0或更高版本。 15 | USB支持是可选的,并且需要pyusb 1.0.0b2或更高版本。如果已经安装了依赖项,则可以使用包含的 16 | ```stcgal.py``` 脚本直接运行stcgal。 17 | 18 | 永久安装有几种选择: 19 | 20 | * 使用Python3和```pip```。运行```pip3 install stcgal``` 21 | 在系统上全局安装最新版本的stcgal。 22 | 这可能需要管理员/ root用户权限才能进行写到系统目录。 23 | 24 | * 使用setuptools。运行`./setup.py build`来构建,并运行'sudo ./setup.py install`'来安装stcgal。 25 | -------------------------------------------------------------------------------- /doc/zh_CN/MODELS.md: -------------------------------------------------------------------------------- 1 | 文档说明 Explanation 2 | ------------------------ 3 | 此文档翻译自MODELS.md 4 | 5 | This document was translated from MODELS.md 6 | 7 | 最后修改时间:2020年6月8日 8 | 9 | Last modified time: June 8, 2020 10 | 11 | 支持的MCU型号 12 | ==================== 13 | 14 | stcgal理论上完全支持STC 89/90/10/11/12/15/8/32系列MCU。 15 | 16 | 到目前为止,stcgal已使用以下MCU模型进行了测试: 17 | 18 | 89/90系列 19 | * STC89C52RC (BSL 版本: 4.3C/6.6C) 20 | * STC89C54RD+ (BSL 版本: 4.3C) 21 | * STC90C52RC (BSL 版本: 4.3C) 22 | * STC90C58RD+ (BSL 版本: 4.3C) 23 | 24 | STC12C系列 25 | * STC12C2052 (BSL 版本: 5.8D) 26 | * STC12C2052AD (BSL 版本: 5.8D) 27 | * STC12C5608AD (BSL 版本: 6.0G) 28 | * STC12C5A16S2 (BSL 版本: 6.2I) 29 | * STC12C5A60S2 (BSL 版本: 6.2I/7.1I) 30 | * STC12C5204AD (BSL 版本: 6.6H) 31 | 32 | 10/11系列价格 33 | * STC10F04XE (BSL 版本: 6.5J) 34 | * STC11F02E (BSL 版本: 6.5K) 35 | * STC11F08XE (BSL 版本: 6.5M) 36 | 37 | STC15系列 38 | * STC15F104E (BSL 版本: 6.7Q) 39 | * STC15F204EA (BSL 版本: 6.7R) 40 | * STC15L104W (BSL 版本: 7.1.4Q) 41 | * STC15F104W (BSL 版本: 7.1.4Q) 42 | * IAP15F2K61S2 (BSL 版本: 7.1.4S) 43 | * STC15L2K16S2 (BSL 版本: 7.2.4S) 44 | * IAP15L2K61S2 (BSL 版本: 7.2.5S) 45 | * STC15W408AS (BSL 版本: 7.2.4T 和 7.2.5T) 46 | * STC15W4K56S4 (BSL 版本: 7.3.4T 和 7.3.7T, UART and USB mode) 47 | 48 | STC8系列 49 | * STC8A8K64S4A12 (BSL 版本: 7.3.9U 和 7.3.12U) 50 | * STC8F2K08S2 (BSL 版本: 7.3.10U) 51 | * STC8A8K64D4 (BSL 版本: 7.4.2U) 52 | * STC8G1K08A-8PIN (BSL 版本: 7.3.12U) 53 | * STC8G1K08-20/16PIN (BSL 版本: 7.3.12U) 54 | * STC8G1K17-20/16PIN (BSL 版本: 7.3.12U) 55 | * STC8G2K64S4 (BSL 版本: 7.3.11U) 56 | * STC8H1K08 (BSL 版本: 7.3.12U) 57 | * STC8H3K64S2 (BSL 版本: 7.4.1U) 58 | * STC8H3K64S4 (BSL 版本: 7.4.1U) 59 | * STC8H4K64TL (BSL 版本: 7.4.3U) 60 | * STC8H8K64U (BSL 版本: 7.4.4U) 61 | 62 | STC32系列 63 | * STC32G12K128-Beta (BSL 版本: 7.4.4U) 64 | 65 | 欢迎提供兼容性报告,无论是负面的还是正面的。 66 | -------------------------------------------------------------------------------- /doc/zh_CN/PyPI.md: -------------------------------------------------------------------------------- 1 | 文档说明 Explanation 2 | ------------------------ 3 | 此文档翻译自PyPI.md 4 | 5 | This document was translated from PyPI.md 6 | 7 | 最后修改时间:2020年6月8日 8 | 9 | Last modified time: June 8, 2020 10 | 11 | stcgal - 用于STC MCU的ISP闪存工具 12 | =============================== 13 | 14 | stcgal是用于[STC MCU Ltd](http://stcmcu.com/)的命令行闪存编程工具。 兼容8051微控制器。 15 | 16 | STC微控制器具有基于UART / USB的引导加载程序(BSL)。 17 | 它采用系统内编程,即基于数据包的协议通过串行链路刷新代码存储器和IAP存储器。 18 | BSL还用于配置各种设备选项。 不幸的是,该协议没有公开记录,STC仅提供(粗略的)Windows GUI应用程序进行编程 19 | 20 | stcgal是STC的Windows软件的功能全面的开源替代品。 它支持多种MCU,非常便携,适合自动下载。 21 | 22 | [有关更多信息,请参见GitHub页面。](https://github.com/grigorig/stcgal). 23 | -------------------------------------------------------------------------------- /doc/zh_CN/USAGE.md: -------------------------------------------------------------------------------- 1 | 文档说明 Explanation 2 | ------------------------ 3 | 此文档翻译自USAGE.md 4 | 5 | This document was translated from USAGE.md 6 | 7 | 最后修改时间:2020年6月8日 8 | 9 | Last modified time: June 8, 2020 10 | 11 | 使用方法 12 | ===== 13 | 14 | 使用 ```-h``` 调用stcgal以获取使用信息。('//'后面是翻译,实际使用过程中没有后面内容) 15 | 16 | ``` 17 | usage: stcgal [-h] [-e] [-a] [-A {dtr,rts}] [-r RESETCMD] 18 | [-P {stc89,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto}] 19 | [-p PORT] [-b BAUD] [-l HANDSHAKE] [-o OPTION] [-t TRIM] [-D] 20 | [-V] 21 | [code_image] [eeprom_image] 22 | 23 | stcgal 1.7 - an STC MCU ISP flash tool 24 | (C) 2014-2018 Grigori Goronzy and others 25 | https://github.com/grigorig/stcgal 26 | 27 | positional arguments: 28 | code_image code segment file to flash (BIN/HEX) //代码段文件刷新 29 | eeprom_image eeprom segment file to flash (BIN/HEX) //EEPROM段文件刷新 30 | 31 | optional arguments: 32 | -h, --help show this help message and exit //显示此帮助消息并退出 33 | -a, --autoreset cycle power automatically by asserting DTR//断言DTR自动重启电源 34 | -A {dtr,rts}, --resetpin {dtr,rts} 35 | pin to hold down when using --autoreset (default: DTR) 36 | -r RESETCMD, --resetcmd RESETCMD 37 | shell command for board power-cycling (instead of DTR //用于板上电重启的shell命令(而不是DTR断言) 38 | assertion) 39 | -P {stc89,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto}, --protocol {stc89,stc12a,stc12b,stc12,stc15a,stc15,stc8,stc8d,stc8g,usb15,auto} 40 | protocol version (default: auto) //协议版本(芯片系列)(在默认状态为auto) 41 | -p PORT, --port PORT serial port device //串口设备 42 | -b BAUD, --baud BAUD transfer baud rate (default: 115200) //传输波特率(默认值:115200) 43 | -l HANDSHAKE, --handshake HANDSHAKE 44 | handshake baud rate (default: 2400) //握手波特率(默认值:2400) 45 | -o OPTION, --option OPTION 46 | set option (can be used multiple times, see//设置选项(可以多次使用,请参阅文档) 47 | documentation) 48 | -t TRIM, --trim TRIM RC oscillator frequency in kHz (STC15+ series only)//RC振荡器频率(kHz)(仅STC15 +系列) 49 | -D, --debug enable debug output //启用调试输出 50 | -V, --version print version info and exit //打印版本信息并退出 51 | ``` 52 | 53 | 最重要的是, ```-p``` 设置用于编程的串行端口。 54 | 55 | ### 传输波特率 56 | 57 | 所有从 STC15 系列开始的 MCU 都支持默认值 115200 波特,至少是之前的 STC12C5A56S2。 58 | 对于较旧的 MCU,您可能必须使用 ```-b 19200``` 才能正确操作。 59 | 60 | ### 通讯协议与规定 61 | 62 | STC MCU对BSL使用各种相关但不兼容的协议。协议可以用```-P``` 标志来指定。 63 | 默认情况下,使用UART协议自动检测。协议与MCU系列的对应关系如下: 64 | 65 | * ```auto``` 自动检测基于UART的协议(默认) 66 | * ```stc89``` STC89/90 系列 67 | * ```stc89a``` STC89/90 系列(BSL 7.2.5C) 68 | * ```stc12a``` STC12x052 系列和其他类似系列 69 | * ```stc12b``` STC12x52 系列, STC12x56 系列和其他类似系列 70 | * ```stc12``` 多数 STC10/11/12 系列 71 | * ```stc15a``` STC15x104E 和 STC15x204E(A) 系列 72 | * ```stc15``` 多数 STC15 系列 73 | * ```stc8``` STC8A8K64S4A12 和 STC8F 系列 74 | * ```stc8d``` 所有 STC8 和 STC32 系列 75 | * ```stc8g``` STC8G1 和 STC8H1 系列 76 | * ```usb15``` 支持USB的STC15W4系列 77 | 78 | doc / reverse-engineering子目录中的文本文件提供了BSL使用的反向工程协议的概述。 79 | 有关更多详细信息,请阅读源代码。 80 | 81 | ### 获取MCU信息 82 | 83 | 调用stcgal而不编写任何文件。它将转储有关MCU的信息,例如:('//'后面是翻译,实际使用过程中没有后面内容) 84 | 85 | ``` 86 | $ ./stcgal.py -P stc15 87 | Waiting for MCU, please cycle power: done //等待MCU,请重启电源 88 | Target model: 89 | Name: IAP15F2K61S2 90 | Magic: F449 91 | Code flash: 61.0 KB 92 | EEPROM flash: 0.0 KB 93 | Target frequency: 10.046 MHz //单片机频率 94 | Target BSL version: 7.1S //单片机BSL版本 95 | Target wakeup frequency: 34.771 KHz //单片机唤醒频率 96 | Target options: 97 | reset_pin_enabled=False //复位引脚启用状态 98 | clock_source=internal //时钟来源 99 | clock_gain=high 100 | watchdog_por_enabled=False //看门狗状态 101 | watchdog_stop_idle=True 102 | watchdog_prescale=256 //看门狗预分频系数 103 | low_voltage_reset=True //低电压复位 104 | low_voltage_threshold=3 105 | eeprom_lvd_inhibit=True 106 | eeprom_erase_enabled=False 107 | bsl_pindetect_enabled=False 108 | por_reset_delay=long 109 | rstout_por_state=high 110 | uart2_passthrough=False //串口2直通 111 | uart2_pin_mode=normal //串口2引脚模式 112 | Disconnected! 113 | ``` 114 | 115 | 如果识别失败,阅读[FAQ(chinese)](FAQ.md) 116 | 117 | ### 编程Flash闪存 118 | 119 | stcgal支持Intel十六进制编码文件以及二进制文件。 120 | Intel HEX通过文件扩展名(. hex,. ihx 或者. ihex ) 自动测试。 121 | 122 | 像前面一样调用 stcgal,但提供代码映像的路径: 123 | 124 | ``` 125 | $ ./stcgal.py -P stc15 hello.hex 126 | Waiting for MCU, please cycle power: done 127 | Target model: 128 | Name: IAP15F2K61S2 129 | Magic: F449 130 | Code flash: 61.0 KB 131 | EEPROM flash: 0.0 KB 132 | Target frequency: 10.046 MHz //单片机频率 133 | Target BSL version: 7.1S //单片机BSL版本 134 | Target wakeup frequency: 34.771 KHz //单片机唤醒频率 135 | Target options: 136 | reset_pin_enabled=False //复位引脚启用状态 137 | clock_source=internal //时钟来源 138 | clock_gain=high 139 | watchdog_por_enabled=False //看门狗状态 140 | watchdog_stop_idle=True 141 | watchdog_prescale=256 //看门狗预分频系数 142 | low_voltage_reset=True //低电压复位 143 | low_voltage_threshold=3 144 | eeprom_lvd_inhibit=True 145 | eeprom_erase_enabled=False 146 | bsl_pindetect_enabled=False 147 | por_reset_delay=long 148 | rstout_por_state=high 149 | uart2_passthrough=False //串口2直通 150 | uart2_pin_mode=normal //串口2模式 151 | Loading flash: 80 bytes (Intel HEX) 152 | Trimming frequency: 10.046 MHz 153 | Switching to 19200 baud: done 154 | Erasing flash: done 155 | Writing 256 bytes: .... done 156 | Setting options: done 157 | Target UID: 0D000021022632 158 | Disconnected! 159 | ``` 160 | 161 | 还可以编程存储器的EEPROM部分,。 将 Flash 图像路径添加到命令行后添加EEPROM图像路径。 162 | 163 | stcgal默认使用 19200 bps的保守波特率。 可以通过标志```-b```选择更快的波特率来加快编程速度。 164 | 165 | ### 设备选项 166 | 167 | stcgal转储了许多目标选项。 也可以修改这些。 在命令行上提供一个( 或者更多) `-o` 标志,后面跟一个 key-value 对来调整这些设置。 168 | 例如你可以将外部晶体启用为时钟源: 169 | 170 | ``` 171 | $ ./stcgal.py -P stc15 -o clock_source=external hello.bin 172 | ``` 173 | 174 | 请注意,设备选项只能在 Flash 内存被编程时设置 ! 175 | 176 | #### 命令行选项键 177 | 178 | 并非所有部件都支持所有选项。 描述中列出了支持每个选项的协议或者部分。 179 | 180 | 选项密钥 | 可能的值 | 协议/模型 | 描述 181 | ------------------------------|-------------------|---------------------|------------ 182 | ```cpu_6t_enabled``` | true/false | 仅STC89 | 6T快速模式 183 | ```bsl_pindetect_enabled``` | true/false | 全部 | BSL仅在 p3。2/p3。3 或者 p1.0/p1.1 ( 取决于模型) 低时启用 184 | ```eeprom_erase_enabled``` | true/false | 全部 | 使用下一个编程周期擦除 EEPROM 185 | ```clock_gain``` | low/high | 所有带XTAL引脚 | 外部晶体的时钟增益 186 | ```ale_enabled``` | true/false | 仅STC89 | 如果 true,正常 GPIO,如果 false,则启用ALE引脚 187 | ```xram_enabled``` | true/false | 仅STC89 | 使用内部 XRAM ( 仅适用于 STC89 ) 188 | ```watchdog_por_enabled``` | true/false | 全部 | 复位复位后的看门狗状态( POR ) 189 | ```low_voltage_reset``` | low/high | STC12A/STC12 | 低电压复位级别( 低:~3.3V, 高: ~3.7V) 190 | ```low_voltage_reset``` | true/false | STC12 | 启用RESET2引脚低压检测 191 | ```low_voltage_reset``` | true/false | STC15A | 启用低电压复位( brownout ) 192 | ```clock_source``` | internal/external | 带XTAL的STC12A+ | 使用内部( RC ) 或者外部( 晶体) 时钟 193 | ```watchdog_stop_idle``` | true/false | STC12A+ | 在空闲模式停止看门狗 194 | ```watchdog_prescale``` | 2,4,8,...,256 | STC12A+ | 看门狗定时器预分频器,必须是两个电源。 195 | ```reset_pin_enabled``` | true/false | STC12+ | 如果 true,正常 GPIO,如果 false,则复位引脚 196 | ```oscillator_stable_delay``` | 4096,...,32768 | 仅STC11F系列 | 时钟中的晶体稳定延迟。 一定是 two。 197 | ```por_reset_delay``` | short/long | STC12+ | 复位复位( POR ) 延迟 198 | ```low_voltage_threshold``` | 0...7 | STC15A+ | 低电压检测阈值。型号特定 199 | ```eeprom_lvd_inhibit``` | true/false | STC15A+ | 在低电压情况下忽略EEPROM写入 200 | ```rstout_por_state``` | low/high | STC15+ | 上电复位后的RSTOUT / RSTSV引脚状态 201 | ```uart1_remap``` | true/false | STC8 | 通过UART1到UART2引脚( 用于单导线UART模式) 202 | ```uart2_passthrough``` | true/false | STC15+ | 直通UART1至UART2引脚(用于单线UART模式) 203 | ```uart2_pin_mode``` | push-pull/normal | STC15+ | UART2 TX引脚的输出模式 204 | ```cpu_core_voltage``` | low/mid/high | STC15W+ | CPU核心电压( 低:~2.7V, mid: ~3.3V, 高:~3.6V) 205 | ```epwm_open_drain``` | true/false | STC8 | 上电复位后,对EPWM引脚使用漏极开路引脚模式 206 | ```program_eeprom_split``` | 512 - 65024 | STC8A8 w/ 64 KB | 选择代码闪存和EEPROM闪存之间的划分(以512字节块为单位) 207 | 208 | ### 频率微调 209 | 210 | 如果使用内部RC振荡器 (```clock_source=internal```), 211 | stcgal可以执行修整过程以将其调整为给定值。 仅在STC15系列及更高版本中受支持。 212 | 调整值与设备选项一起存储。 使用 ```-t``` 标志请求对某个值进行修剪。 213 | 通常可以实现4000到30000 kHz之间的频率。 如果修剪失败,stcgal将中止。 214 | 215 | ### 自动功率循环 216 | 217 | STC的微控制器需要上电复位才能调用引导加载程序,这可能很不方便。 218 | stcgal可以使用串行接口的DTR控制信号来自动执行此操作。 219 | 当通过```-a```用自动复位功能时,DTR信号有效约500 ms。 220 | 这需要外部电路来实际切换电源。 221 | 在某些情况下,当微控制器仅消耗很少的功率时,就有可能直接从DTR信号提供功率。 222 | 223 | 作为DTR的替代方法,可以使用定制的shell命令或外部脚本(通过-r选项)来重置设备。 224 | 您应将命令与```-a```选项一起指定。不要忘了引号 ! 225 | 226 | 例如: 227 | 228 | ``` 229 | $ ./stcgal.py -P stc15 -a -r "echo 1 > /sys/class/gpio/gpio666/value" 230 | ``` 231 | 或者 232 | 233 | ``` 234 | $ ./stcgal.py -P stc15 -a -r "./powercycle.sh" 235 | ``` 236 | 237 | ### 退出状态 238 | 239 | 如果在执行stcgal时没有发生错误,则退出状态为 0.。 240 | 任何错误( 如协议错误或者 I/O 错误) 都会导致退出状态 1。 241 | 如果用户按ctrl键中止 stcgal,则会导致退出状态为 2. 242 | 243 | ### USB支持 244 | 245 | STC15W4系列具有一个基于USB的BSL,可以选择性的使用它。 246 | stcgal中的USB支持是实验性的,将来可能会改变。 247 | USB模式是通过使用“ usb15”协议启用的。 248 | USB协议会忽略端口(```-p```)标志以及波特率选项。同时不支持RC频率调整。 249 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright (c) 2016 Grigori Goronzy 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | 24 | import stcgal 25 | from setuptools import setup, find_packages 26 | 27 | with open("doc/PyPI.md", "r") as fh: 28 | long_description = fh.read() 29 | 30 | setup( 31 | name = "stcgal", 32 | version = stcgal.__version__, 33 | packages = find_packages(exclude=["doc", "tests"]), 34 | install_requires = ["pyserial>=3.0", "tqdm>=4.0.0"], 35 | extras_require = { 36 | "usb": ["pyusb>=1.0.0"] 37 | }, 38 | entry_points = { 39 | "console_scripts": [ 40 | "stcgal = stcgal.frontend:cli", 41 | ], 42 | }, 43 | description = "STC MCU ISP flash tool", 44 | long_description = long_description, 45 | long_description_content_type = "text/markdown", 46 | keywords = "stc mcu microcontroller 8051 mcs-51", 47 | url = "https://github.com/grigorig/stcgal", 48 | author = "Grigori Goronzy", 49 | author_email = "greg@kinoho.net", 50 | license = "MIT License", 51 | platforms = "any", 52 | classifiers = [ 53 | "Development Status :: 5 - Production/Stable", 54 | "Environment :: Console", 55 | "Intended Audience :: Developers", 56 | "License :: OSI Approved :: MIT License", 57 | "Operating System :: POSIX", 58 | "Operating System :: Microsoft :: Windows", 59 | "Operating System :: MacOS", 60 | "Programming Language :: Python :: 3", 61 | "Programming Language :: Python :: 3.5", 62 | "Programming Language :: Python :: 3.6", 63 | "Topic :: Software Development :: Embedded Systems", 64 | "Topic :: Software Development", 65 | ], 66 | test_suite = "tests", 67 | tests_require = ["PyYAML"], 68 | ) 69 | -------------------------------------------------------------------------------- /stcgal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright (c) 2013-2015 Grigori Goronzy 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | 24 | import sys 25 | import stcgal.frontend 26 | 27 | if __name__ == "__main__": 28 | sys.exit(stcgal.frontend.cli()) 29 | -------------------------------------------------------------------------------- /stcgal/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "1.10" 2 | -------------------------------------------------------------------------------- /stcgal/__main__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2013-2015 Grigori Goronzy 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | 23 | import sys 24 | import stcgal.frontend 25 | 26 | if __name__ == "__main__": 27 | sys.exit(stcgal.frontend.cli()) 28 | -------------------------------------------------------------------------------- /stcgal/frontend.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2013-2015 Grigori Goronzy 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | 23 | import sys 24 | import argparse 25 | import stcgal 26 | import serial 27 | from stcgal.utils import BaudType 28 | from stcgal.protocols import Stc89Protocol 29 | from stcgal.protocols import Stc89AProtocol 30 | from stcgal.protocols import Stc12AProtocol 31 | from stcgal.protocols import Stc12BProtocol 32 | from stcgal.protocols import Stc12Protocol 33 | from stcgal.protocols import Stc15Protocol 34 | from stcgal.protocols import Stc15AProtocol 35 | from stcgal.protocols import StcUsb15Protocol 36 | from stcgal.protocols import Stc8Protocol 37 | from stcgal.protocols import Stc8dProtocol 38 | from stcgal.protocols import Stc8gProtocol 39 | from stcgal.protocols import StcAutoProtocol 40 | from stcgal.protocols import StcProtocolException 41 | from stcgal.protocols import StcFramingException 42 | from stcgal.ihex import IHex 43 | 44 | class StcGal: 45 | """STC ISP flash tool frontend""" 46 | 47 | def __init__(self, opts): 48 | self.opts = opts 49 | self.hexFileType = 8 50 | self.initialize_protocol(opts) 51 | 52 | def initialize_protocol(self, opts): 53 | """Initialize protocol backend""" 54 | if opts.protocol == "stc89": 55 | self.protocol = Stc89Protocol(opts.port, opts.handshake, opts.baud) 56 | elif opts.protocol == "stc89a": 57 | self.protocol = Stc89AProtocol(opts.port, opts.handshake, opts.baud) 58 | elif opts.protocol == "stc12a": 59 | self.protocol = Stc12AProtocol(opts.port, opts.handshake, opts.baud) 60 | elif opts.protocol == "stc12b": 61 | self.protocol = Stc12BProtocol(opts.port, opts.handshake, opts.baud) 62 | elif opts.protocol == "stc12": 63 | self.protocol = Stc12Protocol(opts.port, opts.handshake, opts.baud) 64 | elif opts.protocol == "stc15a": 65 | self.protocol = Stc15AProtocol(opts.port, opts.handshake, opts.baud, round(opts.trim * 1000)) 66 | elif opts.protocol == "stc15": 67 | self.protocol = Stc15Protocol(opts.port, opts.handshake, opts.baud, round(opts.trim * 1000)) 68 | elif opts.protocol == "stc8": 69 | self.protocol = Stc8Protocol(opts.port, opts.handshake, opts.baud, round(opts.trim * 1000)) 70 | elif opts.protocol == "stc8d": 71 | self.protocol = Stc8dProtocol(opts.port, opts.handshake, opts.baud, round(opts.trim * 1000)) 72 | elif opts.protocol == "stc8g": 73 | """FIXME Ugly hack, but works until I fully implement the STC8G protocol""" 74 | if opts.trim < 27360: 75 | self.protocol = Stc8dProtocol(opts.port, opts.handshake, opts.baud, round(opts.trim * 1000)) 76 | else: 77 | self.protocol = Stc8gProtocol(opts.port, opts.handshake, opts.baud, round(opts.trim * 1000)) 78 | elif opts.protocol == "usb15": 79 | self.protocol = StcUsb15Protocol() 80 | else: 81 | self.protocol = StcAutoProtocol(opts.port, opts.handshake, opts.baud) 82 | self.protocol.debug = opts.debug 83 | 84 | def emit_options(self, options): 85 | """Set options from command line to protocol handler.""" 86 | 87 | for opt in options: 88 | try: 89 | kv = opt.split("=", 1) 90 | if len(kv) < 2: 91 | raise ValueError("incorrect format") 92 | self.protocol.set_option(kv[0], kv[1]) 93 | except ValueError as ex: 94 | raise NameError("invalid option '%s' (%s)" % (kv[0], ex)) 95 | 96 | def load_file_auto(self, fileobj): 97 | """Load file with Intel Hex autodetection.""" 98 | 99 | fname = fileobj.name.lower() 100 | if (fname.endswith(".hex") or fname.endswith(".ihx") or 101 | fname.endswith(".ihex")): 102 | try: 103 | hexfile = IHex.read(fileobj) 104 | self.hexFileType = hexfile.get_mode() 105 | binary = hexfile.extract_data() 106 | print("%d bytes (Intel HEX)" %len(binary)) 107 | return binary 108 | except ValueError as ex: 109 | raise IOError("invalid Intel HEX file (%s)" %ex) 110 | else: 111 | binary = fileobj.read() 112 | print("%d bytes (Binary)" %len(binary)) 113 | return binary 114 | 115 | def program_mcu(self): 116 | """Execute the standard programming flow.""" 117 | 118 | if self.opts.option: self.emit_options(self.opts.option) 119 | 120 | if self.protocol.split_code and self.protocol.model.iap: 121 | code_size = self.protocol.split_code 122 | ee_size = self.protocol.split_eeprom 123 | else: 124 | code_size = self.protocol.model.code 125 | ee_size = self.protocol.model.eeprom 126 | 127 | print("Loading flash: ", end="") 128 | sys.stdout.flush() 129 | bindata = self.load_file_auto(self.opts.code_image) 130 | 131 | if self.protocol.model.mcs251 and self.hexFileType != 32: 132 | print("Invalid input file. MCU is an MCS-251, input file MUST specify a linear", file=sys.stderr) 133 | print("base address, i.e. contain a type 04 record. More information at:", file=sys.stderr) 134 | print("https://en.wikipedia.org/wiki/Intel_HEX", file=sys.stderr) 135 | else: 136 | # warn if it overflows 137 | if len(bindata) > code_size: 138 | print("WARNING: code_image overflows into eeprom segment!", file=sys.stderr) 139 | if len(bindata) > (code_size + ee_size): 140 | print("WARNING: code_image truncated!", file=sys.stderr) 141 | bindata = bindata[0:code_size + ee_size] 142 | 143 | # add eeprom data if supplied 144 | if self.opts.eeprom_image: 145 | print("Loading EEPROM: ", end="") 146 | sys.stdout.flush() 147 | eedata = self.load_file_auto(self.opts.eeprom_image) 148 | if len(eedata) > ee_size: 149 | print("WARNING: eeprom_image truncated!", file=sys.stderr) 150 | eedata = eedata[0:ee_size] 151 | if len(bindata) < code_size: 152 | bindata += bytes([0xff] * (code_size - len(bindata))) 153 | elif len(bindata) > code_size: 154 | print("WARNING: eeprom_image overlaps code_image!", file=sys.stderr) 155 | bindata = bindata[0:code_size] 156 | bindata += eedata 157 | 158 | # pad to 512 byte boundary 159 | if len(bindata) % 512: 160 | bindata += b'\xff' * (512 - len(bindata) % 512) 161 | 162 | self.protocol.handshake() 163 | self.protocol.erase_flash(len(bindata), code_size) 164 | self.protocol.program_flash(bindata) 165 | self.protocol.program_options() 166 | 167 | self.protocol.disconnect() 168 | 169 | def erase_mcu(self): 170 | """Erase MCU without programming""" 171 | 172 | code_size = self.protocol.model.code 173 | 174 | self.protocol.handshake() 175 | self.protocol.erase_flash(code_size, code_size) 176 | self.protocol.disconnect() 177 | 178 | def run(self): 179 | """Run programmer, main entry point.""" 180 | 181 | if self.opts.version: 182 | print("stcgal {}".format(stcgal.__version__)) 183 | return 0 184 | 185 | try: 186 | self.protocol.connect(autoreset=self.opts.autoreset, resetcmd=self.opts.resetcmd, resetpin=self.opts.resetpin) 187 | if isinstance(self.protocol, StcAutoProtocol): 188 | if not self.protocol.protocol_name: 189 | raise StcProtocolException("cannot detect protocol") 190 | base_protocol = self.protocol 191 | self.opts.protocol = self.protocol.protocol_name 192 | print("Protocol detected: %s" % self.opts.protocol) 193 | # recreate self.protocol with proper protocol class 194 | self.initialize_protocol(self.opts) 195 | else: 196 | base_protocol = None 197 | 198 | self.protocol.initialize(base_protocol) 199 | except KeyboardInterrupt: 200 | sys.stdout.flush() 201 | print("interrupted") 202 | return 2 203 | except (StcFramingException, StcProtocolException) as ex: 204 | sys.stdout.flush() 205 | print("Protocol error: %s" % ex, file=sys.stderr) 206 | if not isinstance(self.protocol, StcAutoProtocol): 207 | self.protocol.disconnect() 208 | return 1 209 | except serial.SerialException as ex: 210 | sys.stdout.flush() 211 | print("Serial port error: %s" % ex, file=sys.stderr) 212 | return 1 213 | except IOError as ex: 214 | sys.stdout.flush() 215 | print("I/O error: %s" % ex, file=sys.stderr) 216 | return 1 217 | except Exception as ex: 218 | sys.stdout.flush() 219 | print("Unexpected error: %s" % ex, file=sys.stderr) 220 | return 1 221 | 222 | try: 223 | if self.opts.code_image: 224 | self.program_mcu() 225 | elif self.opts.erase: 226 | self.erase_mcu() 227 | else: 228 | self.protocol.disconnect() 229 | return 0 230 | except NameError as ex: 231 | sys.stdout.flush() 232 | print("Option error: %s" % ex, file=sys.stderr) 233 | self.protocol.disconnect() 234 | return 1 235 | except (StcFramingException, StcProtocolException) as ex: 236 | sys.stdout.flush() 237 | print("Protocol error: %s" % ex, file=sys.stderr) 238 | self.protocol.disconnect() 239 | return 1 240 | except KeyboardInterrupt: 241 | sys.stdout.flush() 242 | print("interrupted", file=sys.stderr) 243 | self.protocol.disconnect() 244 | return 2 245 | except serial.SerialException as ex: 246 | print("Serial port error: %s" % ex, file=sys.stderr) 247 | return 1 248 | except IOError as ex: 249 | sys.stdout.flush() 250 | print("I/O error: %s" % ex, file=sys.stderr) 251 | self.protocol.disconnect() 252 | return 1 253 | 254 | 255 | def cli(): 256 | # check arguments 257 | parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, 258 | description="stcgal {} - an STC MCU ISP flash tool\n".format(stcgal.__version__) + 259 | "(C) 2014-2018 Grigori Goronzy and others\nhttps://github.com/grigorig/stcgal") 260 | exclusives = parser.add_mutually_exclusive_group() 261 | exclusives.add_argument("code_image", help="code segment file to flash (BIN/HEX)", type=argparse.FileType("rb"), nargs='?') 262 | parser.add_argument("eeprom_image", help="eeprom segment file to flash (BIN/HEX)", type=argparse.FileType("rb"), nargs='?') 263 | exclusives.add_argument("-e", "--erase", help="only erase flash memory", action="store_true") 264 | parser.add_argument("-a", "--autoreset", help="cycle power automatically by asserting DTR", action="store_true") 265 | parser.add_argument("-A", "--resetpin", help="pin to hold down when using --autoreset (default: DTR)", 266 | choices=["dtr", "rts", "dtr_inverted", "rts_inverted"], default="dtr") 267 | parser.add_argument("-r", "--resetcmd", help="shell command for board power-cycling (instead of DTR assertion)", action="store") 268 | parser.add_argument("-P", "--protocol", help="protocol version (default: auto)", 269 | choices=["stc89", "stc89a", "stc12a", "stc12b", "stc12", "stc15a", "stc15", "stc8", "stc8d", "stc8g", "usb15", "auto"], default="auto") 270 | parser.add_argument("-p", "--port", help="serial port device", default="/dev/ttyUSB0") 271 | parser.add_argument("-b", "--baud", help="transfer baud rate (default: 115200)", type=BaudType(), default=115200) 272 | parser.add_argument("-l", "--handshake", help="handshake baud rate (default: 2400)", type=BaudType(), default=2400) 273 | parser.add_argument("-o", "--option", help="set option (can be used multiple times, see documentation)", action="append") 274 | parser.add_argument("-t", "--trim", help="RC oscillator frequency in kHz (STC15+ series only)", type=float, default=0.0) 275 | parser.add_argument("-D", "--debug", help="enable debug output", action="store_true") 276 | parser.add_argument("-V", "--version", help="print version info and exit", action="store_true") 277 | opts = parser.parse_args() 278 | 279 | # run programmer 280 | gal = StcGal(opts) 281 | return gal.run() 282 | -------------------------------------------------------------------------------- /stcgal/ihex.py: -------------------------------------------------------------------------------- 1 | # IHex by Kier Davis, modified for Python 3 2 | # Public Domain 3 | # https://github.com/kierdavis/IHex 4 | 5 | import struct 6 | import codecs 7 | 8 | 9 | class IHex: 10 | """Intel HEX parser and writer""" 11 | 12 | @classmethod 13 | def read(cls, lines): 14 | """Read Intel HEX data from string or lines""" 15 | ihex = cls() 16 | 17 | for line in lines: 18 | line = line.strip() 19 | if not line: 20 | continue 21 | 22 | t, a, d = ihex.parse_line(line) 23 | if t == 0x00: 24 | ihex.insert_data(a, d) 25 | 26 | elif t == 0x01: 27 | break # Should we check for garbage after this? 28 | 29 | elif t == 0x02: 30 | ihex.set_mode(16) 31 | ihex.linearBaseAddress = struct.unpack(">H", d[0:2])[0] << 4 32 | 33 | elif t == 0x03: 34 | ihex.set_mode(16) 35 | 36 | cs, ip = struct.unpack(">2H", d[0:2]) 37 | ihex.set_start((cs, ip)) 38 | 39 | elif t == 0x04: 40 | ihex.set_mode(32) 41 | ihex.linearBaseAddress = struct.unpack(">H", d[0:2])[0] << 16 42 | 43 | elif t == 0x05: 44 | ihex.set_mode(32) 45 | ihex.set_start(struct.unpack(">I", d[0:4])[0]) 46 | 47 | else: 48 | raise ValueError("Invalid type byte") 49 | 50 | return ihex 51 | 52 | @classmethod 53 | def read_file(cls, fname): 54 | """Read Intel HEX data from file""" 55 | f = open(fname, "rb") 56 | ihex = cls.read(f) 57 | f.close() 58 | return ihex 59 | 60 | def __init__(self): 61 | self.areas = {} 62 | self.start = None 63 | self.mode = 8 64 | self.row_bytes = 16 65 | self.linearBaseAddress = 0 66 | 67 | def set_row_bytes(self, row_bytes): 68 | """Set output hex file row width (bytes represented per row).""" 69 | if row_bytes < 1 or row_bytes > 0xff: 70 | raise ValueError("Value out of range: (%r)" % row_bytes) 71 | self.row_bytes = row_bytes 72 | 73 | def extract_data(self, start=None, end=None): 74 | """Extract binary data""" 75 | if start is None: 76 | start = 0 77 | 78 | if end is None: 79 | result = bytearray() 80 | 81 | for addr, data in self.areas.items(): 82 | if addr >= start: 83 | if len(result) < (addr - start): 84 | result[len(result):addr - start] = bytes( 85 | addr - start - len(result)) 86 | result[addr - start:addr - start + len(data)] = data 87 | 88 | return bytes(result) 89 | 90 | result = bytearray() 91 | 92 | for addr, data in self.areas.items(): 93 | if addr >= start and addr < end: 94 | data = data[:end - addr] 95 | if len(result) < (addr - start): 96 | result[len(result):addr - start] = bytes( 97 | addr - start - len(result)) 98 | result[addr - start:addr - start + len(data)] = data 99 | 100 | return bytes(result) 101 | 102 | def set_start(self, start=None): 103 | self.start = start 104 | 105 | def set_mode(self, mode): 106 | self.mode = mode 107 | 108 | def get_mode(self): 109 | return self.mode 110 | 111 | def get_linearBaseAddress(self): 112 | return self.linearBaseAddress 113 | 114 | def get_area(self, addr): 115 | for start, data in self.areas.items(): 116 | end = start + len(data) 117 | if addr >= start and addr <= end: 118 | return start 119 | 120 | return None 121 | 122 | def insert_data(self, istart, idata): 123 | iend = istart + len(idata) 124 | 125 | area = self.get_area(istart) 126 | if area is None: 127 | self.areas[istart] = idata 128 | 129 | else: 130 | data = self.areas[area] 131 | # istart - iend + len(idata) + len(data) 132 | self.areas[area] = data[ 133 | :istart - area] + idata + data[iend - area:] 134 | 135 | def calc_checksum(self, data): 136 | total = sum(data) 137 | return (-total) & 0xFF 138 | 139 | def parse_line(self, rawline): 140 | if rawline[0:1] != b":": 141 | raise ValueError("Invalid line start character (%r)" % rawline[0]) 142 | 143 | try: 144 | line = codecs.decode(rawline[1:], "hex_codec") 145 | except ValueError: 146 | raise ValueError("Invalid hex data") 147 | 148 | length, addr, line_type = struct.unpack(">BHB", line[:4]) 149 | 150 | dataend = length + 4 151 | data = line[4:dataend] 152 | 153 | cs1 = line[dataend] 154 | cs2 = self.calc_checksum(line[:dataend]) 155 | 156 | if cs1 != cs2: 157 | raise ValueError("Checksums do not match") 158 | 159 | return (line_type, addr, data) 160 | 161 | def make_line(self, line_type, addr, data): 162 | line = struct.pack(">BHB", len(data), addr, line_type) 163 | line += data 164 | line += bytes([self.calc_checksum(line)]) 165 | return ":" + line.hex().upper() + "\r\n" 166 | 167 | def write(self): 168 | """Write Intel HEX data to string""" 169 | output = "" 170 | 171 | for start, data in sorted(self.areas.items()): 172 | i = 0 173 | segbase = 0 174 | 175 | while i < len(data): 176 | chunk = data[i:i + self.row_bytes] 177 | 178 | addr = start 179 | newsegbase = segbase 180 | 181 | if self.mode == 8: 182 | addr = addr & 0xFFFF 183 | 184 | elif self.mode == 16: 185 | t = addr & 0xFFFF 186 | newsegbase = (addr - t) >> 4 187 | addr = t 188 | 189 | if newsegbase != segbase: 190 | output += self.make_line( 191 | 0x02, 0, struct.pack(">H", newsegbase)) 192 | segbase = newsegbase 193 | 194 | elif self.mode == 32: 195 | newsegbase = addr >> 16 196 | addr = addr & 0xFFFF 197 | 198 | if newsegbase != segbase: 199 | output += self.make_line( 200 | 0x04, 0, struct.pack(">H", newsegbase)) 201 | segbase = newsegbase 202 | segbase = newsegbase 203 | 204 | output += self.make_line(0x00, addr, chunk) 205 | 206 | i += self.row_bytes 207 | start += self.row_bytes 208 | 209 | if self.start is not None: 210 | if self.mode == 16: 211 | output += self.make_line( 212 | 0x03, 0, struct.pack(">2H", self.start[0], self.start[1])) 213 | elif self.mode == 32: 214 | output += self.make_line( 215 | 0x05, 0, struct.pack(">I", self.start)) 216 | 217 | output += self.make_line(0x01, 0, b"") 218 | return output 219 | 220 | def write_file(self, fname): 221 | """Write Intel HEX data to file""" 222 | f = open(fname, "w") 223 | f.write(self.write()) 224 | f.close() 225 | -------------------------------------------------------------------------------- /stcgal/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013-2015 Grigori Goronzy 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | # 21 | 22 | import argparse 23 | import serial 24 | 25 | class Utils: 26 | """Common utility functions""" 27 | 28 | @classmethod 29 | def to_bool(cls, val): 30 | """make sensible boolean from string or other type value""" 31 | 32 | if not val: 33 | return False 34 | if isinstance(val, bool): 35 | return val 36 | elif isinstance(val, int): 37 | return bool(val) 38 | return True if val[0].lower() == "t" or val[0] == "1" else False 39 | 40 | @classmethod 41 | def to_int(cls, val): 42 | """make int from any value, nice error message if not possible""" 43 | 44 | try: 45 | return int(val, 0) 46 | except (TypeError, ValueError): 47 | raise ValueError("invalid integer") 48 | 49 | @classmethod 50 | def hexstr(cls, bytestr, sep=""): 51 | """make formatted hex string output from byte sequence""" 52 | 53 | return sep.join(["%02X" % x for x in bytes(bytestr)]) 54 | 55 | @classmethod 56 | def decode_packed_bcd(cls, byt): 57 | """Decode two-digit packed BCD value""" 58 | return (byt & 0x0f) + (10 * (byt >> 4)) 59 | 60 | 61 | class BaudType: 62 | """Check baud rate for validity""" 63 | 64 | def __call__(self, string): 65 | baud = int(string) 66 | if baud not in serial.Serial.BAUDRATES: 67 | raise argparse.ArgumentTypeError("illegal baudrate") 68 | return baud 69 | 70 | def __repr__(self): 71 | return "baudrate" 72 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grigorig/stcgal/fdf5fdd60515a260bb303dcf7b251c2b2671f91c/tests/__init__.py -------------------------------------------------------------------------------- /tests/iap15f2k61s2.yml: -------------------------------------------------------------------------------- 1 | name: IAP15F2K61S2 programming test 2 | protocol: stc15 3 | code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57] 4 | responses: 5 | - [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] 6 | - [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] 7 | - [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] 8 | - [0x01] 9 | - [0x05] 10 | - [0x03, 0x0D, 0x00, 0x00, 0x21, 0x02, 0x26, 0x32] 11 | - [0x02, 0x54] 12 | - [0x02, 0x54] 13 | - [0x02, 0x54] 14 | - [0x02, 0x54] 15 | - [0x02, 0x54] 16 | - [0x02, 0x54] 17 | - [0x02, 0x54] 18 | - [0x02, 0x54] 19 | - [0x04, 0x54] -------------------------------------------------------------------------------- /tests/stc12c2052ad.yml: -------------------------------------------------------------------------------- 1 | name: STC12C2052AD programming test 2 | protocol: stc12a 3 | code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57] 4 | responses: 5 | - [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] 6 | - [0x8F, 0xC0, 0x79, 0x3F, 0xFE, 0x28, 0x85] 7 | - [0x8E, 0xC0, 0x79, 0x3F, 0xFE, 0x28] 8 | - [0x80] 9 | - [0x80] 10 | - [0x80] 11 | - [0x80] 12 | - [0x80] 13 | - [0x80, 0x66] 14 | - [0x80, 0x80] 15 | - [0x80, 0x80] 16 | - [0x80, 0x80] 17 | - [0x80, 0xEE] 18 | - [0x10, 0xC0, 0x16, 0xF7, 0xFF, 0xBF, 0x03, 0xFF, 0x58, 0x44, 0xFD, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFD, 0xF7, 0xF7, 0xFF] 19 | - [0x80] -------------------------------------------------------------------------------- /tests/stc12c5a60s2.yml: -------------------------------------------------------------------------------- 1 | name: STC12C5A60S2 programming test 2 | protocol: stc12 3 | code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57] 4 | responses: 5 | - [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] 6 | - [0x8F] 7 | - [0x8F, 0xC0, 0x7E, 0x3F, 0xFE, 0xA0, 0x83, 0x04] 8 | - [0x84, 0xC0, 0x7E, 0x3F, 0xFE, 0xA0, 0x04] 9 | - [0x00] 10 | - [0x00, 0x03] 11 | - [0x00, 0x00] 12 | - [0x00, 0x00] 13 | - [0x00, 0x00] 14 | - [0x8D] 15 | - [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] 16 | -------------------------------------------------------------------------------- /tests/stc15f104e.yml: -------------------------------------------------------------------------------- 1 | name: STC15F104E programming test 2 | protocol: stc15a 3 | code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57] 4 | responses: 5 | - [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] 6 | - [0x8f] 7 | - [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] 8 | - [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] 9 | - [0x01] 10 | - [0x05] 11 | - [0x03, 0x0C, 0x00, 0x00, 0x17, 0x01, 0xA0, 0xE0] 12 | - [0x02, 0x54] 13 | - [0x02, 0x54] 14 | - [0x02, 0x54] 15 | - [0x02, 0x54] 16 | - [0x02, 0x54] 17 | - [0x02, 0x54] 18 | - [0x02, 0x54] 19 | - [0x02, 0x54] 20 | - [0x04, 0x54] -------------------------------------------------------------------------------- /tests/stc15l104w.yml: -------------------------------------------------------------------------------- 1 | name: STC15L104W programming test 2 | protocol: stc15 3 | code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57] 4 | responses: 5 | - [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] 6 | - [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] 7 | - [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] 8 | - [0x01] 9 | - [0x05] 10 | - [0x03, 0x0C, 0x00, 0x00, 0x17, 0x01, 0xA0, 0xE0] 11 | - [0x02, 0x54] 12 | - [0x02, 0x54] 13 | - [0x02, 0x54] 14 | - [0x02, 0x54] 15 | - [0x02, 0x54] 16 | - [0x02, 0x54] 17 | - [0x02, 0x54] 18 | - [0x02, 0x54] 19 | - [0x04, 0x54] -------------------------------------------------------------------------------- /tests/stc15w4k56s4.yml: -------------------------------------------------------------------------------- 1 | name: STC15W4K56S4 programming test 2 | protocol: stc15 3 | code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57] 4 | responses: 5 | - [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] 6 | - [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] 7 | - [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] 8 | - [0x01] 9 | - [0x05] 10 | - [0x03, 0xF5, 0x28, 0x00, 0xA5, 0x03, 0x27, 0x49] 11 | - [0x02, 0x54] 12 | - [0x02, 0x54] 13 | - [0x02, 0x54] 14 | - [0x02, 0x54] 15 | - [0x02, 0x54] 16 | - [0x02, 0x54] 17 | - [0x02, 0x54] 18 | - [0x02, 0x54] 19 | - [0x07, 0x54] 20 | - [0x04, 0x54] 21 | -------------------------------------------------------------------------------- /tests/stc89c52rc.yml: -------------------------------------------------------------------------------- 1 | name: STC89C52RC programming test 2 | protocol: stc89 3 | code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57] 4 | responses: 5 | - [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] 6 | - [0x8F, 0xFD, 0xF8, 0x02, 0x10, 0x28, 0x81] 7 | - [0x8E, 0xFD, 0xF8, 0x02, 0x10, 0x28] 8 | - [0x80] 9 | - [0x80] 10 | - [0x80] 11 | - [0x80] 12 | - [0x80] 13 | - [0x80, 0x66] 14 | - [0x80, 0x80] 15 | - [0x80, 0x80] 16 | - [0x80, 0x80] 17 | - [0x8D, 0xFC, 0xFF, 0xF6, 0xFF] 18 | - [0x10, 0xC0, 0x16, 0xF6, 0xFF, 0xF1, 0x03, 0xFF, 0x43, 0x43, 0xFC] 19 | - [0x80] 20 | -------------------------------------------------------------------------------- /tests/stc8a8k64s4a12.yml: -------------------------------------------------------------------------------- 1 | name: STC8A8K64S4A12 programming test 2 | protocol: stc8 3 | code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57] 4 | responses: 5 | - [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] 6 | - [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] 7 | - [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] 8 | - [0x01] 9 | - [0x05] 10 | - [0x03, 0xF6, 0x28, 0x02, 0xBC, 0x26, 0x98, 0xDF] 11 | - [0x02, 0x54] 12 | - [0x02, 0x54] 13 | - [0x02, 0x54] 14 | - [0x02, 0x54] 15 | - [0x02, 0x54] 16 | - [0x02, 0x54] 17 | - [0x02, 0x54] 18 | - [0x02, 0x54] 19 | - [0x07, 0x54] 20 | - [0x04, 0x54] -------------------------------------------------------------------------------- /tests/stc8f2k08s2-untrimmed.yml: -------------------------------------------------------------------------------- 1 | name: STC8F2K08S2 untrimmed programming test 2 | protocol: stc8 3 | code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57] 4 | responses: 5 | - [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] -------------------------------------------------------------------------------- /tests/test_fuzzing.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Grigori Goronzy 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | 23 | """Tests with fuzzing of input data""" 24 | 25 | import random 26 | import sys 27 | import unittest 28 | from unittest.mock import patch 29 | import yaml 30 | import stcgal.frontend 31 | import stcgal.protocols 32 | from tests.test_program import get_default_opts, convert_to_bytes 33 | 34 | class ByteArrayFuzzer: 35 | """Fuzzer for byte arrays""" 36 | 37 | def __init__(self): 38 | self.rng = random.Random() 39 | self.cut_propability = 0.01 # probability for cutting off an array early 40 | self.cut_min = 0 # minimum cut amount 41 | self.cut_max = sys.maxsize # maximum cut amount 42 | self.bitflip_probability = 0.0001 # probability for flipping a bit 43 | self.randomize_probability = 0.001 # probability for randomizing a char 44 | 45 | def fuzz(self, inp): 46 | """Fuzz an array of bytes according to predefined settings""" 47 | arr = bytearray(inp) 48 | arr = self.cut_off(arr) 49 | self.randomize(arr) 50 | return bytes(arr) 51 | 52 | def randomize(self, arr): 53 | """Randomize array contents with bitflips and random bytes""" 54 | for i, _ in enumerate(arr): 55 | for j in range(8): 56 | if self.rng.random() < self.bitflip_probability: 57 | arr[i] ^= (1 << j) 58 | if self.rng.random() < self.randomize_probability: 59 | arr[i] = self.rng.getrandbits(8) 60 | 61 | def cut_off(self, arr): 62 | """Cut off data from end of array""" 63 | if self.rng.random() < self.cut_propability: 64 | cut_limit = min(len(arr), self.cut_max) 65 | cut_len = self.rng.randrange(self.cut_min, cut_limit) 66 | arr = arr[0:len(arr) - cut_len] 67 | return arr 68 | 69 | class TestProgramFuzzed(unittest.TestCase): 70 | """Special programming cycle tests that use a fuzzing approach""" 71 | 72 | @patch("stcgal.protocols.StcBaseProtocol.read_packet") 73 | @patch("stcgal.protocols.Stc89Protocol.write_packet") 74 | @patch("stcgal.protocols.serial.Serial", autospec=True) 75 | @patch("stcgal.protocols.time.sleep") 76 | @patch("sys.stdout") 77 | @patch("sys.stderr") 78 | def test_program_fuzz(self, err, out, sleep_mock, serial_mock, write_mock, read_mock): 79 | """Test programming cycles with fuzzing enabled""" 80 | yml = [ 81 | "./tests/iap15f2k61s2.yml", 82 | "./tests/stc12c2052ad.yml", 83 | "./tests/stc15w4k56s4.yml", 84 | "./tests/stc12c5a60s2.yml", 85 | "./tests/stc89c52rc.yml", 86 | "./tests/stc15l104w.yml", 87 | "./tests/stc15f104e.yml", 88 | "./tests/stc8a8k64s4a12.yml", 89 | ] 90 | fuzzer = ByteArrayFuzzer() 91 | fuzzer.cut_propability = 0.01 92 | fuzzer.bitflip_probability = 0.005 93 | fuzzer.rng = random.Random(1) 94 | for y in yml: 95 | with self.subTest(msg="trace {}".format(y)): 96 | self.single_fuzz(y, serial_mock, fuzzer, read_mock, err, out, 97 | sleep_mock, write_mock) 98 | 99 | def single_fuzz(self, yml, serial_mock, fuzzer, read_mock, err, out, sleep_mock, write_mock): 100 | """Test a single programming cycle with fuzzing""" 101 | with open(yml) as test_file: 102 | test_data = yaml.load(test_file.read(), Loader=yaml.SafeLoader) 103 | for _ in range(1000): 104 | with self.subTest(): 105 | opts = get_default_opts() 106 | opts.protocol = test_data["protocol"] 107 | opts.code_image.read.return_value = bytes(test_data["code_data"]) 108 | serial_mock.return_value.inWaiting.return_value = 1 109 | fuzzed_responses = [] 110 | for arr in convert_to_bytes(test_data["responses"]): 111 | fuzzed_responses.append(fuzzer.fuzz(arr)) 112 | read_mock.side_effect = fuzzed_responses 113 | gal = stcgal.frontend.StcGal(opts) 114 | self.assertGreaterEqual(gal.run(), 0) 115 | err.reset_mock() 116 | out.reset_mock() 117 | sleep_mock.reset_mock() 118 | serial_mock.reset_mock() 119 | write_mock.reset_mock() 120 | read_mock.reset_mock() 121 | -------------------------------------------------------------------------------- /tests/test_ihex.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2021 Grigori Goronzy 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | 23 | import unittest 24 | import stcgal.ihex 25 | 26 | class IHEXTests(unittest.TestCase): 27 | """Tests for IHEX reader""" 28 | 29 | def test_simple(self): 30 | """Test reading a basic, valid file""" 31 | lines = [ 32 | b":0B00000068656C6C6F5F776F726C645A", 33 | b":00000001FF" 34 | ] 35 | bindata = stcgal.ihex.IHex.read(lines).extract_data() 36 | self.assertEqual(bindata, b"hello_world") 37 | 38 | def test_empty(self): 39 | """Test reading an empty file""" 40 | lines = [] 41 | bindata = stcgal.ihex.IHex.read(lines).extract_data() 42 | self.assertEqual(bindata, b"") 43 | 44 | def test_invalid(self): 45 | """Test invalid encoded data""" 46 | lines = [ 47 | ":abc" 48 | ] 49 | with self.assertRaises(ValueError): 50 | stcgal.ihex.IHex.read(lines) 51 | 52 | def test_roundtrip(self): 53 | """Test round-trip through encoder/decoder""" 54 | bindata = b"12345678" 55 | for mode in (8, 16, 32): 56 | with self.subTest(mode): 57 | hexer = stcgal.ihex.IHex() 58 | hexer.set_mode(mode) 59 | hexer.insert_data(0, bindata) 60 | encoded = hexer.write().encode("ASCII").splitlines() 61 | decoded = stcgal.ihex.IHex.read(encoded).extract_data() 62 | self.assertEqual(decoded, bindata) 63 | -------------------------------------------------------------------------------- /tests/test_program.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Grigori Goronzy 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | 23 | """Tests that simulate a whole programming cycle""" 24 | 25 | import unittest 26 | from unittest.mock import patch 27 | import yaml 28 | import stcgal.frontend 29 | import stcgal.protocols 30 | from stcgal.protocols import StcProtocolException 31 | 32 | def convert_to_bytes(list_of_lists): 33 | """Convert lists of integer lists to list of byte lists""" 34 | return [bytes(x) for x in list_of_lists] 35 | 36 | def get_default_opts(): 37 | """Get a default preconfigured option object""" 38 | opts = unittest.mock.MagicMock() 39 | opts.protocol = "stc89" 40 | opts.autoreset = False 41 | opts.port = "" 42 | opts.baud = 19200 43 | opts.handshake = 9600 44 | opts.trim = 22118 45 | opts.eeprom_image = None 46 | opts.debug = False 47 | opts.version = False 48 | opts.code_image.name = "test.bin" 49 | opts.code_image.read.return_value = b"123456789" 50 | return opts 51 | 52 | class ProgramTests(unittest.TestCase): 53 | """Test MCU programming cycles for different families, based on traces""" 54 | 55 | @patch("stcgal.protocols.StcBaseProtocol.read_packet") 56 | @patch("stcgal.protocols.Stc89Protocol.write_packet") 57 | @patch("stcgal.protocols.serial.Serial", autospec=True) 58 | @patch("stcgal.protocols.time.sleep") 59 | @patch("sys.stdout") 60 | def test_program_stc89(self, out, sleep_mock, serial_mock, write_mock, read_mock): 61 | """Test a programming cycle with STC89 protocol""" 62 | self._program_yml("./tests/stc89c52rc.yml", serial_mock, read_mock) 63 | 64 | @patch("stcgal.protocols.StcBaseProtocol.read_packet") 65 | @patch("stcgal.protocols.Stc89Protocol.write_packet") 66 | @patch("stcgal.protocols.serial.Serial", autospec=True) 67 | @patch("stcgal.protocols.time.sleep") 68 | @patch("sys.stdout") 69 | def test_program_stc12(self, out, sleep_mock, serial_mock, write_mock, read_mock): 70 | """Test a programming cycle with STC12 protocol""" 71 | self._program_yml("./tests/stc12c5a60s2.yml", serial_mock, read_mock) 72 | 73 | @patch("stcgal.protocols.StcBaseProtocol.read_packet") 74 | @patch("stcgal.protocols.Stc89Protocol.write_packet") 75 | @patch("stcgal.protocols.serial.Serial", autospec=True) 76 | @patch("stcgal.protocols.time.sleep") 77 | @patch("sys.stdout") 78 | def test_program_stc12a(self, out, sleep_mock, serial_mock, write_mock, read_mock): 79 | """Test a programming cycle with STC12A protocol""" 80 | self._program_yml("./tests/stc12c2052ad.yml", serial_mock, read_mock) 81 | 82 | def test_program_stc12b(self): 83 | """Test a programming cycle with STC12B protocol""" 84 | self.skipTest("trace missing") 85 | 86 | @patch("stcgal.protocols.StcBaseProtocol.read_packet") 87 | @patch("stcgal.protocols.Stc89Protocol.write_packet") 88 | @patch("stcgal.protocols.serial.Serial", autospec=True) 89 | @patch("stcgal.protocols.time.sleep") 90 | @patch("sys.stdout") 91 | def test_program_stc15f2(self, out, sleep_mock, serial_mock, write_mock, read_mock): 92 | """Test a programming cycle with STC15 protocol, F2 series""" 93 | self._program_yml("./tests/iap15f2k61s2.yml", serial_mock, read_mock) 94 | 95 | @patch("stcgal.protocols.StcBaseProtocol.read_packet") 96 | @patch("stcgal.protocols.Stc89Protocol.write_packet") 97 | @patch("stcgal.protocols.serial.Serial", autospec=True) 98 | @patch("stcgal.protocols.time.sleep") 99 | @patch("sys.stdout") 100 | def test_program_stc15w4(self, out, sleep_mock, serial_mock, write_mock, read_mock): 101 | """Test a programming cycle with STC15 protocol, W4 series""" 102 | self._program_yml("./tests/stc15w4k56s4.yml", serial_mock, read_mock) 103 | 104 | @patch("stcgal.protocols.StcBaseProtocol.read_packet") 105 | @patch("stcgal.protocols.Stc89Protocol.write_packet") 106 | @patch("stcgal.protocols.serial.Serial", autospec=True) 107 | @patch("stcgal.protocols.time.sleep") 108 | @patch("sys.stdout") 109 | def test_program_stc8a8(self, out, sleep_mock, serial_mock, write_mock, read_mock): 110 | """Test a programming cycle with STC8 protocol, STC8A8 series""" 111 | self._program_yml("./tests/stc8a8k64s4a12.yml", serial_mock, read_mock) 112 | 113 | @unittest.skip("trace is broken") 114 | @patch("stcgal.protocols.StcBaseProtocol.read_packet") 115 | @patch("stcgal.protocols.Stc89Protocol.write_packet") 116 | @patch("stcgal.protocols.serial.Serial", autospec=True) 117 | @patch("stcgal.protocols.time.sleep") 118 | @patch("sys.stdout") 119 | def test_program_stc15a(self, out, sleep_mock, serial_mock, write_mock, read_mock): 120 | """Test a programming cycle with STC15A protocol""" 121 | self._program_yml("./tests/stc15f104e.yml", serial_mock, read_mock) 122 | 123 | @patch("stcgal.protocols.StcBaseProtocol.read_packet") 124 | @patch("stcgal.protocols.Stc89Protocol.write_packet") 125 | @patch("stcgal.protocols.serial.Serial", autospec=True) 126 | @patch("stcgal.protocols.time.sleep") 127 | @patch("sys.stdout") 128 | def test_program_stc15l1(self, out, sleep_mock, serial_mock, write_mock, read_mock): 129 | """Test a programming cycle with STC15 protocol, L1 series""" 130 | self._program_yml("./tests/stc15l104w.yml", serial_mock, read_mock) 131 | 132 | @patch("stcgal.protocols.StcBaseProtocol.read_packet") 133 | @patch("stcgal.protocols.Stc89Protocol.write_packet") 134 | @patch("stcgal.protocols.serial.Serial", autospec=True) 135 | @patch("stcgal.protocols.time.sleep") 136 | @patch("sys.stdout") 137 | def test_program_stc8_untrimmed(self, out, sleep_mock, serial_mock, write_mock, read_mock): 138 | """Test error with untrimmed MCU""" 139 | with open("./tests/stc8f2k08s2-untrimmed.yml") as test_file: 140 | test_data = yaml.load(test_file.read(), Loader=yaml.SafeLoader) 141 | opts = get_default_opts() 142 | opts.trim = 0.0 143 | opts.protocol = test_data["protocol"] 144 | opts.code_image.read.return_value = bytes(test_data["code_data"]) 145 | serial_mock.return_value.inWaiting.return_value = 1 146 | read_mock.side_effect = convert_to_bytes(test_data["responses"]) 147 | gal = stcgal.frontend.StcGal(opts) 148 | self.assertEqual(gal.run(), 1) 149 | 150 | def test_program_stc15w4_usb(self): 151 | """Test a programming cycle with STC15W4 USB protocol""" 152 | self.skipTest("USB not supported yet, trace missing") 153 | 154 | def _program_yml(self, yml, serial_mock, read_mock): 155 | """Program MCU with data from YAML file""" 156 | with open(yml) as test_file: 157 | test_data = yaml.load(test_file.read(), Loader=yaml.SafeLoader) 158 | opts = get_default_opts() 159 | opts.protocol = test_data["protocol"] 160 | opts.code_image.read.return_value = bytes(test_data["code_data"]) 161 | serial_mock.return_value.inWaiting.return_value = 1 162 | read_mock.side_effect = convert_to_bytes(test_data["responses"]) 163 | gal = stcgal.frontend.StcGal(opts) 164 | self.assertEqual(gal.run(), 0) 165 | -------------------------------------------------------------------------------- /tests/test_utils.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Grigori Goronzy 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | 23 | """Tests for utility functions and other misc parts""" 24 | 25 | import argparse 26 | import unittest 27 | from stcgal.utils import Utils, BaudType 28 | 29 | class TestUtils(unittest.TestCase): 30 | """Test for utility functions in the Utils class""" 31 | 32 | def test_to_bool(self): 33 | """Test special utility function for bool conversion""" 34 | self.assertTrue(Utils.to_bool(True)) 35 | self.assertTrue(Utils.to_bool("true")) 36 | self.assertTrue(Utils.to_bool("True")) 37 | self.assertTrue(Utils.to_bool("t")) 38 | self.assertTrue(Utils.to_bool("T")) 39 | self.assertTrue(Utils.to_bool(1)) 40 | self.assertTrue(Utils.to_bool(-1)) 41 | self.assertFalse(Utils.to_bool(0)) 42 | self.assertFalse(Utils.to_bool(None)) 43 | self.assertFalse(Utils.to_bool("false")) 44 | self.assertFalse(Utils.to_bool("False")) 45 | self.assertFalse(Utils.to_bool("f")) 46 | self.assertFalse(Utils.to_bool("F")) 47 | self.assertFalse(Utils.to_bool("")) 48 | 49 | def test_to_int(self): 50 | """Test wrapped integer conversion""" 51 | self.assertEqual(Utils.to_int("2"), 2) 52 | self.assertEqual(Utils.to_int("0x10"), 16) 53 | with self.assertRaises(ValueError): 54 | Utils.to_int("a") 55 | with self.assertRaises(ValueError): 56 | Utils.to_int("") 57 | with self.assertRaises(ValueError): 58 | Utils.to_int(None) 59 | 60 | def test_hexstr(self): 61 | """Test byte array formatter""" 62 | self.assertEqual(Utils.hexstr([10]), "0A") 63 | self.assertEqual(Utils.hexstr([1, 2, 3]), "010203") 64 | with self.assertRaises(Exception): 65 | Utils.hexstr([400, 500]) 66 | 67 | def test_decode_packed_bcd(self): 68 | """Test packed BCD decoder""" 69 | self.assertEqual(Utils.decode_packed_bcd(0x01), 1) 70 | self.assertEqual(Utils.decode_packed_bcd(0x10), 10) 71 | self.assertEqual(Utils.decode_packed_bcd(0x11), 11) 72 | self.assertEqual(Utils.decode_packed_bcd(0x25), 25) 73 | self.assertEqual(Utils.decode_packed_bcd(0x99), 99) 74 | 75 | class TestBaudType(unittest.TestCase): 76 | """Test BaudType class""" 77 | 78 | def test_create_baud_type(self): 79 | """Test creation of BaudType instances""" 80 | baud_type = BaudType() 81 | self.assertEqual(baud_type("2400"), 2400) 82 | self.assertEqual(baud_type("115200"), 115200) 83 | with self.assertRaises(argparse.ArgumentTypeError): 84 | baud_type("2374882") 85 | --------------------------------------------------------------------------------