Initial commit
This commit is contained in:
commit
cdbb6eee7c
BIN
doc/hello.bin
Normal file
BIN
doc/hello.bin
Normal file
Binary file not shown.
100
doc/stc11f08xe.txt
Normal file
100
doc/stc11f08xe.txt
Normal file
@ -0,0 +1,100 @@
|
||||
MCU: STC11F08XE
|
||||
Data: hello.bin
|
||||
Handshake: 9600
|
||||
Transfer: 9600
|
||||
Clock: 20 MHz
|
||||
|
||||
2014-01-06 17:13:42.017505: host2mcu
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F
|
||||
2014-01-06 17:13:42.315631: mcu2host
|
||||
46 B9 68 00 39 50 04 BC 04 BD 04 BD 04 BC 04 BC
|
||||
04 BD 04 BC 04 BC 65 4C 00 D3 64 8C BF 7F F7 FF
|
||||
FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 6B 0B D3 00 6A 82 80 11 4F 16
|
||||
2014-01-06 17:13:42.455472: host2mcu
|
||||
46 B9 6A 00 0D 50 00 00 36 01 D3 64 02 35 16
|
||||
2014-01-06 17:13:42.479849: mcu2host
|
||||
46 B9 68 00 07 8F 00 FE 16
|
||||
2014-01-06 17:13:42.504527: host2mcu
|
||||
46 B9 6A 00 0D 8F C0 7E 3F FE A0 83 04 A4 16
|
||||
2014-01-06 17:13:42.768346: mcu2host
|
||||
46 B9 68 00 0E 8F C0 7E 3F FE A0 83 04 04 A7 16
|
||||
2014-01-06 17:13:42.987584: host2mcu
|
||||
46 B9 6A 00 0C 8E C0 7E 3F FE A0 04 1F 16
|
||||
2014-01-06 17:13:43.244111: mcu2host
|
||||
46 B9 68 00 0D 84 C0 7E 3F FE A0 04 04 18 16
|
||||
2014-01-06 17:13:43.286557: host2mcu
|
||||
46 B9 6A 00 8C 84 00 00 02 00 00 20 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 5E 5D 5C 5B 5A 59
|
||||
58 57 56 55 54 53 52 51 50 4F 4E 4D 4C 4B 4A 49
|
||||
48 47 46 45 44 43 42 41 40 3F 3E 3D 3C 3B 3A 39
|
||||
38 37 36 35 34 33 32 31 30 2F 2E 2D 2C 2B 2A 29
|
||||
28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 1A 19
|
||||
18 17 16 15 14 13 12 11 10 0F 0E 21 81 16
|
||||
2014-01-06 17:13:43.718954: mcu2host
|
||||
46 B9 68 00 0E 00 00 08 00 8E 00 A8 2E 01 E2 16
|
||||
2014-01-06 17:13:43.758507: host2mcu
|
||||
46 B9 6A 00 8D 00 00 00 00 00 00 80 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 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 22 7A 16
|
||||
2014-01-06 17:13:44.050030: mcu2host
|
||||
46 B9 68 00 08 00 03 00 73 16
|
||||
2014-01-06 17:13:44.063502: host2mcu
|
||||
46 B9 6A 00 8D 00 00 00 00 80 00 80 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 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 F7 16
|
||||
2014-01-06 17:13:44.261910: mcu2host
|
||||
46 B9 68 00 08 00 00 00 70 16
|
||||
2014-01-06 17:13:44.279527: host2mcu
|
||||
46 B9 6A 00 8D 00 00 00 01 00 00 80 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 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
|
||||
2014-01-06 17:13:44.486933: mcu2host
|
||||
46 B9 68 00 08 00 00 00 70 16
|
||||
2014-01-06 17:13:44.503472: host2mcu
|
||||
46 B9 6A 00 8D 00 00 00 01 80 00 80 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 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 F8 16
|
||||
2014-01-06 17:13:44.698788: mcu2host
|
||||
46 B9 68 00 08 00 00 00 70 16
|
||||
2014-01-06 17:13:44.716462: host2mcu
|
||||
46 B9 6A 00 0D 69 00 00 36 01 D3 64 02 4E 16
|
||||
2014-01-06 17:13:44.755837: mcu2host
|
||||
46 B9 68 00 07 8D 00 FC 16
|
||||
2014-01-06 17:13:44.786562: host2mcu
|
||||
46 B9 6A 00 1B 8D BF 7F F7 FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF 01 30 9A 92 11 97 16
|
||||
2014-01-06 17:13:44.843366: mcu2host
|
||||
46 B9 68 00 24 50 BF 7F F7 FF FF 03 FF 65 4C BF
|
||||
7F F7 FF FF FF FF 01 00 6B 0B D3 00 6A 82 80 00
|
||||
00 00 00 0F A9 16
|
||||
2014-01-06 17:13:44.968518: host2mcu
|
||||
46 B9 6A 00 07 82 00 F3 16
|
||||
|
70
doc/stc12-options.txt
Normal file
70
doc/stc12-options.txt
Normal file
@ -0,0 +1,70 @@
|
||||
Model-specific configuration registers
|
||||
Placement of configuration values
|
||||
|
||||
"~" means the bit is a negated boolean. Sometimes values overlap,
|
||||
depending on MCU model.
|
||||
|
||||
In STC10/11/12 series, the first 4 MCS bytes have active
|
||||
values. Generally, unused bits should be set to 1.
|
||||
|
||||
|
||||
MCS0
|
||||
----
|
||||
|
||||
MSB 7 6 5 4 3 2 1 0 LSB
|
||||
~RS2LV OSC1 OSC0 RSPEN
|
||||
~LVD
|
||||
|
||||
RSPEN := RESET pin enable
|
||||
~RS2LV := RESET2 pin low voltage detect enable
|
||||
~LVD := low voltage detect enable
|
||||
OSC0, OSC1 := oscillator stabilization delay
|
||||
|
||||
OSC1 OSC0 delay
|
||||
0 0 4096
|
||||
0 1 8192
|
||||
1 0 16384
|
||||
1 1 32768
|
||||
|
||||
|
||||
MCS1
|
||||
----
|
||||
|
||||
MSB 7 6 5 4 3 2 1 0 LSB
|
||||
~PORD OSCG CLKSRC
|
||||
|
||||
~PORD := power-on-reset (POR) delay (0 = long, 1 = short)
|
||||
OSCG := high oscillator gain
|
||||
CLKSRC := clock source (0 = internal RC, 1 = external crystal)
|
||||
|
||||
|
||||
MCS2
|
||||
----
|
||||
|
||||
MSB 7 6 5 4 3 2 1 0 LSB
|
||||
~WDEN ~WDSTP WDPS2 WDPS1 WDPS0
|
||||
|
||||
~WDEN := watchdog enable after power-on-reset
|
||||
~WDSTP := stop watchdog counter in idle mode
|
||||
WDPS2...WDPS0 := watchdog counter prescaler
|
||||
|
||||
WDPS2 WDPS1 WDPS0 divisior
|
||||
0 0 0 2
|
||||
0 0 1 4
|
||||
0 1 0 8
|
||||
0 1 1 16
|
||||
1 0 0 32
|
||||
1 0 1 64
|
||||
1 1 0 128
|
||||
1 1 1 256
|
||||
|
||||
|
||||
MCS3
|
||||
----
|
||||
|
||||
MSB 7 6 5 4 3 2 1 0 LSB
|
||||
~EREE ~BSLD
|
||||
|
||||
~EREE := enable eeprom erase next time MCU is programmed
|
||||
~BSLD := enable BSL pin detect; i.e. BSL is only enabled if P1.0/P1.1
|
||||
(or others, depends on MCU model) are held low on POR.
|
182
doc/stc12-protocol.txt
Normal file
182
doc/stc12-protocol.txt
Normal file
@ -0,0 +1,182 @@
|
||||
STC10/11/12 reverse engineering
|
||||
|
||||
Initialisation/Synchronisation
|
||||
------------------------------
|
||||
|
||||
Send a constant stream of 0x7f bytes, and wait for an initial response
|
||||
by the MCU.
|
||||
|
||||
Basic frame format
|
||||
------------------
|
||||
|
||||
M0 M1 DR L0 L1 D0 ... Dn C0 C1 ME
|
||||
|
||||
M0 := 0x46
|
||||
M1 := 0xb9
|
||||
DR := 0x6a if host2mcu else 0x68
|
||||
L := 16 bit big endian packet length, counted from DR to ME
|
||||
C := 16 big endian modular sum from DR to Dn
|
||||
ME := 0x16
|
||||
|
||||
D0..Dn is the packet payload
|
||||
|
||||
In most cases, the first byte of the payload marks the type of packet
|
||||
or type of command. Responses by the MCU often use this type to tell
|
||||
the programmer software which kind of command should follow. For
|
||||
instance, after the baudrate handshake, the MCU replies with a
|
||||
type 0x84 packet, and 0x84 is used for "erase" command packets from
|
||||
the host.
|
||||
|
||||
Fun fact: The start marker (0x46, 0xb9) interpreted as UTF-16 is the
|
||||
Unicode character U+46B9, which is an unusual CJK ideograph (䚹)
|
||||
which translates as "to prepare" or "all ready" into English. How
|
||||
fitting! This might not be a coincidence.
|
||||
|
||||
Packets host2mcu
|
||||
----------------
|
||||
|
||||
1. Initiate baudrate handshake
|
||||
|
||||
Payload: 0x50, 0x07, 0x00, 0x36, 0x01, ID0, ID1
|
||||
^ is 0x00 with current STC software and 11F08XE, what gives?
|
||||
|
||||
ID0 = MCU ID, byte 1
|
||||
ID1 = MCU ID, byte 2
|
||||
|
||||
2. Test baudrate setting
|
||||
|
||||
Payload: 0x8f, 0xc0, brt, 0x3f, brt_csum, delay, iap
|
||||
|
||||
brt := MCU baudrate timer compare
|
||||
brt_csum := (2 * (256 - brt)) & 0xff
|
||||
delay := delay after baudrate change (0x40 seems to be fine),
|
||||
STC software always seems to use 0xa0
|
||||
iap := MCU IAP wait state register value
|
||||
|
||||
3. Switch to baudrate setting
|
||||
|
||||
Payload: 0x8e, 0xc0, brt, 0x3f, brt_csum, delay, iap
|
||||
^ current STC software *omits* this here!
|
||||
Almost the same as the test packet.
|
||||
|
||||
4. Erase flash memory
|
||||
|
||||
Payload: 0x84, 0xff, 0x00, blks, 0x00, 0x00, size,
|
||||
^ no idea what that is for, current STC software uses 0x00
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, ..., 0x0e
|
||||
|
||||
blks := 256 byte blocks to clear
|
||||
size := total number of 256 byte blocks (size of flash memory)
|
||||
|
||||
The 0x80..0x0e sequence seems to be some kind of magic code
|
||||
to stop flaky connections and the like from erasing the flash
|
||||
by accident.
|
||||
|
||||
"size" specifies the number of flash memory blocks. if blks > size,
|
||||
eeprom will be erased.
|
||||
|
||||
5. Program flash memory
|
||||
|
||||
Payload: 0x00, 0x00, 0x00, addr0, addr1, size0, size1, D0, ..., Dn
|
||||
|
||||
addr0, addr1 := big-endian 16 bit address
|
||||
size0, size1 := big-endian 16 bit block size, always 128
|
||||
D0...Dn := block data
|
||||
|
||||
Current STC software always seems to write at least 4 128 byte blocks
|
||||
for some reason. Data is zero-padded.
|
||||
|
||||
Current STC software always writes a sequential set of memory. Since
|
||||
flash and eeprom are essentially the same, any free space between
|
||||
flash to be written and eeprom to be written is padded with zeros,
|
||||
and then the whole batch is sent at once.
|
||||
|
||||
6. Finish flash programming
|
||||
|
||||
Payload: 0x69, 0x00, 0x00, 0x36, 0x01, ID0, ID1
|
||||
^ kSTC-ISP uses 0x07
|
||||
|
||||
This should be sent after all flash programming is done. I am not
|
||||
entirely sure why, though. Programming also works without it.
|
||||
|
||||
7. Set options
|
||||
|
||||
Payload: 0x8d, MS0, ..., MS15, CLK0, CLK1, CLK2, CLK3
|
||||
|
||||
MS0...MS15 := configuration registers specific to MCU model,
|
||||
not documented here.
|
||||
|
||||
CLK0...CLK3 := 32 bit big endian measured clock, in Hz
|
||||
|
||||
8. Reset MCU
|
||||
|
||||
Payload: 0x82
|
||||
|
||||
|
||||
Packets mcu2host
|
||||
----------------
|
||||
|
||||
1. Info packet
|
||||
|
||||
Payload: 0x50, SYNC00, SYNC01, ..., SYNC70, SYNC71,
|
||||
V1, V2, 0x00, ID0, ID1, 0x8c,
|
||||
MS0, ..., MS7,
|
||||
UID0, ..., UID6,
|
||||
unknown bytes follow
|
||||
|
||||
SYNC* := sequence of 8 16-bit big-endian counter values, recorded
|
||||
from the initial 0x7f sync sequence. this can be used to
|
||||
determine the MCU clock frequency.
|
||||
|
||||
V1 := version number, two digits packed BCD.
|
||||
V2 := stepping, one ASCII character.
|
||||
ID0 := MCU model ID, byte 1
|
||||
ID1 := MCU model ID, byte 2
|
||||
UID0...UID6 := 7 bytes of unique id
|
||||
|
||||
UID is only sent by some BSL versions, others send zero bytes.
|
||||
|
||||
2. Acknowledge baudrate handshake start
|
||||
|
||||
Payload: 0x8f
|
||||
|
||||
This means the programming software should erase the flash memory as
|
||||
the next step.
|
||||
|
||||
3. Acknowledge baudrate test
|
||||
|
||||
Payload: request packet payload with some pad byte appended to payload
|
||||
|
||||
4. Acknowledge baudrate switch
|
||||
|
||||
Payload: request packet payload with some pad byte appended to payload, and
|
||||
first payload byte changed to 0x84
|
||||
|
||||
5. Acknowledge erase
|
||||
|
||||
Payload: 0x00, [UID0, ..., UID6]
|
||||
|
||||
The UID is optional, not sent by all BSL versions.
|
||||
|
||||
6. Acknowledge block write
|
||||
|
||||
Payload: 0x00, csum
|
||||
|
||||
csum := 8 bit modular sum of flash block data
|
||||
|
||||
7. Acknowledge finish flash writing
|
||||
|
||||
Payload: 0x8d
|
||||
|
||||
This means the programming software should set options as the next
|
||||
step.
|
||||
|
||||
8. Acknowledge set options
|
||||
|
||||
Payload: 0x50, MS0, ..., MS4, 0x03, 0xff, V1, V2, MS0, ..., MS7,
|
||||
UID0, ..., UID6,
|
||||
unknown bytes follow
|
||||
|
||||
Some of the model-specific bytes are repeated twice (MS0-MS4).
|
100
doc/stc12c5a60s2.txt
Normal file
100
doc/stc12c5a60s2.txt
Normal file
@ -0,0 +1,100 @@
|
||||
MCU: STC12C5A60S2
|
||||
Data: hello.bin
|
||||
Handshake: 9600
|
||||
Transfer: 9600
|
||||
Clock: 20 MHz
|
||||
|
||||
2014-01-06 17:19:52.426530: host2mcu
|
||||
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
|
||||
7F 7F 7F 7F
|
||||
2014-01-06 17:19:52.722646: mcu2host
|
||||
46 B9 68 00 31 50 04 BD 04 BC 04 BC 04 BD 04 BC
|
||||
04 BC 04 BC 04 BC 62 49 00 D1 7E 8C FF 7F F7 FF
|
||||
FF FF 00 00 00 03 00 B0 02 2E 6B 00 CD 80 00 00
|
||||
11 7E 16
|
||||
2014-01-06 17:19:52.846519: host2mcu
|
||||
46 B9 6A 00 0D 50 00 00 36 01 D1 7E 02 4D 16
|
||||
2014-01-06 17:19:52.893712: mcu2host
|
||||
46 B9 68 00 07 8F 00 FE 16
|
||||
2014-01-06 17:19:52.928824: host2mcu
|
||||
46 B9 6A 00 0D 8F C0 7E 3F FE A0 83 04 A4 16
|
||||
2014-01-06 17:19:53.209386: mcu2host
|
||||
46 B9 68 00 0E 8F C0 7E 3F FE A0 83 04 04 A7 16
|
||||
2014-01-06 17:19:53.424544: host2mcu
|
||||
46 B9 6A 00 0C 8E C0 7E 3F FE A0 04 1F 16
|
||||
2014-01-06 17:19:53.679264: mcu2host
|
||||
46 B9 68 00 0D 84 C0 7E 3F FE A0 04 04 18 16
|
||||
2014-01-06 17:19:53.724472: host2mcu
|
||||
46 B9 6A 00 8C 84 00 00 02 00 00 F0 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 5E 5D 5C 5B 5A 59
|
||||
58 57 56 55 54 53 52 51 50 4F 4E 4D 4C 4B 4A 49
|
||||
48 47 46 45 44 43 42 41 40 3F 3E 3D 3C 3B 3A 39
|
||||
38 37 36 35 34 33 32 31 30 2F 2E 2D 2C 2B 2A 29
|
||||
28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 1A 19
|
||||
18 17 16 15 14 13 12 11 10 0F 0E 22 51 16
|
||||
2014-01-06 17:19:55.505307: mcu2host
|
||||
46 B9 68 00 07 00 00 6F 16
|
||||
2014-01-06 17:19:55.537548: host2mcu
|
||||
46 B9 6A 00 8D 00 00 00 00 00 00 80 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 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 22 7A 16
|
||||
2014-01-06 17:19:55.968298: mcu2host
|
||||
46 B9 68 00 08 00 03 00 73 16
|
||||
2014-01-06 17:19:55.986526: host2mcu
|
||||
46 B9 6A 00 8D 00 00 00 00 80 00 80 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 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 F7 16
|
||||
2014-01-06 17:19:56.412372: mcu2host
|
||||
46 B9 68 00 08 00 00 00 70 16
|
||||
2014-01-06 17:19:56.430530: host2mcu
|
||||
46 B9 6A 00 8D 00 00 00 01 00 00 80 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 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
|
||||
2014-01-06 17:19:56.865930: mcu2host
|
||||
46 B9 68 00 08 00 00 00 70 16
|
||||
2014-01-06 17:19:56.884481: host2mcu
|
||||
46 B9 6A 00 8D 00 00 00 01 80 00 80 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
00 00 00 00 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 F8 16
|
||||
2014-01-06 17:19:57.288219: mcu2host
|
||||
46 B9 68 00 08 00 00 00 70 16
|
||||
2014-01-06 17:19:57.306515: host2mcu
|
||||
46 B9 6A 00 0D 69 00 00 36 01 D1 7E 02 66 16
|
||||
2014-01-06 17:19:57.369302: mcu2host
|
||||
46 B9 68 00 07 8D 00 FC 16
|
||||
2014-01-06 17:19:57.412492: host2mcu
|
||||
46 B9 6A 00 1B 8D FF 7F F7 FF FF FF FF FF FF FF
|
||||
FF FF FF FF FF FF 01 30 5A 49 11 4E 16
|
||||
2014-01-06 17:19:57.511742: mcu2host
|
||||
46 B9 68 00 24 50 FF 7F F7 FF FF 03 FF 62 49 FF
|
||||
7F F7 FF FF FF FF 01 00 03 00 B0 02 2E 6B 00 CD
|
||||
80 00 00 10 09 16
|
||||
2014-01-06 17:19:57.672474: host2mcu
|
||||
46 B9 6A 00 07 82 00 F3 16
|
||||
|
568
stcgal.py
Executable file
568
stcgal.py
Executable file
@ -0,0 +1,568 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2013 Grigori Goronzy
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
#
|
||||
|
||||
# stcgal - STC MCU serial bootloader flash programmer
|
||||
|
||||
"""
|
||||
TODO:
|
||||
- Utils class?
|
||||
- error/exception handling
|
||||
- some more documentation / comments
|
||||
- private member naming, other style issues
|
||||
|
||||
- MCU database
|
||||
- Prepare for STC89/STC15 protocols
|
||||
"""
|
||||
|
||||
import serial
|
||||
import sys, os, time, struct
|
||||
import argparse
|
||||
|
||||
DEBUG = False
|
||||
|
||||
class Utils:
|
||||
"""make sensible boolean from string or other type value"""
|
||||
@classmethod
|
||||
def to_bool(self, val):
|
||||
if isinstance(val, bool): return val
|
||||
if isinstance(val, int): return bool(val)
|
||||
if len(val) == 0: return False
|
||||
return True if val[0].lower() == "t" or val[0] == "1" else False
|
||||
|
||||
|
||||
class Stc12Option:
|
||||
"""Manipulate STC10/11/12 series option bytes"""
|
||||
|
||||
def __init__(self, msr):
|
||||
self.msr = bytearray(msr)
|
||||
|
||||
"""list of options and their handlers"""
|
||||
self.options = (
|
||||
("reset_pin_enabled", self.get_reset_pin_enabled, self.set_reset_pin_enabled),
|
||||
("low_voltage_detect", self.get_low_voltage_detect, self.set_low_voltage_detect),
|
||||
("oscillator_stable_delay", self.get_osc_stable_delay, self.set_osc_stable_delay),
|
||||
("power_on_reset_delay", self.get_por_delay, self.set_por_delay),
|
||||
("clock_gain", self.get_clock_gain, self.set_clock_gain),
|
||||
("clock_source", self.get_clock_source, self.set_clock_source),
|
||||
("watchdog_por_enabled", self.get_watchdog, self.set_watchdog),
|
||||
("watchdog_stop_idle", self.get_watchdog_idle, self.set_watchdog_idle),
|
||||
("watchdog_prescale", self.get_watchdog_prescale, self.set_watchdog_prescale),
|
||||
("eeprom_erase_enabled", self.get_ee_erase, self.set_ee_erase),
|
||||
("bsl_pindetect_enabled", self.get_pindetect, self.set_pindetect),
|
||||
)
|
||||
|
||||
def print(self):
|
||||
print("Target options:")
|
||||
for name, get_func, _ in self.options:
|
||||
print(" %s=%s" % (name, get_func()))
|
||||
|
||||
def set_option(self, name, value):
|
||||
for opt, _, set_func in self.options:
|
||||
if opt == name:
|
||||
print("Option %s=%s" % (name, value))
|
||||
set_func(value)
|
||||
return
|
||||
raise ValueError
|
||||
|
||||
def get_option(self, name):
|
||||
for opt, get_func, _ in self.options:
|
||||
if opt == name:
|
||||
return get_func(name)
|
||||
raise ValueError
|
||||
|
||||
def get_msr(self):
|
||||
return bytes(self.msr)
|
||||
|
||||
def get_reset_pin_enabled(self):
|
||||
return bool(self.msr[0] & 1)
|
||||
|
||||
def set_reset_pin_enabled(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
self.msr[0] &= 0xfe
|
||||
self.msr[0] |= 0x01 if bool(val) else 0x00
|
||||
|
||||
def get_low_voltage_detect(self):
|
||||
return not bool(self.msr[0] & 64)
|
||||
|
||||
def set_low_voltage_detect(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
self.msr[0] &= 0xbf
|
||||
self.msr[0] |= 0x40 if not val else 0x00
|
||||
|
||||
def get_osc_stable_delay(self):
|
||||
return 2 ** (((self.msr[0] >> 4) & 0x03) + 12)
|
||||
|
||||
def set_osc_stable_delay(self, val):
|
||||
val = int(val, 0)
|
||||
osc_vals = {4096: 0, 8192: 1, 16384: 2, 32768: 3}
|
||||
if val not in osc_vals.keys(): raise ValueError
|
||||
self.msr[0] &= 0x8f
|
||||
self.msr[0] |= osc_vals[val] << 4
|
||||
|
||||
def get_por_delay(self):
|
||||
delay = not bool(self.msr[1] & 128)
|
||||
return "long" if delay else "short"
|
||||
|
||||
def set_por_delay(self, val):
|
||||
delays = {"short": 1, "long": 0}
|
||||
if val not in delays.keys(): raise ValueError
|
||||
self.msr[1] &= 0x7f
|
||||
self.msr[1] |= delays[val] << 7
|
||||
|
||||
def get_clock_gain(self):
|
||||
gain = bool(self.msr[1] & 64)
|
||||
return "high" if gain else "low"
|
||||
|
||||
def set_clock_gain(self, val):
|
||||
gains = {"low": 0, "high": 1}
|
||||
if val not in gains.keys(): raise ValueError
|
||||
self.msr[1] &= 0xbf
|
||||
self.msr[1] |= gains[val] << 6
|
||||
|
||||
def get_clock_source(self):
|
||||
source = bool(self.msr[1] & 2)
|
||||
return "external" if source else "internal"
|
||||
|
||||
def set_clock_source(self, val):
|
||||
sources = {"internal": 0, "external": 1}
|
||||
if val not in sources.keys(): raise ValueError
|
||||
self.msr[1] &= 0xfd
|
||||
self.msr[1] |= sources[val] << 1
|
||||
|
||||
def get_watchdog(self):
|
||||
return not bool(self.msr[2] & 32)
|
||||
|
||||
def set_watchdog(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
self.msr[2] &= 0xdf
|
||||
self.msr[2] |= 0x20 if not val else 0x00
|
||||
|
||||
def get_watchdog_idle(self):
|
||||
return not bool(self.msr[2] & 8)
|
||||
|
||||
def set_watchdog_idle(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
self.msr[2] &= 0xf7
|
||||
self.msr[2] |= 0x08 if not val else 0x00
|
||||
|
||||
def get_watchdog_prescale(self):
|
||||
return 2 ** (((self.msr[2]) & 0x07) + 1)
|
||||
|
||||
def set_watchdog_prescale(self, val):
|
||||
val = int(val, 0)
|
||||
wd_vals = {2: 0, 4: 1, 8: 2, 16: 3, 32: 4, 64: 5, 128: 6, 256: 7}
|
||||
if val not in wd_vals.keys(): raise ValueError
|
||||
self.msr[2] &= 0xf8
|
||||
self.msr[2] |= wd_vals[val]
|
||||
|
||||
def get_ee_erase(self):
|
||||
return not bool(self.msr[3] & 2)
|
||||
|
||||
def set_ee_erase(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
self.msr[3] &= 0xfd
|
||||
self.msr[3] |= 0x02 if not val else 0x00
|
||||
|
||||
def get_pindetect(self):
|
||||
return not bool(self.msr[3] & 1)
|
||||
|
||||
def set_pindetect(self, val):
|
||||
val = Utils.to_bool(val);
|
||||
self.msr[3] &= 0xfe
|
||||
self.msr[3] |= 0x01 if not val else 0x00
|
||||
|
||||
|
||||
class Stc12Protocol:
|
||||
"""Protocol handler for STC 10/11/12 series"""
|
||||
|
||||
"""magic word that starts a packet"""
|
||||
PACKET_START = bytes([0x46, 0xb9])
|
||||
|
||||
"""magic byte that ends a packet"""
|
||||
PACKET_END = bytes([0x16])
|
||||
|
||||
"""magic byte for packets received from MCU"""
|
||||
PACKET_MCU = bytes([0x68])
|
||||
|
||||
"""magic byte for packets sent by host"""
|
||||
PACKET_HOST = bytes([0x6a])
|
||||
|
||||
"""block size for programming flash"""
|
||||
PROGRAM_BLOCKSIZE = 128
|
||||
|
||||
def __init__(self, port, baud_handshake, baud_transfer):
|
||||
self.port = port
|
||||
self.baud_handshake = baud_handshake
|
||||
self.baud_transfer = baud_transfer
|
||||
|
||||
self.mcu_magic = 0
|
||||
self.mcu_clock_hz = 0.0
|
||||
self.mcu_bsl_version = ""
|
||||
self.options = None
|
||||
|
||||
def dump_packet(self, data, receive=True):
|
||||
if DEBUG:
|
||||
print("%s Packet data: " % ("<-" if receive else "->") +
|
||||
" ".join(hex(x) for x in data), file=sys.stderr)
|
||||
|
||||
def modular_sum(self, data):
|
||||
"""modular 16-bit sum"""
|
||||
|
||||
s = 0
|
||||
for b in data: s += b
|
||||
return s & 0xffff
|
||||
|
||||
def read_packet(self):
|
||||
"""Read and check packet from MCU.
|
||||
|
||||
Reads a packet of data from the MCU and and do
|
||||
validity and checksum checks on it.
|
||||
|
||||
Returns packet payload or None in case of an error.
|
||||
"""
|
||||
|
||||
# read and check frame start magic
|
||||
packet = bytes()
|
||||
packet += self.ser.read(2)
|
||||
if packet[0:2] != self.PACKET_START:
|
||||
print("Wrong magic (%s), discarding packet!" %
|
||||
packet[0:2], file=sys.stderr)
|
||||
self.dump_packet(packet)
|
||||
return None
|
||||
|
||||
# read direction and length
|
||||
packet += self.ser.read(3)
|
||||
if packet[2] != self.PACKET_MCU[0]:
|
||||
print("Wrong direction (%s), discarding packet!" %
|
||||
hex(packet[3]), file=sys.stderr)
|
||||
self.dump_packet(packet)
|
||||
return None
|
||||
|
||||
# read packet data
|
||||
packet_len, = struct.unpack(">H", packet[3:5])
|
||||
packet += self.ser.read(packet_len - 3)
|
||||
|
||||
# verify end code
|
||||
if packet[packet_len+1] != self.PACKET_END[0]:
|
||||
print("Wrong end code (%s), discarding packet!" %
|
||||
hex(packet[packet_len+1]), file=sys.stderr)
|
||||
self.dump_packet(packet)
|
||||
return None
|
||||
|
||||
# verify checksum
|
||||
packet_csum, = struct.unpack(">H", packet[packet_len-1:packet_len+1])
|
||||
calc_csum = sum(packet[2:packet_len-1]) & 0xffff
|
||||
if packet_csum != calc_csum:
|
||||
print("Wrong checksum (%s, expected %s), discarding packet!" %
|
||||
(hex(packet_csum), hex(calc_csum)), file=sys.stderr)
|
||||
self.dump_packet(packet)
|
||||
return None
|
||||
|
||||
self.dump_packet(packet, receive=True)
|
||||
|
||||
# payload only is returned
|
||||
return packet[5:packet_len-1]
|
||||
|
||||
def write_packet(self, data):
|
||||
"""Send packet to MCU.
|
||||
|
||||
Constructs a packet with supplied payload and sends it to the MCU.
|
||||
"""
|
||||
|
||||
# frame start and direction magic
|
||||
packet = bytes()
|
||||
packet += self.PACKET_START
|
||||
packet += self.PACKET_HOST
|
||||
|
||||
# packet length and payload
|
||||
packet += struct.pack(">H", len(data) + 6)
|
||||
packet += data
|
||||
|
||||
# checksum and end code
|
||||
packet += struct.pack(">H", sum(packet[2:]) & 0xffff)
|
||||
packet += self.PACKET_END
|
||||
|
||||
self.dump_packet(packet, receive=False)
|
||||
self.ser.write(packet)
|
||||
self.ser.flush()
|
||||
|
||||
def decode_status_packet(self, packet):
|
||||
"""Decode status packet"""
|
||||
|
||||
self.mcu_magic, = struct.unpack(">H", packet[20:22])
|
||||
|
||||
freq_counter = 0
|
||||
for i in range(8):
|
||||
freq_counter += struct.unpack(">H", packet[1+2*i:3+2*i])[0]
|
||||
freq_counter /= 8.0
|
||||
self.mcu_clock_hz = (self.baud_handshake * freq_counter * 12.0) / 7.0
|
||||
|
||||
bl_version, bl_stepping = struct.unpack("BB", packet[17:19])
|
||||
self.mcu_bsl_version = "%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
||||
chr(bl_stepping))
|
||||
|
||||
def calculate_baud(self):
|
||||
"""Calculate MCU baudrate setting.
|
||||
|
||||
Calculate appropriate baudrate settings for the MCU's UART,
|
||||
according to clock frequency and requested baud rate.
|
||||
"""
|
||||
|
||||
# baudrate is directly controlled by programming the MCU's BRT register
|
||||
brt = 256 - round((self.mcu_clock_hz) / (self.baud_transfer * 16))
|
||||
brt_csum = (2 * (256 - brt)) & 0xff
|
||||
baud_actual = (self.mcu_clock_hz) / (16 * (256 - brt))
|
||||
baud_error = (abs(self.baud_transfer - baud_actual) * 100.0) / self.baud_transfer
|
||||
if baud_error > 5.0:
|
||||
print("WARNING: baud rate error is %.2f%%. You may need to set a slower rate." %
|
||||
baud_error, file=sys.stderr)
|
||||
|
||||
# IAP wait states (according to datasheet(s))
|
||||
iap_wait = 0x80
|
||||
if self.mcu_clock_hz < 1E6: iap_wait = 0x87
|
||||
elif self.mcu_clock_hz < 2E6: iap_wait = 0x86
|
||||
elif self.mcu_clock_hz < 3E6: iap_wait = 0x85
|
||||
elif self.mcu_clock_hz < 6E6: iap_wait = 0x84
|
||||
elif self.mcu_clock_hz < 12E6: iap_wait = 0x83
|
||||
elif self.mcu_clock_hz < 20E6: iap_wait = 0x82
|
||||
elif self.mcu_clock_hz < 24E6: iap_wait = 0x81
|
||||
|
||||
# MCU delay after switching baud rates
|
||||
delay = 0x80
|
||||
|
||||
return brt, brt_csum, iap_wait, delay
|
||||
|
||||
def print_mcu_info(self):
|
||||
"""Print MCU status information"""
|
||||
|
||||
print("Target magic: %s" % hex(self.mcu_magic))
|
||||
print("Target frequency: %.3f MHz" % (self.mcu_clock_hz / 1E6))
|
||||
print("Target bootloader version: %s" % self.mcu_bsl_version)
|
||||
|
||||
def connect(self):
|
||||
"""Connect to MCU and initialize communication.
|
||||
|
||||
Set up serial port, send sync sequence and get part info.
|
||||
"""
|
||||
|
||||
self.ser = serial.Serial(port=self.port, baudrate=self.baud_handshake,
|
||||
parity=serial.PARITY_EVEN)
|
||||
|
||||
# send sync, and wait for MCU response
|
||||
print("Waiting for MCU, please cycle power...", end="")
|
||||
sys.stdout.flush()
|
||||
while True:
|
||||
self.ser.write(b"\x7f")
|
||||
self.ser.flush()
|
||||
time.sleep(0.015)
|
||||
if self.ser.inWaiting() > 0: break
|
||||
print("done")
|
||||
|
||||
# read status packet
|
||||
status_packet = self.read_packet()
|
||||
if status_packet == None or status_packet[0] != 0x50:
|
||||
print("Error receiving status packet, aborting!", file=sys.stderr)
|
||||
return False
|
||||
self.decode_status_packet(status_packet)
|
||||
self.print_mcu_info()
|
||||
self.options = Stc12Option(status_packet[23:27])
|
||||
self.options.print()
|
||||
|
||||
return True
|
||||
|
||||
def handshake(self):
|
||||
"""Do baudrate handshake
|
||||
|
||||
Initate and do the (rather complicated) baudrate handshake.
|
||||
"""
|
||||
|
||||
# start baudrate handshake
|
||||
brt, brt_csum, iap, delay = self.calculate_baud()
|
||||
print("Switching to %d baud..." % self.baud_transfer, end="")
|
||||
sys.stdout.flush()
|
||||
packet = bytes([0x50, 0x00, 0x00, 0x36, 0x01])
|
||||
packet += struct.pack(">H", self.mcu_magic)
|
||||
self.write_packet(packet)
|
||||
response = self.read_packet()
|
||||
if response == None or response[0] != 0x8f:
|
||||
print("Error receiving handshake packet, aborting!", file=sys.stderr)
|
||||
return False
|
||||
|
||||
# test new settings
|
||||
print("testing...", end="")
|
||||
sys.stdout.flush()
|
||||
packet = bytes([0x8f, 0xc0, brt, 0x3f, brt_csum, delay, iap])
|
||||
self.write_packet(packet)
|
||||
time.sleep(0.2)
|
||||
self.ser.baudrate = self.baud_transfer
|
||||
response = self.read_packet()
|
||||
self.ser.baudrate = self.baud_handshake
|
||||
if response == None or response[0] != 0x8f:
|
||||
print("Error receiving handshake packet, aborting!", file=sys.stderr)
|
||||
return False
|
||||
|
||||
# switch to the settings
|
||||
print("setting...", end="")
|
||||
sys.stdout.flush()
|
||||
packet = bytes([0x8e, 0xc0, brt, 0x3f, brt_csum, delay])
|
||||
self.write_packet(packet)
|
||||
time.sleep(0.2)
|
||||
self.ser.baudrate = self.baud_transfer
|
||||
response = self.read_packet()
|
||||
if response == None or response[0] != 0x84:
|
||||
print("Error receiving handshake packet, aborting!", file=sys.stderr)
|
||||
return False
|
||||
print("done")
|
||||
|
||||
return True
|
||||
|
||||
def erase_flash(self, erase_size, flash_size):
|
||||
"""Erase the MCU's flash memory.
|
||||
|
||||
Erase the flash memory with a block-erase command.
|
||||
"""
|
||||
|
||||
blks = (erase_size + 255) // 256
|
||||
size = (flash_size + 255) // 256
|
||||
print("Erasing %d blocks..." % blks)
|
||||
packet = bytes([0x84, 0x00, 0x00, blks, 0x00, 0x00, size,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00])
|
||||
for i in range(0x80, 0x0d, -1): packet += bytes([i])
|
||||
self.write_packet(packet)
|
||||
response = self.read_packet()
|
||||
if response == None or response[0] != 0x00:
|
||||
print("Error receiving erase response, aborting!", file=sys.stderr)
|
||||
return False
|
||||
return True
|
||||
|
||||
def program_flash(self, addr, data):
|
||||
"""Program the MCU's flash memory.
|
||||
|
||||
Write data into flash memory, starting at the given address. The address
|
||||
should be 128 byte aligned.
|
||||
"""
|
||||
|
||||
print("Writing %d bytes..." % len(data), end="")
|
||||
sys.stdout.flush()
|
||||
for i in range(addr, addr+len(data), 128):
|
||||
packet = bytes(3)
|
||||
packet += struct.pack(">H", i)
|
||||
packet += struct.pack(">H", self.PROGRAM_BLOCKSIZE)
|
||||
packet += data[i-addr:i-addr+128]
|
||||
while len(packet) < self.PROGRAM_BLOCKSIZE + 7: packet += b"\x00"
|
||||
csum = sum(packet[7:]) & 0xff
|
||||
self.write_packet(packet)
|
||||
response = self.read_packet()
|
||||
if response == None or response[0] != 0x00:
|
||||
print("Error receiving program response packet, aborting!", file=sys.stderr)
|
||||
return False
|
||||
elif response[1] != csum:
|
||||
print("Wrong checksum in program response (%s, expected %s), aborting!" %
|
||||
(hex(response[1]), hex(csum)), file=sys.stderr)
|
||||
print(".", end="")
|
||||
sys.stdout.flush()
|
||||
print()
|
||||
|
||||
packet = bytes([0x69, 0x00, 0x00, 0x36, 0x01])
|
||||
packet += struct.pack(">H", self.mcu_magic)
|
||||
self.write_packet(packet)
|
||||
response = self.read_packet()
|
||||
if response == None or response[0] != 0x8d:
|
||||
print("Error receiving program finish response packet, aborting!", file=sys.stderr)
|
||||
return False
|
||||
print("Finished writing flash!")
|
||||
|
||||
return True
|
||||
|
||||
def set_option(self, name, value):
|
||||
self.options.set_option(name, value)
|
||||
|
||||
def program_options(self):
|
||||
#self.options.print()
|
||||
print("Setting options...")
|
||||
msr = self.options.get_msr()
|
||||
packet = bytes([0x8d, msr[0], msr[1], msr[2], msr[3],
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
|
||||
|
||||
packet += struct.pack(">I", int(self.mcu_clock_hz))
|
||||
self.write_packet(packet)
|
||||
response = self.read_packet()
|
||||
if response == None or response[0] != 0x50:
|
||||
print("Error receiving set options response packet, aborting!", file=sys.stderr)
|
||||
return False
|
||||
|
||||
print("Target UID: %02x%02x%02x%02x%02x%02x%02x" %
|
||||
(response[18], response[19], response[20], response[21],
|
||||
response[22], response[23], response[24]))
|
||||
|
||||
return True
|
||||
|
||||
def disconnect(self):
|
||||
"""Disconnect from MCU"""
|
||||
|
||||
# reset mcu
|
||||
packet = bytes([0x82])
|
||||
self.write_packet(packet)
|
||||
self.ser.close()
|
||||
print("Disconnected!")
|
||||
|
||||
class StcGal:
|
||||
"""STC ISP flash tool frontend"""
|
||||
|
||||
def __init__(self, opts):
|
||||
self.opts = opts
|
||||
self.protocol = Stc12Protocol(opts.port, opts.handshake, opts.baud)
|
||||
|
||||
def run(self):
|
||||
self.protocol.connect()
|
||||
|
||||
if opts.binary:
|
||||
bindata = opts.binary.read()
|
||||
|
||||
if opts.option:
|
||||
for o in opts.option:
|
||||
k, v = o.split("=", 1)
|
||||
self.protocol.set_option(k, v)
|
||||
|
||||
self.protocol.handshake()
|
||||
self.protocol.erase_flash(len(bindata), 0xf0 * 256)
|
||||
self.protocol.program_flash(0, bindata)
|
||||
self.protocol.program_options()
|
||||
|
||||
self.protocol.disconnect()
|
||||
|
||||
if __name__ == "__main__":
|
||||
# check arguments
|
||||
parser = argparse.ArgumentParser(description="STC10/11/12 series MCU ISP flash tool")
|
||||
parser.add_argument("binary", help="binary file to flash", type=argparse.FileType("rb"), nargs='?')
|
||||
parser.add_argument("-p", "--port", help="serial port device", default="/dev/ttyUSB0")
|
||||
parser.add_argument("-b", "--baud", help="transfer baud rate (default: 19200)", type=int, default=19200)
|
||||
parser.add_argument("-l", "--handshake", help="handshake baud rate (default: 2400)", type=int, default=2400)
|
||||
parser.add_argument("-o", "--option", help="set option (can be used multiple times)", action="append")
|
||||
opts = parser.parse_args()
|
||||
|
||||
# run programmer
|
||||
gal = StcGal(opts)
|
||||
sys.exit(gal.run())
|
Loading…
Reference in New Issue
Block a user