Cannot connect to MCU on SKIPR board

Basic Information:

Printer Model: N/A
MCU / Printerboard: MKS SKIPR v1.0
Host / SBC: MKS SKIPR v1.0
klippy.log

Describe your issue:

I am giving up with stock boards on my Twotrees SK1, which are too unstable, and purchased a MKS SKIPR board instead. In the meantime I installed pretty fresh Armbian, using KIAUH installed moonraker, klipper, fluidd, and other stuff.

Unfortunately I hit an issue uploading klipper firmware to MCU. I pretty much followed build recommendations, and compiled klipper for STM32F407 MCU, 48k bootloader, UART1 on PA10/PA9 communication. To flash the firmware I used this command line:
make serialflash FLASH_DEVICE=/dev/ttyS0
With pressing BOOT button while reset, this command uploads the firmware without any errors.

As per instructions, printer config includes this section

[mcu]
serial: /dev/ttyS0
restart_method: command

Unfortunately klipper can’t connect to the MCU.

mks@mkspi:~$ ~/klippy-env/bin/python ~/klipper/klippy/console.py /dev/ttyS0

  This is a debugging console for the Klipper micro-controller.
  In addition to mcu commands, the following artificial commands are
  available:
    DELAY : Send a command at a clock time (eg, "DELAY 9999 get_uptime")
    FLOOD : Send a command many times (eg, "FLOOD 22 .01 get_uptime")
    SUPPRESS : Suppress a response message (eg, "SUPPRESS analog_in_state 4")
    SET   : Create a local variable (eg, "SET myvar 123.4")
    DUMP  : Dump memory (eg, "DUMP 0x12345678 100 32")
    FILEDUMP : Dump to file (eg, "FILEDUMP data.bin 0x12345678 100 32")
    STATS : Report serial statistics
    LIST  : List available mcu commands, local commands, and local variables
    HELP  : Show this text
  All commands also support evaluation by enclosing an expression in { }.
  For example, "reset_step_clock oid=4 clock={clock + freq}".  In addition
  to user defined variables (via the SET command) the following builtin
  variables may be used in expressions:
    clock : The current mcu clock time (as estimated by the host)
    freq  : The mcu clock frequency

==================== attempting to connect ====================
INFO:root:Starting serial connect
INFO:root:Timeout on connect
ERROR:root:Wait for identify_response
Traceback (most recent call last):
  File "/home/mks/klipper/klippy/serialhdl.py", line 68, in _get_identify_data
    params = self.send_with_response(msg, 'identify_response')
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mks/klipper/klippy/serialhdl.py", line 262, in send_with_response
    return src.get_response([cmd], self.default_cmd_queue)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mks/klipper/klippy/serialhdl.py", line 319, in get_response
    self.serial.raw_send_wait_ack(cmds[-1], minclock, reqclock,
  File "/home/mks/klipper/klippy/serialhdl.py", line 254, in raw_send_wait_ack
    self._error("Serial connection closed")
  File "/home/mks/klipper/klippy/serialhdl.py", line 61, in _error
    raise error(self.warn_prefix + (msg % params))
serialhdl.error: Serial connection closed

I also tried the flashing way suggested by the manufacturer:

  • built the klipper
  • renamed klipper.bin to mks_skipr.bin, and uploaded to a FAT32 SD card
  • insterted the card to the MCU SD Card slot
  • powered on the board, and waited for a few minutes

Unfortunately the firmware did not flash, no files on the SD card updated, or renamed to *.CUR, indicating the firmware flashed successully.

What could be wrong, and how I can upload the firmware to MCU?
I suspect that by using serialflash utility I overwrote the SD-card bootloader. So perhaps I need to flash bootloader first, and only then flash the firmware.

Thank you for being my rubber duck :slight_smile:
I spent 3 hours trying to correctly upload the MCU firmware, and 5 minute after I posted my question I realized what was wrong.

TL/DR: If you are using make serialflash firmware upload method, you should disable bootloader in the menuconfig while building the firmware.

Explanation:
Unlike AVR microcontrollers, in the STM32 world the bootloader is a simple program. It resides in the beginning of the flash memory, and uploads new firmware to the upper addresses. That is why the instruction requests setting a bootloader shift by 48k. In this case lowest 48k are occupied by the bootloader, and the firmware knows that it will work at higher addresses.

make serialflash method flashes whole flash memory, including the part that is usually reserved for the bootloader. So I simply overwrote the bootloader with a firmware, which in fact was written at the beginning of the flash, but thought it works with a 48k shift. Obviously it did not work with such descrepancy. When I recompiled the firmware with no bootloader option (so that firmware starts at the beginning of the flash) everything started working normally.

There is still a problem: I destroyed the bootloader capable of SD card update. It would be nice if someone could point me to this bootloader. Fortunately I do not really need it for future updates, as I always can upload the new firmware using the make serialflash method.

Unfortunately MKS does not offer the original bootloader. You can flash Katapult, which more powerful anyway.
You can use e.g. 16KiB offset and then build Klipper the same way.

Thanks for pointing to katapult. It looks quite interesting solution for USB and CAN. Though I am a bit skeptic using it for UART, as there is no automatic way to enter bootloader. Am I missing something?

In case of built-in STM32 UART bootloader I need to press BOOT and RESET keys to enter bootloader. In case of Katapult I need to press RESET twice. In any case I need to open printer chasis to access buttons. What would be the katapult’s benefit in this case?

Thank you for being my rubber duck again :slight_smile:

flashtool.py utility has a -r command switch, that remotely switches microcontroller to the bootloader mode. I am surprised, there is even a speciall support code in Klipper firmware. So having automatic/remote reboot to bootloader totally satisfy my needs.