Skip to content

Instantly share code, notes, and snippets.

@gleber
Last active December 5, 2025 15:53
Show Gist options
  • Select an option

  • Save gleber/8d6c90d16dee45db2dd458814d3dd1fc to your computer and use it in GitHub Desktop.

Select an option

Save gleber/8d6c90d16dee45db2dd458814d3dd1fc to your computer and use it in GitHub Desktop.
X.Tips X7S Keyboard (2024-04)

QMK config

I've managed to compile a working firmware with this config: https://github.com/gleber/qmk_firmware/commit/54078ec73c0ff2bd01984242f748a837c1954d03

Details

This isn't tested much, just the basics: keys and split setup. LED, bootloader magic key and any other features are not yet implemented. Tested only the Miryoku layout so far.

I've disassembled it and found a few things.

Back of one of the sides looks like this:

A more close up photo of the chip shows some STM32 chip:

If you decode the QR code it gives you a short link to what seem to be JLC PCB page about this specific PCB:

It includes product name 【X.Tips】X7S小分体键盘_-_V2.0_【热插拔】PCB-X7S-V2-R__20240726163326 which translates with Google Translate to 【X.Tips】X7S small split keyboard_-_V2.0_【Hot plug】PCB-X7S-V2-R__20240726163326

And these schematics images for the right side:

and for the left side:

Attached via-x7.json file was sent to one of the buyers by the seller. It works for my keyboard.

{
"name": "X.Tips X7 Keyboard",
"vendorId": "0x5262",
"productId": "0x4E4B",
"keycodes": ["qmk_lighting"],
"menus": [ "qmk_rgblight"],
"matrix": {"rows": 8, "cols": 5},
"layouts": {
"keymap": [
["0,0","0,1","0,2","0,3","0,4",{"x":1},"4,4","4,3","4,2","4,1","4,0"],
["1,0","1,1","1,2","1,3","1,4",{"x":1},"5,4","5,3","5,2","5,1","5,0"],
["2,0","2,1","2,2","2,3","2,4",{"x":1},"6,4","6,3","6,2","6,1","6,0"],
[{"x":2},"3,2","3,3","3,4",{"x":1},"7,4","7,3","7,2"]
]
}
}
{
"name": "X.Tips X7 Keyboard",
"vendorProductId": 1382174283,
"macros": ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""],
"layers": [
[
"KC_Q",
"KC_W",
"KC_E",
"KC_R",
"KC_T",
"KC_A",
"KC_S",
"KC_D",
"KC_F",
"KC_G",
"KC_Z",
"KC_X",
"KC_C",
"KC_V",
"KC_B",
"KC_NO",
"KC_NO",
"MT(MOD_LCTL,KC_ESC)",
"LT(1,KC_SPC)",
"KC_LSFT",
"KC_P",
"KC_O",
"KC_I",
"KC_U",
"KC_Y",
"KC_ENT",
"KC_L",
"KC_K",
"KC_J",
"KC_H",
"KC_BSPC",
"LT(4,KC_DOT)",
"LT(3,KC_COMM)",
"KC_M",
"KC_N",
"KC_NO",
"KC_NO",
"MT(MOD_LGUI,KC_DEL)",
"LT(7,KC_SPC)",
"MT(MOD_LALT,KC_TAB)"
],
[
"KC_7",
"KC_8",
"KC_9",
"KC_PDOT",
"KC_PPLS",
"KC_4",
"KC_5",
"KC_6",
"KC_0",
"KC_PMNS",
"KC_1",
"KC_2",
"KC_3",
"KC_BSPC",
"KC_EQL",
"KC_NO",
"KC_NO",
"KC_LCTL",
"TO(0)",
"MT(MOD_LSFT,KC_PENT)",
"KC_GRV",
"S(KC_BSLS)",
"S(KC_SCLN)",
"S(KC_4)",
"KC_PAST",
"KC_SCLN",
"S(KC_RBRC)",
"S(KC_LBRC)",
"S(KC_3)",
"KC_PSLS",
"KC_QUOT",
"S(KC_DOT)",
"S(KC_COMM)",
"S(KC_7)",
"KC_BSLS",
"KC_NO",
"KC_NO",
"KC_LGUI",
"G(KC_SPC)",
"KC_LALT"
],
[
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO",
"KC_NO"
],
[
"LCAG(KC_P)",
"KC_F9",
"KC_F10",
"KC_F11",
"KC_F12",
"LCAG(KC_ENT)",
"KC_F5",
"KC_F6",
"KC_F7",
"KC_F8",
"LCAG(KC_BSPC)",
"KC_F1",
"KC_F2",
"KC_F3",
"KC_F4",
"KC_NO",
"KC_NO",
"KC_RCTL",
"TT(6)",
"KC_RSFT",
"KC_NLCK",
"KC_APP",
"KC_INS",
"KC_VOLU",
"KC_VOLD",
"KC_SLCK",
"KC_PSCR",
"KC_PAUS",
"KC_MNXT",
"KC_MPRV",
"RCS(KC_O)",
"RCS(KC_X)",
"TO(0)",
"KC_MPLY",
"KC_MUTE",
"KC_NO",
"KC_NO",
"KC_RGUI",
"MO(5)",
"KC_RALT"
],
[
"MEH(KC_Q)",
"MEH(KC_W)",
"MEH(KC_E)",
"MEH(KC_R)",
"MEH(KC_T)",
"MEH(KC_A)",
"MEH(KC_S)",
"MEH(KC_D)",
"MEH(KC_F)",
"MEH(KC_G)",
"MEH(KC_Z)",
"MEH(KC_X)",
"MEH(KC_C)",
"MEH(KC_V)",
"MEH(KC_B)",
"KC_NO",
"MEH(KC_2)",
"MEH(KC_3)",
"MEH(KC_4)",
"MEH(KC_5)",
"MEH(KC_P)",
"MEH(KC_O)",
"MEH(KC_I)",
"MEH(KC_U)",
"MEH(KC_Y)",
"MEH(KC_ENT)",
"MEH(KC_L)",
"MEH(KC_K)",
"MEH(KC_J)",
"MEH(KC_H)",
"MEH(KC_BSPC)",
"TO(0)",
"MEH(KC_COMM)",
"MEH(KC_M)",
"MEH(KC_N)",
"KC_NO",
"KC_NO",
"MEH(KC_0)",
"MEH(KC_9)",
"MEH(KC_6)"
],
[
"RGB_HUI",
"RGB_MOD",
"HYPR(KC_E)",
"HYPR(KC_R)",
"HYPR(KC_T)",
"RGB_SAI",
"RGB_SPI",
"HYPR(KC_D)",
"HYPR(KC_F)",
"HYPR(KC_G)",
"RGB_VAI",
"RGB_TOG",
"HYPR(KC_C)",
"HYPR(KC_V)",
"HYPR(KC_B)",
"HYPR(KC_1)",
"HYPR(KC_2)",
"HYPR(KC_3)",
"HYPR(KC_4)",
"HYPR(KC_5)",
"KC_MS_BTN2",
"KC_MS_UP",
"KC_MS_BTN1",
"A(KC_TAB)",
"A(KC_F4)",
"KC_MS_RIGHT",
"KC_MS_DOWN",
"KC_MS_LEFT",
"C(KC_T)",
"C(KC_W)",
"KC_MS_BTN3",
"KC_MS_BTN5",
"KC_MS_BTN4",
"C(KC_TAB)",
"RCS(KC_TAB)",
"KC_NO",
"KC_NO",
"MEH(KC_RBRC)",
"TO(0)",
"MEH(KC_LBRC)"
],
[
"LCAG(KC_Q)",
"KC_F21",
"KC_F22",
"KC_F23",
"KC_F24",
"LCAG(KC_A)",
"KC_F17",
"KC_F18",
"KC_F19",
"KC_F20",
"LCAG(KC_Z)",
"KC_F13",
"KC_F14",
"KC_F15",
"KC_F16",
"KC_NO",
"KC_NO",
"MT(MOD_LCTL,KC_ESC)",
"TO(0)",
"MT(MOD_LSFT,KC_TAB)",
"KC_PDOT",
"KC_P9",
"KC_P8",
"KC_P7",
"KC_PPLS",
"KC_P0",
"KC_P6",
"KC_P5",
"KC_P4",
"KC_PMNS",
"KC_BSPC",
"KC_P3",
"KC_P2",
"KC_P1",
"KC_PAST",
"KC_NO",
"KC_NO",
"KC_PENT",
"MT(MOD_LSFT,KC_SPC)",
"MT(MOD_LALT,KC_PSLS)"
],
[
"S(KC_GRV)",
"S(KC_5)",
"S(KC_MINS)",
"S(KC_6)",
"S(KC_EQL)",
"S(KC_2)",
"S(KC_QUOT)",
"S(KC_1)",
"S(KC_SLSH)",
"KC_MINS",
"KC_LBRC",
"KC_RBRC",
"S(KC_9)",
"S(KC_0)",
"KC_EQL",
"KC_NO",
"KC_NO",
"KC_RCTL",
"KC_CAPS",
"KC_RSFT",
"KC_PGUP",
"KC_END",
"KC_UP",
"KC_HOME",
"S(KC_8)",
"KC_PGDN",
"KC_RGHT",
"KC_DOWN",
"KC_LEFT",
"KC_SLSH",
"KC_DEL",
"KC_TAB",
"KC_ESC",
"MEH(KC_SLSH)",
"KC_BSLS",
"KC_NO",
"KC_NO",
"KC_RGUI",
"TO(0)",
"KC_RALT"
],
[
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS",
"KC_TRNS"
]
],
"encoders": []
}
@GreyTime
Copy link

@kyonav Thanks for the detailed tutorial. I bought the ST-Link and did the steps, but sadly the right side is not working (for the left side I didn't't even need to do the ST-Link process). It doesn't seem to go out of bootloader mode, and windows is giving me an error that it's corrupted or something. I tried a bunch of different bootloaders, but had luck unfortunately.

@zundr
Copy link

zundr commented Jan 2, 2025

@kyonav Thanks for the tutorial too! I had similar results than @GreyTime, in Linux in my case.

I am able to flash the bootloader with both STM32CubeProgrammer as well as with st-flash.
Once flashed through the ST-link v2, I disconnect and connect through the USB, and it is recognized as Maple (0x1eaf:0x0003).
In this state, dfu-util -l detects the device and recognizes 3 interfaces. However, when I try to flash QMK firmware (any .bin), it complains that it cannot set the alternate interface:

Opening DFU capable USB device...
Device ID 1eaf:0003
Device DFU version 0110
Claiming USB DFU Interface...
Setting Alternate Interface #2 ...
dfu-util: Cannot set alternate interface: LIBUSB_ERROR_OTHER
make[1]: *** [platforms/chibios/flash.mk:42: dfu-util] Error 74

I tried the maple_rev3, with similar results.
With the generic_boot20_pc13.bin firmware, the device was recognized as a USB modem, and dfu-util didn't detect it.

Then, I tried rebooting shorting the bootloader pins, and I got the "Unable to enumerate" error.

usb 1-2: new full-speed USB device number 83 using xhci_hcd
usb 1-2: Device not responding to setup address.
usb 1-2: Device not responding to setup address.
usb 1-2: device not accepting address 83, error -71
usb 1-2: WARN: invalid context state for evaluate context command.
usb usb1-port2: unable to enumerate USB device

Finally, I tried flashing the firmware directly with STM32CubeProgrammer and with st-flash, which completed successfully, but then produced the same "Unable to enumerate USB device". Shorting the pins, don't make a difference.

I think it's a bit striking than after flashing the maple bootloader and shorting the pins produces the same "bricked" state (while the pins are shorted), as than flashing the QMK firmware through ST-link.

@sietschie
Copy link

Just wanted to add my own datapoint: Flashing went well for me, nothing got bricked. Thanks for the effort of figuring everyting out.

@DominikJaskowiec
Copy link

DominikJaskowiec commented Mar 13, 2025

Hello, I bricked the left side of the keyboard using the method provided, and now I cant unbrick it. I've flashed the right side first and than other and it's now unresponsive (right side still works with flashed layout). I've tried going the STLink route but it doesn't work, it shows me a window that says "Unable to get core ID" followed by "No STM32 target found". I've checked if the working half is detected by STM and it does. I've ordered the STLink v2 off of Aliexpress and updated it's firmware with the stm32 tool and connected the cables as labeled. Nothing works

Does anyone have an Idea of what to do here?

EDIT: Thought this would possibly help, I've checked and it's not completely dead. when i connect the right half to my PC, Windows detects it as "Unknown USB Device (Device Descriptor Request Failed)"

@tgfuellner
Copy link

Hi,

I was able to unbrick the left side of my X.Tips V4e Keyboard.
First I read the firmware of the working right side: st-flash read firmware.bin 0x08000000 0x10000
Then I wrote to the left side: st-flash write firmware.bin 0x08000000

@code-inflation
Copy link

@tgfuellner how did you connect the stm programmer to the V4e? Thanks!

@tgfuellner
Copy link

At that time, I wrote down the following:

SWDIO=PA13=34, SWCLK=PA14=37, GND=VSS=8, NRST=7

To flash the keyboard you need to connect the reset contacts (not necessary the holes, but the metal around them) with anything conductive DURING power up of th
e keyboard. I.e. the way I do it normally is I short these RESET contacts and I plug in the USB cable. This moves the chip on the keyboard into bootloader mode, w
hich allows you to flash it.

Hope that helps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment