Karve-Split-Keyboard

Public

@osnwy

Download board files

Files for version 1. Pick what you came for.

Share Karve-Split-Keyboard

Check access before sharing the link.

Who can open this board

Anyone can open this board. No sign-in is required.

This link opens the latest version. Copying it does not grant additional access.

Loading 3D model… large boards can take a moment.

README

Karve-Split-Keyboard

What is this?

This is a keyboard, designed to be slightly ergonomic-consious while keeping the orginal layout and familarity of an 80% keyboard. The idea is to create a split keyboard, but with the option to connect the two havles together to create a regular 80% keyboard, inspired from the Epomaker Split 65. Unlike the Split 65, this features an 80% layout with macro keys on the left column, an OLED 0.91 inch screen and rotary encoder on both sides. While making this keyboard, I realized that the format is really similar to the Keychron Q11 with the macro keys and 80% layout. This keyboard features an unexploded (is that the right term) layout, maximizing desk space without comprimising on the number of keys (I need my precious function row).

Each side of the keyboard is powered by an Pi Pico with an RP2040. The descision behind the RP2040 was due to the number of GPIO pins. Other options such as the nrf52840 and the RP2040-Zero would've worked well for this project, but the number of GPIO pins wouldn't be sufficient for all the switches and the extra features on the keyboard. The OLED screen is a general 0.91 inch 128x32px screen, with optional footprints for pull-up resistors, and the rotary encoder is a regular EC11 push switch. The switches in the keyboard are wired in a matrix with a diode on each switch. The left side is wired as an 8x6 matrix, and the right side is an 9x6 matrix. The switches themselves contain a regular mx hotswap socket which allows for easy switching between switches of the same format.

How do I get this?

For this keyboard, you need the pcb, switches, stablizers, keycaps, two Pi Picos, two OLED screens and two rotary encoders. You should order the rest of the components using the PCBA option on JLCPCB. You can order it using the gerbers zip file in the Gerbers file, as well as the bom.csv and the positions-full-pcb-offset.csv. Make sure you choose bottom side assembly. The switches simply slide into the top of the plate and fit into the hotswap sockets on the PCB, the stablizers are plate mounted and can be slotted into the plate, and the keycaps simply go on top of the switches. The plate uses spacers to attach to both the PCB and the case using self-tapping screws through the plate, without the need for unnessecary mounting holes on the thin plate, which may degrade it's strength. The OLED screen and Pi Pico must be soldered into the PCB using the pins, making sure they are in the correct orientation.

CAD

This keyboard is printed in two parts, with two different cases for each half of the PCB, as well as two plates for each half the plate and pcb are seperated by 3.5mm spacers, which are screwed in from the top of the plate to the PCB mounting holes.

ONSHAPE LINK

Schematic

The schematic contains a matrix for the switches on each side, a simple 4 pin OLED screen with pull-up resistors that can be unpopulated if the screen already has pull-ups, a USB-C UART connector between the two halves, and a fuse and capacitor for the power line. The USB-C UART connections works by splitting the TX and RX lines, as well as passing the 5v through the VSYS and passing the ground through the wire.

PCB

The PCB is a simple PCB with traces of varying widths for the purpose of each trace. The power lines and ground lines for the USB-C receptacle were 0.75mm, other ground traces and local power lines are 0.5mm. The PCB also includes M2 holes for the mounting and mousebites so the PCB can be ordered as one part.

The silkscreen art is put togetrher in a way that (hopefully) will show a full image of the tree when the split halves are put together.

BOM

JLCPCB BOM

QtyReferencesComponentManufacturer / Part numberPCB footprintJLCPCB partLibrary
2C2, C310 µF, 50 V, X5R, ±10% ceramic capacitorMurata GRM21BR61H106KE43L0805C440198Basic
92D43–D1341 A, 200 V fast-recovery diodeDOWO ES1D (SOD-123FL)SOD-123FLC22374920Extended
2F2, F3500 mA resettable fuse, 33 VBHFUSE BSMD1206-050-33V1206C7202014Extended
2J2, J3USB-C 2.0 receptacle, 16-pinKorean Hroparts TYPE-C-31-M-12USB_C_Receptacle_HRO_TYPE-C-31-M-12C165948Extended
2R5, R647 Ω, ±1%, 100 mW resistorUNI-ROYAL 0603WAF470JT5E0603C23182Basic
90SW43–SW50, SW52–SW92, SW94–SW134MX-compatible hot-swap socketHanElectricity CPG151101S11-16See variants belowC41430893Extended
Hot-swap footprint variants
FootprintQty
MX100H77
MX125H4
MX150H2
MX175H2
MX200H1
MX225H3
MX275H1
Total90

PCB and PCBA

ComponentQuantityNotes / specificationLinkCost
Custom split-keyboard PCB set1Left and right PCB (together)JLCPCB$64.59 USD
Raspberry Pi Pico2RP2040 USB-C CloneLINK$8.09 USD
Kailh MX-compatible hot-swap socket90HanElectricity CPG151101S11-16; JLCPCB/LCSC C41430893JLCPCBIncluded in PCBA
Matrix diode92DOWO ES1D, SOD-123FL, 1 A, 200 V; JLCPCB/LCSC C22374920JLCPCBIncluded in PCBA
USB-C 2.0 receptacle2Korean Hroparts TYPE-C-31-M-12; JLCPCB/LCSC C165948JLCPCBIncluded in PCBA
Resettable polyfuse2BHFUSE BSMD1206-050-33V, 500 mA; JLCPCB/LCSC C7202014JLCPCBIncluded in PCBA
10 µF ceramic capacitor2Murata GRM21BR61H106KE43L, 0805, 50 V, X5R; JLCPCB/LCSC C440198JLCPCBIncluded in PCBA
47 Ω resistor2UNI-ROYAL 0603WAF470JT5E, 0603, ±1%; JLCPCB/LCSC C23182JLCPCBIncluded in PCBA
4.7 kΩ pull-up resistor4 optionalThrough-hole; only install if the OLED modules do not include I²C pull-upsOptionalN/A

Displays and Controls

ComponentQuantityNotes / specificationLinkCost
0.91-inch I²C OLED display2pin order and pull upsAliExpress$7.70 USD
EC11-style rotary encoder with push switch2EC11 FootprintAliExpress$3.35 USD

Switches and Keycaps

ComponentQuantityNotes / specificationLinkCost
MX-compatible mechanical switch905-pin PCB-mount switches recommendedsAliExpress$22.53 USD
Keycap set1 setMust cover the full split layout and split spacebarAliExpress$27.45 USD
StabilizersAs requiredRequired for stabilized keysAliExpress$10.72 USD

Case, Plate, and Mounting Hardware

ComponentQuantityNotes / specificationLinkCost
Left keyboard plate13d printedN/AN/A
Right keyboard plate13d printedN/AN/A
Left keyboard case13d printedN/AN/A
Right keyboard case13d printedN/AN/A
Spacers163d pritnedN/AN/A

Pico and Display Installation Hardware

ComponentQuantityNotes / specificationLinkCost
1×20 pin headers4 stripsTwo rows per Pico if soldering through-hole headersCOMES WITH PI PICOFREE
1×4 pin headers2For directly soldering the OLED modulesCOMES WITH OLEDFREE

Cost Summary

CategoryCost
PCB fabrication$29.90 USD
PCB components and assembly$34.69 USD
Picos, displays, and encoders$19.14 USD
Switches and keycaps$49.98 USD
Case, plates, and hardwareN/A
Cables and assembly supplies$10.72
Shipping and taxes$41.25 USD
Estimated total$185.68 USD

Firmware

This firmware is the preliminary firmware, and may be changed for the final finished build. It uses QMK, and can be flashed using UF2 and QMK commands. I used this repositry as a reference: https://github.com/aminch/c64p/tree/main, as well as a couple other websites.

The firmware is grouped under the firmware file in the repositry. It includes:

FilePurpose
info.jsontells the computer what keyboard/mcu, as well as the USB type.
rules.mktells the computer what QMK features should be used, such as the I2C OLED.
mcuconf.henables the rp2040 I2C hardware for the OLED screens.
halconf.halso used to enable the I2C for the OLED screens.
config.hused to define all the pins on the picos for both the left and right split halves, as well as other features such as debounce time, OLED brightness, etc.
keymap.cused to define the keymap as well as the OLED, encoders, as well as layers.

rules.mk:

MCU = RP2040
BOARD = GENERIC_RP_RP2040
BOOTLOADER = rp2040

ENCODER_ENABLE = yes
OLED_ENABLE = yes
OLED_DRIVER = ssd1306
OLED_TRANSPORT = i2c

These lines are used to define the MCU, board, as well as enable rotary encoders and OLED screens.

config.h:

#define DIODE_DIRECTION COL2ROW

#define MATRIX_ROW_PINS { GP8, GP9, GP10, GP11, GP12, GP13 }
#define MATRIX_COL_PINS { GP0, GP1, GP2, GP3, GP4, GP5, GP6, GP7, NO_PIN }

#define MATRIX_ROW_PINS_RIGHT { GP5, GP4, GP3, GP2, GP1, GP0 }
#define MATRIX_COL_PINS_RIGHT { GP14, GP13, GP12, GP11, GP10, GP9, GP8, GP7, GP6 }

#define ENCODER_A_PINS { GP20 }
#define ENCODER_B_PINS { GP21 }
#define ENCODER_A_PINS_RIGHT { GP20 }
#define ENCODER_B_PINS_RIGHT { GP21 }

#define SERIAL_USART_FULL_DUPLEX
#define SERIAL_USART_TX_PIN GP16
#define SERIAL_USART_RX_PIN GP17

#define I2C_DRIVER I2CD1
#define I2C1_SDA_PIN GP18
#define I2C1_SCL_PIN GP19

This is used to define what each pin is used for, such as the matrix, encoders, as bwell as TX/RX and pins used for the OLED screen etc. The RX/TX are crossed through the USB port, so both sides can have the same RX/TX pins.

#define EE_HANDS

This means that both of the source codes are the same for both the left and right side.

keymap.c:

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [_BASE] = {
        { KC_MUTE, KC_ESC,  KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_NO },
        { KC_F13,  KC_GRV,  KC_1,    KC_2,    KC_3,    KC_4,    KC_5,    KC_6,    KC_NO },
        { KC_F14,  KC_TAB,  KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,    KC_NO,   KC_NO },
        { KC_F15,  KC_CAPS, KC_A,    KC_S,    KC_D,    KC_F,    KC_G,    KC_NO,   KC_NO },
        { KC_F16,  KC_LSFT, KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_NO,   KC_NO },
        { KC_F17,  KC_LCTL, KC_LGUI, KC_LALT, KC_SPC,  KC_NO,   KC_NO,   KC_NO,   KC_NO },
        { KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12,  KC_INS,  KC_DEL,  KC_MUTE },
        { KC_NO,   KC_7,    KC_8,    KC_9,    KC_0,    KC_MINS, KC_EQL,  KC_BSPC, KC_PGUP },
        { KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,    KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN },
        { KC_NO,   KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT, KC_ENT,  KC_HOME },
        { KC_NO,   KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_RSFT, KC_UP,   KC_END },
        { KC_NO,   KC_SPC,  KC_RALT, KC_RGUI, MO(_FN), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT }
    },
    [_FN] = {
        { _______, QK_BOOT, _______, _______, _______, _______, _______, _______, 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,   _______, _______, _______, _______, _______, _______, _______, _______ }
    }
};

The keymap file allows us to assign each matrix to a specific key by using these arrays, as well as the function layer. Right now these keys are in a tentative map, but it can easily be changed later.

bool encoder_update_user(uint8_t index, bool clockwise) {
    if (index == 0) {
        if (clockwise){
            tap_code(KC_PGDN);
        }else{
            tap_code(KC_PGUP);
        }
    } else {
        if (clockwise){
            tap_code(KC_VOLU);
        }else{
            tap_code(KC_VOLD);
        }
    } 
    return false;
}

This simply assigns the rotary encoders left and right turns to a key.

#ifdef OLED_ENABLE

oled_rotation_t oled_init_user(oled_rotation_t rotation) {
    return rotation;
}

bool oled_task_user(void) {
    oled_write_ln_P(PSTR("KARVE"), false);

    if (is_keyboard_left()) {
        oled_write_ln_P(PSTR("LEFT"), false);
    } else {
        oled_write_ln_P(PSTR("RIGHT"), false);
    }

    if (is_keyboard_master()) {
        oled_write_ln_P(PSTR("MASTER"), false);
    } else {
        oled_write_ln_P(PSTR("SLAVE"), false);
    }

    oled_write_P(PSTR("LAYER "), false);
    oled_write_char('0' + get_highest_layer(layer_state), false);

    return false;
}

#endif

This displays "KARVE LEFT MASTER" or "KARVE RIGHT SLAVE" on the OLED screens depending on the split half. This is can easily changed to other options later.

Comments

No comments yet. Be the first to ask about this board.

Ask about this board

Sign in to BoardRepo

New here? Signing in creates your account; there is no separate sign-up.