serial: Add Fysetc Cheetah board specific reset sequence
Fysetc Cheetah v1.2 boards require a special sequence to reset reliably. This sequence works for me in all cases. Simpler sequences without double reset did not work correctly. This is likely because of a weird stateful circuitry for toggling the bootloader state. Cheetah boards use RTS to configure bootloader triggering. By default, pySerial sets RTS on connect, which unfortunately configures the board to start the bootloader on reset. Add a toggle for the RTS state to allow users to workaround. The RTS state is set before the serial connection is opened, so there are no glitches. Addresses #2026. Signed-off-by: Grigori Goronzy <greg@chown.ath.cx>
This commit is contained in:
parent
5c8d15bbee
commit
0a20430e07
|
@ -288,15 +288,16 @@ pin_map: arduino
|
||||||
# default is to not enable the aliases.
|
# default is to not enable the aliases.
|
||||||
#restart_method:
|
#restart_method:
|
||||||
# This controls the mechanism the host will use to reset the
|
# This controls the mechanism the host will use to reset the
|
||||||
# micro-controller. The choices are 'arduino', 'rpi_usb', and
|
# micro-controller. The choices are 'arduino', 'cheetah', 'rpi_usb',
|
||||||
# 'command'. The 'arduino' method (toggle DTR) is common on Arduino
|
# and 'command'. The 'arduino' method (toggle DTR) is common on
|
||||||
# boards and clones. The 'rpi_usb' method is useful on Raspberry Pi
|
# Arduino boards and clones. The 'cheetah' method is a special
|
||||||
# boards with micro-controllers powered over USB - it briefly
|
# method needed for some Fysetc Cheetah boards. The 'rpi_usb' method
|
||||||
# disables power to all USB ports to accomplish a micro-controller
|
# is useful on Raspberry Pi boards with micro-controllers powered
|
||||||
# reset. The 'command' method involves sending a Klipper command to
|
# over USB - it briefly disables power to all USB ports to
|
||||||
# the micro-controller so that it can reset itself. The default is
|
# accomplish a micro-controller reset. The 'command' method involves
|
||||||
# 'arduino' if the micro-controller communicates over a serial port,
|
# sending a Klipper command to the micro-controller so that it can
|
||||||
# 'command' otherwise.
|
# reset itself. The default is 'arduino' if the micro-controller
|
||||||
|
# communicates over a serial port, 'command' otherwise.
|
||||||
|
|
||||||
# The printer section controls high level printer settings.
|
# The printer section controls high level printer settings.
|
||||||
[printer]
|
[printer]
|
||||||
|
|
|
@ -386,16 +386,22 @@ class MCU:
|
||||||
self._disconnect)
|
self._disconnect)
|
||||||
# Serial port
|
# Serial port
|
||||||
self._serialport = config.get('serial', '/dev/ttyS0')
|
self._serialport = config.get('serial', '/dev/ttyS0')
|
||||||
|
serial_rts = True
|
||||||
|
if config.get('restart_method', None) == "cheetah":
|
||||||
|
# Special case: Cheetah boards require RTS to be deasserted, else
|
||||||
|
# a reset will trigger the built-in bootloader.
|
||||||
|
serial_rts = False
|
||||||
baud = 0
|
baud = 0
|
||||||
if not (self._serialport.startswith("/dev/rpmsg_")
|
if not (self._serialport.startswith("/dev/rpmsg_")
|
||||||
or self._serialport.startswith("/tmp/klipper_host_")):
|
or self._serialport.startswith("/tmp/klipper_host_")):
|
||||||
baud = config.getint('baud', 250000, minval=2400)
|
baud = config.getint('baud', 250000, minval=2400)
|
||||||
self._serial = serialhdl.SerialReader(
|
self._serial = serialhdl.SerialReader(
|
||||||
self._reactor, self._serialport, baud)
|
self._reactor, self._serialport, baud, serial_rts)
|
||||||
# Restarts
|
# Restarts
|
||||||
self._restart_method = 'command'
|
self._restart_method = 'command'
|
||||||
if baud:
|
if baud:
|
||||||
rmethods = {m: m for m in [None, 'arduino', 'command', 'rpi_usb']}
|
rmethods = {m: m for m in [None, 'arduino', 'cheetah', 'command',
|
||||||
|
'rpi_usb']}
|
||||||
self._restart_method = config.getchoice(
|
self._restart_method = config.getchoice(
|
||||||
'restart_method', rmethods, None)
|
'restart_method', rmethods, None)
|
||||||
self._reset_cmd = self._config_reset_cmd = None
|
self._reset_cmd = self._config_reset_cmd = None
|
||||||
|
@ -683,6 +689,10 @@ class MCU:
|
||||||
logging.info("Attempting MCU '%s' reset", self._name)
|
logging.info("Attempting MCU '%s' reset", self._name)
|
||||||
self._disconnect()
|
self._disconnect()
|
||||||
serialhdl.arduino_reset(self._serialport, self._reactor)
|
serialhdl.arduino_reset(self._serialport, self._reactor)
|
||||||
|
def _restart_cheetah(self):
|
||||||
|
logging.info("Attempting MCU '%s' Cheetah-style reset", self._name)
|
||||||
|
self._disconnect()
|
||||||
|
serialhdl.cheetah_reset(self._serialport, self._reactor)
|
||||||
def _restart_via_command(self):
|
def _restart_via_command(self):
|
||||||
if ((self._reset_cmd is None and self._config_reset_cmd is None)
|
if ((self._reset_cmd is None and self._config_reset_cmd is None)
|
||||||
or not self._clocksync.is_active()):
|
or not self._clocksync.is_active()):
|
||||||
|
@ -713,6 +723,8 @@ class MCU:
|
||||||
self._restart_rpi_usb()
|
self._restart_rpi_usb()
|
||||||
elif self._restart_method == 'command':
|
elif self._restart_method == 'command':
|
||||||
self._restart_via_command()
|
self._restart_via_command()
|
||||||
|
elif self._restart_method == 'cheetah':
|
||||||
|
self._restart_cheetah()
|
||||||
else:
|
else:
|
||||||
self._restart_arduino()
|
self._restart_arduino()
|
||||||
# Misc external commands
|
# Misc external commands
|
||||||
|
|
|
@ -13,12 +13,13 @@ class error(Exception):
|
||||||
|
|
||||||
class SerialReader:
|
class SerialReader:
|
||||||
BITS_PER_BYTE = 10.
|
BITS_PER_BYTE = 10.
|
||||||
def __init__(self, reactor, serialport, baud):
|
def __init__(self, reactor, serialport, baud, rts=True):
|
||||||
self.reactor = reactor
|
self.reactor = reactor
|
||||||
self.serialport = serialport
|
self.serialport = serialport
|
||||||
self.baud = baud
|
self.baud = baud
|
||||||
# Serial port
|
# Serial port
|
||||||
self.ser = None
|
self.ser = None
|
||||||
|
self.rts = rts
|
||||||
self.msgparser = msgproto.MessageParser()
|
self.msgparser = msgproto.MessageParser()
|
||||||
# C interface
|
# C interface
|
||||||
self.ffi_main, self.ffi_lib = chelper.get_ffi()
|
self.ffi_main, self.ffi_lib = chelper.get_ffi()
|
||||||
|
@ -85,7 +86,10 @@ class SerialReader:
|
||||||
try:
|
try:
|
||||||
if self.baud:
|
if self.baud:
|
||||||
self.ser = serial.Serial(
|
self.ser = serial.Serial(
|
||||||
self.serialport, self.baud, timeout=0, exclusive=True)
|
baudrate=self.baud, timeout=0, exclusive=True)
|
||||||
|
self.ser.port = self.serialport
|
||||||
|
self.ser.rts = self.rts
|
||||||
|
self.ser.open()
|
||||||
else:
|
else:
|
||||||
self.ser = open(self.serialport, 'rb+')
|
self.ser = open(self.serialport, 'rb+')
|
||||||
except (OSError, IOError, serial.SerialException) as e:
|
except (OSError, IOError, serial.SerialException) as e:
|
||||||
|
@ -266,6 +270,32 @@ def stk500v2_leave(ser, reactor):
|
||||||
logging.debug("Got %s from stk500v2", repr(res))
|
logging.debug("Got %s from stk500v2", repr(res))
|
||||||
ser.baudrate = origbaud
|
ser.baudrate = origbaud
|
||||||
|
|
||||||
|
def cheetah_reset(serialport, reactor):
|
||||||
|
# Fysetc Cheetah v1.2 boards have a weird stateful circuitry for
|
||||||
|
# configuring the bootloader. This sequence takes care of disabling it for
|
||||||
|
# sure.
|
||||||
|
# Open the serial port with RTS asserted
|
||||||
|
ser = serial.Serial(baudrate=2400, timeout=0, exclusive=True)
|
||||||
|
ser.port = serialport
|
||||||
|
ser.rts = True
|
||||||
|
ser.open()
|
||||||
|
ser.read(1)
|
||||||
|
reactor.pause(reactor.monotonic() + 0.100)
|
||||||
|
# Toggle DTR
|
||||||
|
ser.dtr = True
|
||||||
|
reactor.pause(reactor.monotonic() + 0.100)
|
||||||
|
ser.dtr = False
|
||||||
|
# Deassert RTS
|
||||||
|
reactor.pause(reactor.monotonic() + 0.100)
|
||||||
|
ser.rts = False
|
||||||
|
reactor.pause(reactor.monotonic() + 0.100)
|
||||||
|
# Toggle DTR again
|
||||||
|
ser.dtr = True
|
||||||
|
reactor.pause(reactor.monotonic() + 0.100)
|
||||||
|
ser.dtr = False
|
||||||
|
reactor.pause(reactor.monotonic() + 0.100)
|
||||||
|
ser.close()
|
||||||
|
|
||||||
# Attempt an arduino style reset on a serial port
|
# Attempt an arduino style reset on a serial port
|
||||||
def arduino_reset(serialport, reactor):
|
def arduino_reset(serialport, reactor):
|
||||||
# First try opening the port at a different baud
|
# First try opening the port at a different baud
|
||||||
|
|
Loading…
Reference in New Issue