STC15 reverse engineering

Note: so far only based on STC15F104E! This protocol has been renamed ot STC15A.

Basic differences between STC12 and STC15

* Initial MCU response is an ack (0x80) packet. Host needs to respond
  with the same ack and pulse 0x7f again, then MCU sends the info
  packet.

* Frequency timings sent with info packet are different; the calculation
  is the same but only four timings are sent, followed by two other
  unknown timings and two zero words.

* A new handshake is used to tune the RC oscillator for a given
  frequency.

* The baudrate isn't changed with a complicated handshake, it is just
  switched to with a 0x8e type packet.
  This may be different on other MCUs that have a hardware UART.

* Transfers use 64 bytes block size.
  Possibly that's because the 15F104E only has 128 bytes RAM. It
  might use bigger blocks on MCUs with more RAM.

* Position of many option bits has changed, and more bits are used.


The RC oscillator calibration

Theory of operation:
* Host sends a sequence of challenges. These are values to be
  programmed into an internal RC oscillator calibration register.
* Host sends 0x7f pulses
* MCU sends back responses, which are the runtime of the baudrate
  timing counter (similar to the info packet)
* Host repeats this with finer trimmed challenge values.
* Host determines calibration value with the lowest error.
* Host sends baudrate switch packet
* Host sends option packet to program frequency after flash programming

The STC software uses a fixed set of coarse grained trim values to
try. These are:

sequence                        clock (MHz)
0x1800 0x1880 0x1880 0x18ff     [4, 7.5]
0x1880 0x18ff 0x5800 0x5880     (7.5, 10]
0x5800 0x5880 0x5880 0x58ff     (10, 15]
0x5880 0x58ff 0x9800 0x9880     (15, 21]
0x9800 0x9880 0x9880 0x98ff     (21, 31] 
0xd800 0xd880 0xd880 0xd8b4     (31, 40]

In addition it sends a sequence for the programming speed:
0x5800 0x5880 for normal speed and 0x9800 0x9880 for high
speed programming.

Then, by linear interpolation, it choses a suitable range of
fine-tuning trim values to try according to the counter values sent
by the MCU.

The programming speed trim value is only determined by linear
interpolation of the two trim challenges sent in the first round of
calibration. This seems to be good enough.


New packets host2mcu
--------------------

1. RC calibration challenge

Payload: 0x65, T0, .., T6, 0xff, 0xff, 0x06, CNT,
         TR00, TR01, 0x02, 0x00,
         TR10, TR11, 0x02, 0x00,
         ...

T0...T6 := trim constants, from info packet
CNT := number of calibration challenges (max 11)
TRxx := calibration challenge trim values

2. Baudrate switch

Payload: 0x8e, TR0, TR1, BDIV, 0xa1, 0x64, FC,
         0x00, IAP, 0x20, 0xff, 0x00

TR0, TR1 := trim value for programming frequency
            (normal = 11.0592 MHz, highspeed = 22.1184 MHz)
BDIV := baud rate divider (normal: baud = 115200 / BDIV, highspeed: baud = 230400 / BDIV)
FC := some frequency constant, normal: 0xdc, highspeed: 0xb8
IAP := IAP delay, normal: 0x83, highspeed: 0x81



Communication dump with notes
-----------------------------

Firmware version: 6.7Q
Magic: F294
UID: 0A00002802C4EB

This seems to work differently from what we've seen on STC10/11/12 series with
firmware 6.2/6.5.

Get status packet
-----------------

mcu2host:

2014-01-09 11:35:17.917063:
46 B9 68 00 07 80 00 EF 16
2014-01-09 11:35:18.056583:
46 B9 68 00 40 50 02 B0 02 B0 02 AF 02 B0 02 E6
02 E7 00 00 00 00 67 51 FF F2 94 8C EF 3B F5 58
34 FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00
FF FF FF FF FF FF FF FF 58 50 0C 94 21 FF 29 21
82 16

host2mcu:

2014-01-09 11:37:13.000352:
7F 7F 7F 7F 46 B9 6A 00 07 80 00 F1 16 7F 7F 7F
7F
2014-01-09 11:37:13.298358:
46 B9 6A 00 07 82 00 F3 16

* MCU first sends an ACK packet (0x80),
  which needs to be replied to with the same ACK (0x80) by the host.
  after that host needs to pulse (send 0x7f until reply) again

* STC software then adjust the frequency of the RC, after that the handshake
  is done.

Program hello.bin
-----------------

host2mcu:

FF 7F 7F 7F 7F 46 B9 6A 00 07 80 00 F1 16 7F 7F
7F 7F 7F 7F
2014-01-09 11:46:06.334342:
46 B9 6A 00 0D 50 00 00 36 01 F2 94 02 84 16 
^ Initiate baudrate handshake, like STC12


46
B9 6A 00 2A 65 58 50 0C 95 21 FF 2B FF FF 06 06
58 00 02 00 58 80 02 00 58 80 02 00 58 FF 02 00
58 00 02 00 58 80 02 00 0A 32 16 
^ This is a new type of packet (0x65), presumably
  for frequency adjustment


7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F
46 B9 6A 00 3E 65 58 50 0C
95 21 FF 2B FF FF 06 0B 58 24 02 00 58 25 02 00
58 26 02 00 58 27 02 00 58 28 02 00 58 29 02 00
58 2A 02 00 58 2B 02 00 58 2C 02 00 58 2D 02 00
58 2E 02 00 0B 51 16
^ Same new packet again!

7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 46 B9 6A 00 12 8E 58 29 0C A1
64 DC 12 83 20 FF 00 05 2C 16
^ Straight jumps to setting the new baudrate,
  instead of testing it like in earlier firmware.

2014-01-09 11:46:07.466357:
46 B9 6A 00 3B 84 FF 00 02 00 00 10 00 00 00 00
00 00 00 00 00 00 00 00 80 7F 7E 7D 7C 7B 7A 79
78 77 76 75 74 73 72 71 70 6F 6E 6D 6C 6B 6A 69
68 67 66 65 64 63 62 61 60 5F 11 09 16
^ erase flash

2014-01-09 11:46:08.322346:
46 B9 6A 00 4D 00 00 00 00 00 00 40 02 00 08 12
00 3F 80 FE 75 81 07 12 00 4C E5 82 60 03 02 00
03 E4 78 FF F6 D8 FD 02 00 03 AE 82 AF 83 8E 04
8F 05 1E BE FF 01 1F EC 4D 60 0F 7C 90 7D 01 1C
BC FF 01 1D EC 4D 70 F7 80 E4 22 90 1A 85 16

46
B9 6A 00 4D 00 00 00 00 40 00 40 03 E8 12 00 1E
E5 80 F4 F5 80 80 F3 75 82 00 22 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 08 AC 16

46 B9
6A 00 4D 00 00 00 00 80 00 40 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 01 77 16

46 B9 6A
00 4D 00 00 00 00 C0 00 40 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 01 B7 16

46 B9 6A 00
4D 00 00 00 01 00 00 40 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 F8 16

46 B9 6A 00 4D
00 00 00 01 40 00 40 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 01 38 16

46 B9 6A 00 4D 00
00 00 01 80 00 40 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 01 78 16

46 B9 6A 00 4D 00 00
00 01 C0 00 40 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 01 B8 16

^ flash write packets. curiously they use
  a smaller block size, 64 bytes.

46 B9 6A 00 0D 69 00 00
36 01 F2 94 02 9D 16
^ finish packet

2014-01-09 11:46:09.571449:
46 B9 6A 00 1A 8D EF FC F7 58 29 FF FF FF FF FF
FF FF FF FF FF FF FF FF FF 12 66 16
^ set options packet

2014-01-09 11:46:09.774383:
46 B9 6A 00 07 82 00 F3 16
^ reset packet

mcu2host:

2014-01-09 11:49:50.004984:
46 B9 68 00 07 80 00 EF 16
^ ACK

2014-01-09 11:49:50.166675:
46 B9 68 00 40 50 02 9C 02 9C 02 9C 02 9C 02 E6
02 E7 00 00 00 00 67 51 FF F2 94 8C EF FC F7 58
29 FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00
FF FF FF 12 FF FF FF FF 58 50 0C 95 21 FF 2B 21
01 16
^ status packet

46 B9 68 00 07 8F 00 FE 16
^ acknowledge handshake

2014-01-09 11:49:50.566935:
46 B9 68 00 2A 65 58 50 0C 95 21 FF 2B FF FF 06
06 58 00 02 4A 58 80 03 45 58 80 03 46 58 FF 04
3D 58 00 02 4A 58 80 03 45 0B D6 16
^ reply to first new 0x65 packet

2014-01-09 11:49:50.941928:
46 B9 68 00 3E 65 58 50 0C 95 21 FF 2B FF FF 06
0B 58 24 02 92 58 25 02 94 58 26 02 97 58 27 02
9A 58 28 02 9A 58 29 02 9C 58 2A 02 9F 58 2B 02
A2 58 2C 02 A1 58 2D 02 A4 58 2E 02 A8 12 0A 16
^ reply to second 0x65 packet

2014-01-09 11:49:51.391860:
46 B9 68 00 13 84 58 29 0C A1 64 DC 12 83 20 FF
^ new packet type (0x84)

00 05 05 26 16
2014-01-09 11:49:52.253370:
46 B9 68 00 0E 00 0A 00 00 28 02 C4 EB 02 59 16
^ acknowledge erase

2014-01-09 11:49:52.393369:
46 B9 68 00 08 00 8E 00 FE 16
2014-01-09 11:49:52.518566:
46 B9 68 00 08 00 75 00 E5 16
2014-01-09 11:49:52.643749:
46 B9 68 00 08 00 00 00 70 16
2014-01-09 11:49:52.772755:
46 B9 68 00 08 00 00 00 70 16
2014-01-09 11:49:52.905131:
46 B9 68 00 08 00 00 00 70 16
2014-01-09 11:49:53.047673:
46 B9 68 00 08 00 00 00 70 16
2014-01-09 11:49:53.170668:
46 B9 68 00 08 00 00 00 70 16
2014-01-09 11:49:53.299131:
46 B9 68 00 08 00 00 00 70 16
^ acknowlegde flash writes

2014-01-09 11:49:53.460551:
46 B9 68 00 07 8D 00 FC 16
^ acknowledge finish flash programming

                  | last three bytes of UID
46 B9 68 00 2F 50 02
C4 EB 58 29 03 FF 67 51 EF FC F7 58 29 FF FF FF
FF FF FF FF FF FF FF FF FF FF FF 12 FF FF FF FF
00 00 00 00 00 00 00 1A 36 16
^ acknowledge set options