Klipper support on stm32f103 over usb

Thanks for doing amazing work on klipper.

I’ve been trying to make klipper work on bluepill boards (stm32f103c8t6) and there is no luck in this regard

I built the firmware with following config and installed on bluepill using st-link.

stm32f1 enumerates over usb but it does not give a response to the commands coming from klippy.

$ ~/klippy-env/bin/python ./klippy/console.py -b 115200  /dev/ttyACM0 
..
..
==================== 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/ami/klipper/klippy/serialhdl.py", line 75, in _get_identify_data
    params = self.send_with_response(msg, 'identify_response')
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ami/klipper/klippy/serialhdl.py", line 271, in send_with_response
    return src.get_response([cmd], self.default_cmd_queue)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ami/klipper/klippy/serialhdl.py", line 331, in get_response
    self.serial.raw_send_wait_ack(cmds[-1], minclock, reqclock,
  File "/home/ami/klipper/klippy/serialhdl.py", line 263, in raw_send_wait_ack
    self._error("Serial connection closed")
  File "/home/ami/klipper/klippy/serialhdl.py", line 68, in _error
    raise error(self.warn_prefix + (msg % params))
serialhdl.error: Serial connection closed

[Oct23 12:18] usb 3-3.3.1: new full-speed USB device number 112 using xhci_hcd
[  +0.099155] usb 3-3.3.1: New USB device found, idVendor=1d50, idProduct=614e, bcdDevice= 1.00
[  +0.000005] usb 3-3.3.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  +0.000001] usb 3-3.3.1: Product: stm32f103xe
[  +0.000001] usb 3-3.3.1: Manufacturer: Klipper
[  +0.000001] usb 3-3.3.1: SerialNumber: B55B5A1A000000007A9EEE01
[  +0.008449] cdc_acm 3-3.3.1:1.0: ttyACM0: USB ACM device


I debugged a bit and found following things in command.c



// Find the next complete message block
int_fast8_t
command_find_block(uint8_t *buf, uint_fast8_t buf_len, uint_fast8_t *pop_count)
{
    static uint8_t sync_state;
    if (buf_len && sync_state & CF_NEED_SYNC)
        goto need_sync;
    if (buf_len < MESSAGE_MIN)
        goto need_more_data;
    uint_fast8_t msglen = buf[MESSAGE_POS_LEN];
    if (msglen < MESSAGE_MIN || msglen > MESSAGE_MAX)
        goto error;
    uint_fast8_t msgseq = buf[MESSAGE_POS_SEQ];
    if ((msgseq & ~MESSAGE_SEQ_MASK) != MESSAGE_DEST)
        goto error;
    if (buf_len < msglen)
        goto need_more_data;
    if (buf[msglen-MESSAGE_TRAILER_SYNC] != MESSAGE_SYNC)
        goto error;
    uint16_t msgcrc = ((buf[msglen-MESSAGE_TRAILER_CRC] << 8)
                       | buf[msglen-MESSAGE_TRAILER_CRC+1]);
    uint16_t crc = crc16_ccitt(buf, msglen-MESSAGE_TRAILER_SIZE);
    if (crc != msgcrc)
        goto error;
    sync_state &= ~CF_NEED_VALID;
    *pop_count = msglen;
    // Check sequence number
    if (msgseq != next_sequence) {
        // Lost message - discard messages until it is retransmitted
        goto nak;
    }
    next_sequence = ((msgseq + 1) & MESSAGE_SEQ_MASK) | MESSAGE_DEST;
    return 1;



if (msgseq != next_sequence) {
        // Lost message - discard messages until it is retransmitted
//<---- this is where it fails         
goto nak;
}

I’ve tried with different cables and got the same issue. I wonder if it’s a known issue.

Some additional information is required:

  1. Could you include your klippy.log as requested?
  2. When you say the board “enumerated”, what do you mean?
  3. Did you look for the serial ID using ls /dev/serial/by-d? If you did, what value did you get?
  4. What is your host? How did you load Klipper onto it?
  5. You might want to rebuild with “Enable extra low-level configuration options” selected

thank you.

  1. attached the log:

    klippy.log (28.4 KB)

  2. yes, i meant usb enumeration.

    [  +0.000005] usb 3-3.3.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  +0.000002] usb 3-3.3.1: Product: stm32f103xe
[  +0.000001] usb 3-3.3.1: Manufacturer: Klipper
[  +0.000001] usb 3-3.3.1: SerialNumber: B55B5A1A000000007A9EEE01
[  +0.008707] cdc_acm 3-3.3.1:1.0: ttyACM0: USB ACM device

:~/printer_data/logs$ ls /dev/serial/by-id/
usb-Klipper_stm32f103xe_B55B5A1A000000007A9EEE01-if00

  1. running ubuntu 24.04 on an intel machine.
    $ uname -r
    6.14.0-33-generic
  2. I’ve tried with “Enable extra low-level configuration options” and many combinations, but it did not work.

You didn’t answer my question regarding how you installed Klipper. This is important because…

Looking at your klippy.log, I see that you have a “dirty” version of Moonraker:

webhooks client 137019292383712: Client info {'program': 'Moonraker', 'version': 'v0.9.3-122-g3eb575d-dirty'}

You’re going to have to get a clean version of Moonraker before we can help you.


One question; you have a very involved printer.cfg - why are you using that? You have an absolutely minimal controller board and your printer.cfg has a ton of macros, three TMC2209s, BLTouch, etc. I don’t know if that’s the cause of your problems (let’s get a clean version of Moonraker first) but it definitely makes it more difficult to debug the connection.

Could I suggest, once you’ve fixed the Moonraker issue, use the default printer.cfg, which for your Blue Pill board would be:

[mcu]
serial = /dev/serial/by-id/usb-Klipper_stm32f103xe_B55B5A1A000000007A9EEE01-if00

[virtual_sdcard]
path = /home/shido/printer_data/gcodes
on_error_gcode = CANCEL_PRINT

[printer]
kinematics = none
max_velocity = 1000
max_accel = 1000

thank you! I used kiauh for installation. The changes I did in moonmaker was into installation script.

diff --git a/scripts/install-moonraker.sh b/scripts/install-moonraker.sh
index 6df1612..62c455d 100755
--- a/scripts/install-moonraker.sh
+++ b/scripts/install-moonraker.sh
@@ -216,7 +216,7 @@ class SysDepsParser:
 # *** SYSTEM DEPENDENCIES START ***
 system_deps = {
     "debian": [
-        "python3-virtualenv", "python3-dev", "libopenjp2-7", "libsodium-dev",
+        "python3-virtualenv", "libpython3-dev", "libopenjp2-7", "libsodium-dev",

I was using the printer.cfg of my ender 3v3 se, which runs klipper and the host is RPI3.

Currently, I am out of station and don’t have access to the printer. I brought st-link, bluepill board and mpu-6050 and I am currently experimenting with input shaping. :slight_smile: so thought of trying out bluepill to talk to mpu-6050 over usb. I am surprised why it’s not working and while debugging found out that the sequence number does not match up in command_find_block() in command.c

if (msgseq != next_sequence) {
        // Lost message - discard messages until it is retransmitted
//<---- this is where it fails         
goto nak;
}

Cleaned the moonraker as you suggested and using minimal printer.cfg.

attached the klippy.log.

klippy.log (32.0 KB)

Is this the schematic of the Blue Pill that you’re using:

If it is, please rebuild with the “Set Pins to Output Option” with the value !PC13

I believe what you’re looking for is:

This will turn on D2 (on the schematic) to help verify that the Klipper firmware is running.

Now, you still haven’t explained how you installed Klipper on your PC. I want to rule out that there is an error in the installation.

Thanks. I’ve used kiauh to install klipper on my laptop.

I will use your suggestions and try out but I did try using gpio_out_setup(GPIO(‘C’, 13), 0) to debug the firmware code and onboard led was switched on. This is how I came to conclusion which i mentioned in my first post.

My laptop has only USB-C ports and I am using a usb-c hub which has other peripherals (ethernet, hdmi) along with usb2.0 ports.

I wonder if the usb packets sequence is getting messed up because of the use of usb hub.

Probably a bug in cdc_acm kernel driver?

You could probably try disconnecting the other peripherals from the USB hub so the only thing connected to the hub is the board.

Those peripherals are inbuilt into this hub.

I’ve used this hub to flash imx93 based boards over usb. Never faced any issues.

You did this with the STLink? That should just show you have a connection to the MCU, not that a) the firmware is actually loaded correctly or b) that it is actually running.

Chances are it’s not the issue but it takes a few seconds to test out.


I don’t think that’s very likely but it’s worth eliminating the hub and try having a more direct USB connection to the Blue Pill.

Why don’t you get a USB C to USB A adapter? Here is what you can get from Amazon, but I can get them at a local dollar store for about $3:

Or, how about a USB C to Micro USB Cable so you can plug directly into your laptop:

Like, explicitly turning on the LED in your Klipper firmware, this will eliminate another variable.

I’ve added the line gpio_out_setup(GPIO(‘C’, 13), 0) into klipper firmware code to debug.

I used !PC13 and flashed the new firmware, and the onboard led is switched on which confirms that klipper firmware is running on the board.

While debugging, I found out that, klipper/src/command.c at master · Klipper3d/klipper · GitHub is where the problem happens.

 // Check sequence number
    if (msgseq != next_sequence) {
        // Lost message - discard messages until it is retransmitted
        goto nak;
    }

all received packets are discarded due to mismatch in seq number.

I bought a USB C to USB Adapter,Type C to USB Adapter from a local shop and tried with it and got the same problem.

Do you have a stm32f103 bluepill and could you please try it out at your end?

It’s definitely the klipper firmware or klippy issue.

I do have a couple and I’ll try out firmware tomorrow. I have an STLink and I’ll use STMCubeProgrammer to load the firmware. This is what you are using, correct?

I think it’s too early to make that conclusion - when I do my testing, I’ll use a Raspberry Pi 4 as the host and see what kind of results I get.

I’m always suspicious of using a PC as a Klipper host instead of an SBC because there’s a lot more going on in the background that can affect timing. You indicated that you’re running Ubuntu; If you take a look at people who have successfully used PCs as Klipper hosts, they generally run a minimal Linux distribution like Mint.

1 Like

Thank you so much!

I am using st-flash to flash the firmware.

st-flash write klipper.bin 0x08000000

but STMCubeProgrammer will work too. I use STMCubeProgrammer when there is a problem, generally, related to RDP register.

2 Likes

Finally, I could solve this problem. I used wireshark to debug the packets and it is the double buffer implementation which actually cause the problem. Thank you all for your help.

This allows me to experiment more with klipper and understand in detail.

This is the patch, which made things work!

:~/klipper$ git diff 
diff --git a/src/stm32/usbfs.c b/src/stm32/usbfs.c
index 5385c956..7a7838e0 100644
--- a/src/stm32/usbfs.c
+++ b/src/stm32/usbfs.c
@@ -251,29 +251,12 @@ usb_send_bulk_in(void *data, uint_fast8_t len)
         // No buffer space available
         return -1;
     uint32_t ep = USB_CDC_EP_BULK_IN;
-    uint32_t bipp = bulk_in_push_pos, bufnum = bipp & 1;
-    bulk_in_push_pos = bipp ^ 1;
+    uint32_t  bufnum = 0;
     btable_write_packet(ep, bufnum, data, len);
-    writel(&bulk_in_pop_flag, USB_EP_DTOG_RX);
-
-    // Check if hardware needs to be notified
     uint32_t epr = USB_EPR[ep];
-    if (epr_is_dbuf_blocking(epr) && readl(&bulk_in_pop_flag)) {
-        writel(&bulk_in_pop_flag, 0);
-        if (unlikely(bipp & BI_START)) {
-            // Two packets are always sent when starting in double
-            // buffering mode, so wait for second packet before starting.
-            if (bipp == (BI_START | 1)) {
-                bulk_in_push_pos = 0;
-                writel(&bulk_in_pop_flag, USB_EP_KIND); // Dummy flag
-                USB_EPR[ep] = calc_epr_bits(epr, USB_EPTX_STAT
-                                            , USB_EP_TX_VALID);
-            }
-        } else {
-            USB_EPR[ep] = calc_epr_bits(epr, 0, 0) | USB_EP_DTOG_RX;
-        }
-    }
-
+    USB_EPR[ep] = calc_epr_bits(epr, USB_EPTX_STAT, USB_EP_TX_VALID);
+    writel(&bulk_in_pop_flag, USB_EP_DTOG_RX);
+    
     return len;
 }
 
@@ -362,7 +345,7 @@ usb_reset(void)
     bulk_out_push_flag = USB_EP_DTOG_TX;
 
     ep = USB_CDC_EP_BULK_IN;
-    USB_EPR[ep] = (USB_CDC_EP_BULK_IN | USB_EP_BULK | USB_EP_KIND
+    USB_EPR[ep] = (USB_CDC_EP_BULK_IN | USB_EP_BULK //| USB_EP_KIND
                    | USB_EP_TX_NAK);
     bulk_in_pop_flag = USB_EP_DTOG_RX;

klipper log:

tats 29213.0: gcodein=0 mcu: mcu_awake=0.000 mcu_task_avg=0.000000 mcu_task_stddev=0.000000 bytes_write=869 bytes_read=4841 bytes_retransmit=9 bytes_invalid=0 send_seq=115 receive_seq=115 retransmit_seq=2 srtt=0.000 rttvar=0.000 rto=0.025 ready_bytes=0 upcoming_bytes=0 freq=72003523 print_time=7.186 buffer_time=0.556 print_stall=0 sysload=1.01 cputime=1.352 memavail=23352320
webhooks client 138866297416752: Disconnected
Restarting printer
Start printer at Fri Oct 24 19:55:15 2025 (1761315915.2 29214.7)
===== Config file =====
[mcu]
serial = /dev/serial/by-id/usb-Klipper_stm32f103xe_B55B5A1A000000007A9EEE01-if00

[virtual_sdcard]
path = /home/shido/printer_data/gcodes
on_error_gcode = CANCEL_PRINT

[printer]
kinematics = none
max_velocity = 1000
max_accel = 1000
=======================
mcu 'mcu': Starting serial connect
webhooks client 138866307380240: New connection
webhooks client 138866307380240: Client info {'program': 'Moonraker', 'version': 'v0.9.3-123-g8426f41'}
Loaded MCU 'mcu' 132 commands (v0.13.0-373-g6465921a-dirty-20251024_195450-CP-IN-7ZMK5M3 / gcc: (15:13.2.rel1-2) 13.2.1 20231009 binutils: (2.42-1ubuntu1+23) 2.42)
MCU 'mcu' config: ADC_MAX=4095 BUS_PINS_i2c1=PB6,PB7 BUS_PINS_i2c1a=PB8,PB9 BUS_PINS_i2c2=PB10,PB11 BUS_PINS_spi1=PA6,PA7,PA5 BUS_PINS_spi1_PA6_PA7_PA5=PA6,PA7,PA5 BUS_PINS_spi1_PB4_PB5_PB3=PB4,PB5,PB3 BUS_PINS_spi1a=PB4,PB5,PB3 BUS_PINS_spi2=PB14,PB15,PB13 BUS_PINS_spi2_PB14_PB15_PB13=PB14,PB15,PB13 BUS_PINS_spi3=PB4,PB5,PB3 BUS_PINS_spi3_PB4_PB5_PB3=PB4,PB5,PB3 CLOCK_FREQ=72000000 MCU=stm32f103xe PWM_MAX=257 RESERVE_PINS_USB=PA11,PA12 STATS_SUMSQ_BASE=256 STEPPER_OPTIMIZED_EDGE=9 STEPPER_STEP_BOTH_EDGE=1
Configured MCU 'mcu' (1024 moves)
Stats 29215.3: gcodein=0 mcu: mcu_awake=0.000 mcu_task_avg=0.000000 mcu_task_stddev=0.000000 bytes_write=854 bytes_read=4815 bytes_retransmit=9 bytes_invalid=0 send_seq=101 receive_seq=101 retransmit_seq=2 srtt=0.000 rttvar=0.000 rto=0.025 ready_bytes=0 upcoming_bytes=0 freq=72005056 print_time=0.000 buffer_time=0.000 print_stall=0 sysload=1.01 cputime=1.384 memavail=23358492
webhooks: registering remote method 'shutdown_machine' for connection id: 138866307380240
webhooks: registering remote method 'reboot_machine' for connection id: 138866307380240
webhooks: registering remote method 'pause_job_queue' for connection id: 138866307380240
webhooks: registering remote method 'start_job_queue' for connection id: 138866307380240

Hey @ami

I made up an ST-Link 2 cable to interface with the Blue Pill board and built the firmware for the STMF103 using this configuration:

I ended up with the same error you have been flagging.

I then modified ~/klipper/src/stm32/usbfs.c and, rebuilt the firmware, flashed it into the Blue Pill board and I got a connection.

Now, to check it out the quality of the connection, I added a temperature readout which gave consistently negative temperatures for the MCU.

To see if the MCU was actually running and could work with Klipper, I added a macro to allow me to turn on and off the status LED (at PC13) which worked without issues. What was interesting was that when Klipper restarted, the MCU temperature issue went away and the macro allows me to turn on and off the status LED.

Here’s the printer.cfg that I’m using:

[include mainsail.cfg]

[mcu]
serial: /dev/serial/by-id/usb-Klipper_stm32f103xe_B55B5A1A00000000C8E4F201-if00
[temperature_sensor mcu_temp]
sensor_type: temperature_mcu

[virtual_sdcard]
path: /home/biqu/printer_data/gcodes
on_error_gcode: CANCEL_PRINT

[printer]
kinematics: none
max_velocity: 1000
max_accel: 1000

[temperature_sensor raspberry_pi]
sensor_type: temperature_host
min_temp: 10
max_temp: 100

[output_pin status]
pin: PC13

[gcode_macro setstatus] 
gcode:
    {% set value = params.VALUE|int %}
    {% if 0 == value %} # All Off
        SET_PIN PIN=status VALUE={1}
    {% else %}
        SET_PIN PIN=status VALUE={0}
    {% endif %}

Here is my klippy.log: klippy.log (191.3 KB) - you’ll see that the Klipper firmware is marked as “dirty”, which is expected.

Nice patch - how did you come up with it?

1 Like

Can you inspect your “blue pill board” to check if it is an authentic stm32f103 chip? There have been a couple of sporadic reports of stm32 clones that do not correctly implement the usbfs double buffering system.

Cheers,
-Kevin

The one I have on my Blue Pill appears to be “authentic”.

What should I be looking for?

EDIT:

Sorry, I should also point out that STMCubeProgrammer using ST-Link 2 connected to my Blue Pill recognizes the chip as you can see in the Target Information" box in bottom right below:

Ah, I didn’t realize you were also having the same issue. Was this a recent purchase or have you had this blue pill board for a long time?

Alas, I don’t know how one can spot a clone chip if they’ve also manipulated the chip markings. If you do a web search though, I’m sure you’ll find lots of reports of fake stm32 chips on the blue pill boards.

A very large number of stm32f103 chips run Klipper with the current USB double buffering support, so it would be surprising if authentic stm32f103 chips stopped working with it.

Cheers,
-Kevin

I bought a couple from Amazon on December 27th, 2024. So there’s no provenance for the MCU’s on these boards. I got them to evaluate the STM32F103 against the STM32F070Fx6 - the big drawback to the STM32F103 was that it didn’t have a USB interface for DFU Mode.

Now, as I remember (and could be wrong), I did get Klipper running on this board at that time. I guess you could see if there has been any changes to usbfs.c since then to see if that was possible. Again, maybe I didn’t, but I do know I programmed them with custom C code using STMCubeProgrammer and ST-Link 2 - that was discussed here in this forum.

Let me know if there’s anything you think I should do to more definitely determine the chip’s authenticity.