Keyboard stuck in Bootloader mode

Hello there!
There already are plenty of topics asking for help with non-functional keyboard, but can’t seem to find neither any solutions in them, nor technical details beyond reseating the board, reflashing th SD card, turning it off and then on, and so forth.
That’s why I’m creating another one.
I have been affected by this problem too, at first it was intermittent (sometimes working, sometimes not), then it became kind of permanent and I decided to investigate it further.

So here’s what I tried:

  1. Took it out of the case and connected it via micro-usb cable to my computer.
  2. The keyboard registered as an STM32duino DFU device and the green LED (D1) started blinking.
  3. I’ve tried various methods of reflashing the firmware, namely, using the provided keyboard flashing utilities, both the old version (0.1) and the rewritten version (0.3), also I’ve built foriequal0’s firmware myself and flashed it directly via dfu-tuil.
  4. The result was always the same: after flashing the keyboard began to work (I could type and use the trackball on my computer), but if I were to reconnect it, it went back to the bootloader mode and the LED began to flash again.
  5. I tried it in my DevTerm as well, and could see the LED flashing the same way.
  6. I checked the electrical connections to SW1 and BOOT0 pin and ensured that is was always pulled low, so no problems there.

All this said, there are two possibilities that I’m considering:

  1. The microcontroller is somehow defective (and it’s not a proper STM32 on my keyboard, rather some CKS-branded clone)
  2. I’m missing something in the flashing procedure.

So I am kindly asking the DevTerm developers: Please, please, give me some hints. I’ve got some programming and electronics skills to successfully debug this thing, but some insight from you might make it much quicker.
For now, I’m leaning towards version 1 and inclined just to replace the microcontroller with an STM32 one.
I like DevTerm’s design and idea, but this problem seem to affect multiple users and renders it utterly unusable. Let’s come up with a reliable solution together.

In order to check whether the firmware is written to the internal flash correctly, I read it back from the micro and compared against the file I was writing. They were identical.
The same fault in another user’s DevTerm.

1 Like

Try comment out Line 47 in the firmware:

I also had this problem during my development of custom keyboard fw.
It would get stuck in the loop and the host cannot enumerate the device.

My first workaround was to comment out L47.
Later on I developed a theory (which seems correct) that while(!USBComposite) is too busy and would block the usb interrupts.
This worked far more reliably:

1 Like

I have had the keyboard lockup while still in use and reseating it didn’t do the trick. I had to plug in a full size keyboard and shut everything down to get it running again.

It sometimes enumerates as a completely different device. I am assuming that Leaf Labs is the DFU mode enumeration? The first section is how it enumerated after reseating, the second plugged in using a USB cable:

[ 2577.678093] usb 5-1.4: new full-speed USB device number 13 using ehci-platform
[ 2577.787888] usb 5-1.4: New USB device found, idVendor=1eaf, idProduct=0003, bcdDevice= 2.01
[ 2577.787919] usb 5-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 2577.787937] usb 5-1.4: Product: Maple 003
[ 2577.787954] usb 5-1.4: Manufacturer: LeafLabs
[ 2577.787970] usb 5-1.4: SerialNumber: LLM 003
[ 2578.735633] usb 5-1.4: USB disconnect, device number 13
[ 2578.958128] usb 5-1.4: new full-speed USB device number 14 using ehci-platform
[ 2579.069130] usb 5-1.4: New USB device found, idVendor=1eaf, idProduct=0024, bcdDevice= 2.00
[ 2579.069158] usb 5-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 2579.069177] usb 5-1.4: Product: DevTerm
[ 2579.069193] usb 5-1.4: Manufacturer: ClockworkPI
[ 2579.069210] usb 5-1.4: SerialNumber: 20210531
[ 2579.075895] input: ClockworkPI DevTerm Consumer Control as /devices/platform/fe380000.usb/usb5/5-1/5-1.4/5-1.4:1.0/0003:1EAF:0024.000E/input/input24
[ 2579.134963] input: ClockworkPI DevTerm Keyboard as /devices/platform/fe380000.usb/usb5/5-1/5-1.4/5-1.4:1.0/0003:1EAF:0024.000E/input/input25
[ 2579.136954] input: ClockworkPI DevTerm as /devices/platform/fe380000.usb/usb5/5-1/5-1.4/5-1.4:1.0/0003:1EAF:0024.000E/input/input26
[ 2579.137915] input: ClockworkPI DevTerm Mouse as /devices/platform/fe380000.usb/usb5/5-1/5-1.4/5-1.4:1.0/0003:1EAF:0024.000E/input/input27
[ 2579.139075] hid-generic 0003:1EAF:0024.000E: input,hidraw2: USB HID v1.10 Keyboard [ClockworkPI DevTerm] on usb-fe380000.usb-1.4/input0
[ 2579.140090] cdc_acm 5-1.4:1.1: ttyACM0: USB ACM device

Thank you for your suggestion, but that’s not it. The control doesn’t even get to the main firmware, it’s stil stuck in bootloader mode and the keyboard is fully operational as a DFU device, but not as a keyboard.

Yes, these are VID and PID from the dreaded DFU mode. It says “Maple” because the STM32duino bootloader was derived from one for a LeafLabs Maple board.

Just guessing but it seems like this could be something like a floating reset/program mode pin. Since it seems like it can happen randomly it may be getting a capacitive coupling during boot making it register high long enough to enter this mode. I suggest that seeing as it also seems to have a residual charge until you pop out the batteries and fully drain everything.

Not in my case. I have mentioned that I have checked the BOOT0 pin and it is at correct potential at all times.
More so, the CKS micro appear to not have a built-in bootloader in the system memory (like the STM32 counterpart), so it simply wouldn’t start if I set that pin incorrectly.
From the micro’s point of view the STM32duino bootloader is just a normal piece of code, and it executes it normally. The problem lies in the fact that the bootloader does not jump to the keyboard firmware for some reason.
The next step would be connecting a programmer and try to reflash the bootloader (just in case), and then debug it. Unfortunately, the DevTerm team did not make that easy and hasn’t left any pins for SWD for easy connection. I know that they are routed to the GPIO ribbon cable connector, but I haven’t found a suitable one yet. I’ll post my next findings once I will resolve this issue (don’t want to solder to the board directly as to not damage it in the process).

That we cannot be sure at the moment.
Maybe it boots the firmware, but then USBComposite library puts it back (faulty packets, then triggering DTS reset)?

FWIW the DTS reset never worked reliably for me. Had to power cycle it most of the time to enter DFU mode (quite the opposite to your board…).

I know, tricky stuff since we don’t have easy access to debugging facilities. Maybe try modify the firmware, so that before it enables USBComposite, it gives a signal, like rapid blinking led? That way we bisects firmware not booting vs booted but went back.

(just don’t disable the USBComposite code or otherwise you may need to find a suitable ribbon cable first)

Perhaps yours is different? Possibly different board revisions or as was mentioned, “alternative supply chain friendly chip substitutes”.

I am curious if anyone has brought up the ribbon cables before. Is there a schematic somewhere that shows the pin assignments? Anyone found a way to tap into these cleanly?

ooh it’s really different. I’ve never heard of CKS before!

The keyboard schematics is in the github repo.

The micro on my board is exactly the same as on your photo, down to every number (which probably means they are from the same batch).
The keyboard schematic can be found on github, the debugging pin assignments are as follows (these are pin numbers on the GPIO flat cable connector):

SWDIO ... 19
SWCLK ... 20
SWO ... 26?
NRST ... 4
VTREF ... 3, 59
GND ... 1, 22, 39, 56, 60

I have managed to get the keyboard working (at least with my computer, haven’t tested it with DevTerm yet).

Here’s what I did:

  1. Connected to the keyboard via ST-Link using the flat cable connector (see pinout above, you’ll need only SWCLK, SWDIO and nRST ones. In case your ST-Link needs VTRef, connect it to any 3.3V source.)
  2. I noticed that the SWD frequency should not exceed 100kHz for it all to work reliably. Also, only ST-Link v2 worked for me for some reason, but not v3.
  3. Installed the SM32Duino core as hinted at here.
  4. Cloned the STM32Duino bootloader source code. It seems to be the bootloader that was used originally.
  5. Modified config.h with the following:
diff --git a/config.h b/config.h
index b377f98..f8ce81a 100644
--- a/config.h
+++ b/config.h
@@ -156,7 +156,7 @@
 // Use Boot1 PB2 as the button, as hardly anyone uses this pin as GPIO
 // Need to set the button input mode to just CR_INPUT and not CR_INPUT_PU_PD because the external pullup on the jumplink is very weak
        #define BUTTON_INPUT_MODE       CR_INPUT
-    #define BUTTON_BANK GPIOB
+    #define BUTTON_BANK GPIOD
     #define BUTTON_PIN 2

Reasoning for the change: the state of the BUTTON determines whether the bootloader will jump to the user code or wait indefinitely.
6. Compiled the bootloader: make generic-pc13 (where pc13 stands for the pin with the LED). Important: you should use the gcc version that was installed with the STM32duino core.
7. Used STM32CubeProgrammer to flash the resulting *.bin file to the keyboard.
8. Set the switch labeled “2” to the “ON” position. The keyboard should load to the DFU mode after reset, the green LED will be blinking.
9. Compiled the stock keyboard firmware or the custom one. Do not use the binaries that are provided with the stock firmware, they already contain the bootloader inside them.
10. Flashed the firmware with dfu-util: dfu-util -a 2 -D devterm_keyboard.ino.bin
11. Set the switch back to the “OFF” position and restarted the keyboard. The green LED flashed for a bit and then turned off, and the keyboard was functional.

I did not perform any deep analysis of the source code, so I’m not sure whether if this is a correct solution and I have no idea if the second switch is used in the keyboard firmware at all. But it worked for me.

UPD: It is working with DevTerm as well.


So is step 8 a result of the change to the bootloader?

Also are the stlink tools still windows only?

And in response to the pin diagram for the flex cable, I am a bit leary of assuming it is still the same when the processor itself has been replaced. Any idea what the pitch size of the cable is?

The schematics has a reset button but it’s not on the board. Perhaps that makes the connected pin floating?

Hrm, I am guessin that might do it actually. The trace will act like a capacitor, and it’s possible enough charge buildup could affect an internal pullup resister on the processor. Even more likely on “nonstandard” cpu’s.

The reset pin is tied to +3.3V via an external 10k resistor (see schematic), and the button specified in the schematic is normally open, so there’s nothing wrong in not installing it.


So is step 8 a result of the change to the bootloader?

Yes, the second section of SW1 had no apparent effect in the stock firmware, and the bootloader had a button definition for a “Force bootloader mode” function, hence the change.

else if (readButtonState())
    no_user_jump = TRUE;

In other words, the thesult of readButtonState() call was always true, and the bootloader never jumped to the keyboard firmware.

Also are the stlink tools still windows only?

STM32 Cube Programmer is a cross-platform tool, I was using it on an ArchLinux system and had no problems.

Any idea what the pitch size of the cable is?

According to the board outline file, it’s 0.5mm.

awesome patch!

I repeated the whole process under linux

use STM32Cube to flash the bootloader hex file

finally use stm32flash to extract the whole firmware from keyboard ,included modified bootloader

here is the hacked files:

but after this change,it seems not able to use arudino IDE to do the upload

I need to put 2 ON every time when I want to flash code

I found out that the keyboard(with original firmware) is easier to hang up when the typ-c is plugged in

if I unplug type-c and re-install keyboard on DT then keyboard will be back

and of cause ,for convenience I did not install the packs of DT, naked DT

So I think there is an undervoltage that causes the original code, plugging in another device that draws power from USB seems to also lock out the keyboard. I’ll use your fix, as it does keep it from randomly switching.