8 Commits

Author SHA1 Message Date
a414bfb864 protocols.py: Increase clock_safety_factor to 2.5
This fixes cp2102 and ch341a baudswitch on mac sierra

Signed-off-by: Andrew 'ncrmnt' Andrianov <andrew@ncrmnt.org>
2017-10-14 21:08:26 +03:00
68d19f7b88 Use calculated delays
Some serial drivers don't handle draining the transmit buffer
correctly. This has been handled with a long delay so far, which might
be problematic. There's a race condition with some protocol versions.

Until STC15, the baud rate switch is initiated with a command sent by
stcgal, which is replied to by the MCU with the new baud rate. So the
switch of the baud rate has to be done after the command has finished
transmission, but before the MCU has started to transmit the response.

This change calculates the minimum delay needed (with some tolerance
added) so that it's unlikely that the baud rate switch will happen
too late.
2017-10-10 22:11:07 +02:00
ebcfeb467c Merge pull request #27 from nekromant/fixes
Implement power-cycling via a custom shell cmd, update models.py
2017-10-09 00:05:55 +02:00
d7e226df6b README.md: Document -r option properly
Signed-off-by: Andrew Andrianov <andrew@ncrmnt.org>
2017-10-08 23:58:31 +03:00
191a580469 protocols: Move device reset logic to a separate method
Signed-off-by: Andrew Andrianov <andrew@ncrmnt.org>
2017-10-08 23:20:17 +03:00
c131a9d901 frontend: Use command instead of cmd in description
Signed-off-by: Andrew Andrianov <andrew@ncrmnt.org>
2017-10-08 23:19:55 +03:00
3f4263e8fe models.py: Add some STC15xxx definitions from stcdude's mcudb
Signed-off-by: Andrew Andrianov <andrew@ncrmnt.org>
2017-10-07 23:30:03 +03:00
ba4faf9c43 Implement power-cycling via custom shell command
Sometimes instead of DTR line some custom way (e.g SoC gpio line)
may be used to reset the device. This commit implements
automated power-cycling using a a custom shell command that can
be specified via -r option

Signed-off-by: Andrew Andrianov <andrew@ncrmnt.org>
2017-10-07 22:41:49 +03:00
4 changed files with 101 additions and 26 deletions

View File

@ -61,7 +61,7 @@ Features
* Set device options
* Read unique device ID (STC 10/11/12/15)
* Trim RC oscillator frequency (STC 15)
* Automatic power-cycling with DTR toggle
* Automatic power-cycling with DTR toggle or a custom shell command
* Automatic UART protocol detection
Installation
@ -96,6 +96,9 @@ positional arguments:
optional arguments:
-h, --help show this help message and exit
-a, --autoreset cycle power automatically by asserting DTR
-r RESETCMD, --resetcmd RESETCMD
Use this shell command for board power-cycling
(instead of DTR assertion)
-P {stc89,stc12a,stc12,stc15a,stc15,auto}, --protocol {stc89,stc12a,stc12,stc15a,stc15,auto}
protocol version
-p PORT, --port PORT serial port device
@ -276,7 +279,22 @@ serial interface to automate this. The DTR signal is asserted for
approximately 500 ms when the autoreset feature is enabled with the
```-a``` flag. This requires external circuitry to actually switch the
power. In some cases, when the microcontroller draws only little power,
it is possible to directly supply power from the DTR signal, however.
it is possible to directly supply power from the DTR signal.
As an alternative to DTR, you can use a custom shell command or an external
script (via -r option) to reset the device. You should specify the command
along with -a option. Do not forget the quotes!
Example:
```
$ ./stcgal.py -P stc15 -a -r "echo 1 > /sys/class/gpio/gpio666/value"
```
or
```
$ ./stcgal.py -P stc15 -a -r "./powercycle.sh"
```
### Exit status

View File

@ -132,8 +132,7 @@ class StcGal:
"""Run programmer, main entry point."""
try:
self.protocol.connect(autoreset=self.opts.autoreset)
self.protocol.connect(autoreset=self.opts.autoreset, resetcmd=self.opts.resetcmd)
if self.opts.protocol == "auto":
if not self.protocol.protocol_name:
raise StcProtocolException("cannot detect protocol")
@ -203,6 +202,7 @@ def cli():
parser.add_argument("code_image", help="code segment file to flash (BIN/HEX)", type=argparse.FileType("rb"), nargs='?')
parser.add_argument("eeprom_image", help="eeprom segment file to flash (BIN/HEX)", type=argparse.FileType("rb"), nargs='?')
parser.add_argument("-a", "--autoreset", help="cycle power automatically by asserting DTR", action="store_true")
parser.add_argument("-r", "--resetcmd", help="Use this shell command for board power-cycling (instead of DTR assertion)", action="store")
parser.add_argument("-P", "--protocol", help="protocol version (default: auto)", choices=["stc89", "stc12a", "stc12b", "stc12", "stc15a", "stc15", "usb15", "auto"], default="auto")
parser.add_argument("-p", "--port", help="serial port device", default="/dev/ttyUSB0")
parser.add_argument("-b", "--baud", help="transfer baud rate (default: 19200)", type=BaudType(), default=19200)

View File

@ -973,6 +973,46 @@ class MCUModelDatabase:
MCUModel(name='STC90LE513AD', magic=0xf18d, total=65536, code=53248, eeprom=10240),
MCUModel(name='STC90LE514AD', magic=0xf18e, total=65536, code=57344, eeprom=6144),
MCUModel(name='STC90LE516AD', magic=0xf190, total=65536, code=63488, eeprom=0),
# Warning, these definitions lack a valid eeprom size.
MCUModel(name='STC15F04AD', magic=0xd444, total=4096, code=4096, eeprom=0),
MCUModel(name='STC15F06AD', magic=0xd446, total=6144, code=6144, eeprom=0),
MCUModel(name='STC15F08AD', magic=0xd448, total=8192, code=8192, eeprom=0),
MCUModel(name='STC15F10AD', magic=0xd44a, total=10240, code=10240, eeprom=0),
MCUModel(name='STC15F12AD', magic=0xd44c, total=12288, code=12288, eeprom=0),
MCUModel(name='STC15F04CCP', magic=0xd434, total=4096, code=4096, eeprom=0),
MCUModel(name='STC15F06CCP', magic=0xd436, total=6144, code=6144, eeprom=0),
MCUModel(name='STC15F08CCP', magic=0xd438, total=8192, code=8192, eeprom=0),
MCUModel(name='STC15F10CCP', magic=0xd43a, total=10240, code=10240, eeprom=0),
MCUModel(name='STC15F12CCP', magic=0xd43c, total=12288, code=12288, eeprom=0),
MCUModel(name='STC15F04', magic=0xd404, total=4096, code=4096, eeprom=0),
MCUModel(name='STC15F06', magic=0xd406, total=6144, code=6144, eeprom=0),
MCUModel(name='STC15F08', magic=0xd408, total=8192, code=8192, eeprom=0),
MCUModel(name='STC15F10', magic=0xd40a, total=10240, code=10240, eeprom=0),
MCUModel(name='STC15F12', magic=0xd40c, total=12288, code=12288, eeprom=0),
MCUModel(name='IAP15F08AD', magic=0xd458, total=8192, code=8192, eeprom=0),
MCUModel(name='IAP15F10AD', magic=0xd45a, total=10240, code=10240, eeprom=0),
MCUModel(name='IAP15F12AD', magic=0xd45c, total=12288, code=12288, eeprom=0),
MCUModel(name='IAP15F14AD', magic=0xd45e, total=14336, code=14336, eeprom=0),
MCUModel(name='STC15L04AD', magic=0xd4c4, total=4096, code=4096, eeprom=0),
MCUModel(name='STC15L06AD', magic=0xd4c6, total=6144, code=6144, eeprom=0),
MCUModel(name='STC15L08AD', magic=0xd4c8, total=8192, code=8192, eeprom=0),
MCUModel(name='STC15L10AD', magic=0xd4ca, total=10240, code=10240, eeprom=0),
MCUModel(name='STC15L12AD', magic=0xd4cc, total=12288, code=12288, eeprom=0),
MCUModel(name='STC15L04CCP', magic=0xd4b4, total=4096, code=4096, eeprom=0),
MCUModel(name='STC15L06CCP', magic=0xd4b6, total=6144, code=6144, eeprom=0),
MCUModel(name='STC15L08CCP', magic=0xd4b8, total=8192, code=8192, eeprom=0),
MCUModel(name='STC15L10CCP', magic=0xd4ba, total=10240, code=10240, eeprom=0),
MCUModel(name='STC15L12CCP', magic=0xd4bc, total=12288, code=12288, eeprom=0),
MCUModel(name='STC15L04', magic=0xd484, total=4096, code=4096, eeprom=0),
MCUModel(name='STC15L06', magic=0xd486, total=6144, code=6144, eeprom=0),
MCUModel(name='STC15L08', magic=0xd488, total=8192, code=8192, eeprom=0),
MCUModel(name='STC15L10', magic=0xd48a, total=10240, code=10240, eeprom=0),
MCUModel(name='STC15L12', magic=0xd48c, total=12288, code=12288, eeprom=0),
MCUModel(name='IAP15L08AD', magic=0xd4d8, total=8192, code=8192, eeprom=0),
MCUModel(name='IAP15L10AD', magic=0xd4da, total=10240, code=10240, eeprom=0),
MCUModel(name='IAP15L12AD', magic=0xd4dc, total=12288, code=12288, eeprom=0),
MCUModel(name='IAP15L14AD', magic=0xd4de, total=14336, code=14336, eeprom=0),
)
@classmethod
@ -988,6 +1028,3 @@ class MCUModelDatabase:
print(" Magic: %02X%02X" % (model.magic >> 8, model.magic & 0xff))
print(" Code flash: %.1f KB" % (model.code / 1024.0))
print(" EEPROM flash: %.1f KB" % (model.eeprom / 1024.0))

View File

@ -238,10 +238,39 @@ class StcBaseProtocol:
return iap_wait
def delay_safely_written(self, length):
"""
Delay until data has been safely written and sent to device.
Some buggy serial drivers don't implement tcdrain/flush correctly.
That is, they wait until all data has been written to USB, but they
do not wait until the data has actually finished transmission.
Add additional delay to work around.
"""
bit_time = 1.0 / self.ser.baudrate
byte_time = bit_time * 11.0 # start, 8 data bits, stop, parity
clock_safety_factor = 2.5 # additional delay in case clock is slow
time.sleep(byte_time * length * clock_safety_factor)
def set_option(self, name, value):
self.options.set_option(name, value)
def connect(self, autoreset=False):
def reset_device(self, resetcmd=False):
if not resetcmd:
print("Cycling power: ", end="")
sys.stdout.flush()
self.ser.setDTR(True)
time.sleep(0.5)
self.ser.setDTR(False)
print("done")
else:
print("Cycling power via shell cmd: " + resetcmd)
os.system(resetcmd)
print("Waiting for MCU: ", end="")
sys.stdout.flush()
def connect(self, autoreset=False, resetcmd=False):
"""Connect to MCU and initialize communication.
Set up serial port, send sync sequence and get part info.
@ -260,14 +289,7 @@ class StcBaseProtocol:
self.ser.flushInput()
if autoreset:
print("Cycling power: ", end="")
sys.stdout.flush()
self.ser.setDTR(True)
time.sleep(0.5)
self.ser.setDTR(False)
print("done")
print("Waiting for MCU: ", end="")
sys.stdout.flush()
self.reset_device(resetcmd)
else:
print("Waiting for MCU, please cycle power: ", end="")
sys.stdout.flush()
@ -440,7 +462,7 @@ class Stc89Protocol(StcBaseProtocol):
packet += struct.pack(">H", brt)
packet += bytes([0xff - (brt >> 8), brt_csum, delay, iap])
self.write_packet(packet)
time.sleep(0.2)
self.delay_safely_written(len(packet))
self.ser.baudrate = self.baud_transfer
response = self.read_packet()
self.ser.baudrate = self.baud_handshake
@ -454,7 +476,7 @@ class Stc89Protocol(StcBaseProtocol):
packet += struct.pack(">H", brt)
packet += bytes([0xff - (brt >> 8), brt_csum, delay])
self.write_packet(packet)
time.sleep(0.2)
self.delay_safely_written(len(packet))
self.ser.baudrate = self.baud_transfer
response = self.read_packet()
if response[0] != 0x8e:
@ -630,7 +652,7 @@ class Stc12AProtocol(Stc12AOptionsMixIn, Stc89Protocol):
sys.stdout.flush()
packet = bytes([0x8f, 0xc0, brt, 0x3f, brt_csum, delay, iap])
self.write_packet(packet)
time.sleep(0.2)
self.delay_safely_written(len(packet))
self.ser.baudrate = self.baud_transfer
response = self.read_packet()
self.ser.baudrate = self.baud_handshake
@ -642,7 +664,7 @@ class Stc12AProtocol(Stc12AOptionsMixIn, Stc89Protocol):
sys.stdout.flush()
packet = bytes([0x8e, 0xc0, brt, 0x3f, brt_csum, delay])
self.write_packet(packet)
time.sleep(0.2)
self.delay_safely_written(len(packet))
self.ser.baudrate = self.baud_transfer
response = self.read_packet()
if response[0] != 0x8e:
@ -827,7 +849,7 @@ class Stc12BaseProtocol(StcBaseProtocol):
sys.stdout.flush()
packet = bytes([0x8f, 0xc0, brt, 0x3f, brt_csum, delay, iap])
self.write_packet(packet)
time.sleep(0.2)
self.delay_safely_written(len(packet))
self.ser.baudrate = self.baud_transfer
response = self.read_packet()
self.ser.baudrate = self.baud_handshake
@ -839,7 +861,7 @@ class Stc12BaseProtocol(StcBaseProtocol):
sys.stdout.flush()
packet = bytes([0x8e, 0xc0, brt, 0x3f, brt_csum, delay])
self.write_packet(packet)
time.sleep(0.2)
self.delay_safely_written(len(packet))
self.ser.baudrate = self.baud_transfer
response = self.read_packet()
if response[0] != 0x84:
@ -1113,7 +1135,7 @@ class Stc15AProtocol(Stc12Protocol):
packet += struct.pack(">B", 230400 // self.baud_transfer)
packet += bytes([0xa1, 0x64, 0xb8, 0x00, iap_wait, 0x20, 0xff, 0x00])
self.write_packet(packet)
time.sleep(0.2)
self.delay_safely_written(len(packet))
self.ser.baudrate = self.baud_transfer
response = self.read_packet()
if response[0] != 0x84:
@ -1299,7 +1321,6 @@ class Stc15Protocol(Stc15AProtocol):
response = self.read_packet()
if response[0] != 0x01:
raise StcProtocolException("incorrect magic in handshake packet")
time.sleep(0.2)
self.ser.baudrate = self.baud_transfer
def switch_baud_ext(self):
@ -1316,7 +1337,6 @@ class Stc15Protocol(Stc15AProtocol):
response = self.read_packet()
if response[0] != 0x01:
raise StcProtocolException("incorrect magic in handshake packet")
time.sleep(0.2)
self.ser.baudrate = self.baud_transfer
# for switching back to RC, program factory values
@ -1504,7 +1524,7 @@ class StcUsb15Protocol(Stc15Protocol):
host2dev = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_RECIPIENT_DEVICE | usb.util.CTRL_OUT
self.dev.ctrl_transfer(host2dev, request, value, index, chunks)
def connect(self, autoreset=False):
def connect(self, autoreset=False, resetcmd=False):
"""Connect to USB device and read info packet"""
# USB support is optional. Provide an error if pyusb is not available.