--- description: "Prototyping new concepts: Adjustable column position, thumb clusters, GPIO expander" created: 2024-01-24 --- ![Left side working prototype](Left side working prototype.jpg) [TOC] ## Intro ### Design ideas - Low profile - Modular additions - Indents for anti slip feet, to keep it low profile - Joinable halves perhaps - Tactile difference for different types of keys - Smaller function key row - Concave and convex keys, to indicate type - Lots of homing indicators ### New Parts After finding out, [what worked, and what didn't with my first custom keyboard](https://blog.node5.net/Custom keyboard/#retrospective-ideas-for-a-version-2) I've got some new ideas for components i want to try out. - Low profile switches - Dedicated scroll / volume roller (scrolling on the roller ball is really nice!) - GPIO expander, for split keyboard - [aliexpress.com/ - Horizontal scrollers EVQWGD001](https://www.aliexpress.com/item/32990950196.html) - [keychron.com - Gateron Low Profile 2.0 Mechanical Switch](https://www.keychron.com/products/low-profile-gateron-mechanical-switch-set?variant=40587643355225) - [keychron.com - Keychron Low Profile Mechanical Switch](https://www.keychron.com/products/keychron-low-profile-mechanical-switch?variant=40561882595417) - MCP23017 ### Layout With the [my first keyboard design](https://blog.node5.net/Custom%20keyboard/) i validated that i like ortholinear layout, this enables me to offset the columns relative to each other, but i cannot settle on how much to offset it, therefore i got the idea to make it adjustable, I've not seen this done before, i wonder if there's a reason for this? (this is forshadowing) ![Notes idea](Notes idea.jpg) The keyboard base will have GPIO + I²C pulled out on a connector, allowing any kind of expansion I'll make the following modules: trackpoint, mouse buttons, thumb clusters, rollers for vertical scrolling and volume. #### Trackpoint I might switch from the tiny roller ball to a [ThinkPad TrackPoint™](https://xkcd.com/243/) pointing device. Since it allows for precise inputs, or fast movement, depepending on force used. Perhaps this could be implemented with the tiny roller ball aswell. The rollerball is kinda choppy though. ![Trackpoint modules](Trackpoint modules.jpg) The trackpoint module is a PS/2 device, see [QMK documentation](https://docs.qmk.fm/#/feature_ps2_mouse) and [Trackpoint pinout](https://deskthority.net/wiki/TrackPoint_Hardware) #### Height ![Key switch height compared to v1](Key switch height compared to v1.jpg) [V1 keyboard](https://blog.node5.net/Custom%20keyboard/) vs new keyboard (V2) height, almost half, nice #### Keycaps ![3D printed keycaps with legends](3D printed keycaps with legends.jpg) To print legends, multi color on the same layer see this cool blog: [Creating a Keyboard - docs.juliaebert.com](https://docs.juliaebert.com/projects/keyboard#making-them-prettier) ### Other keyboards with adjustable columns After i started on this, i found out that apparently I'm not the first to think of adjustable columns, bummer see: - [ReSummit/Seismos GitHub repo](https://github.com/ReSummit/Seismos) - [nezumee/zebra GitHub repo](https://github.com/nezumee/zebra) ## Switch holder module ![Notes column module idea generation](Notes column module idea generation.jpg) ### Switch holder design ideas ![Switch holder itterations](Switch holder itterations.jpg) ![Switches](Switches.jpg) [switch product page](https://www.gateron.co/products/gateron-low-profile-mechanical-switch-set) ![3D printed trace groves](3D printed trace groves.jpg) I ought to use a PCB for this, but that doesn't play nice with my rapid proto typing. ![Slide test 1](Slide test 1.png) ![Slide test 1 slicer 2 lines](Slide test 1 slicer 2 lines.png) Testing if this method can be manufactured on my 3D printer, it's only 2 lines wide. ### 3D printed "PCB" feasability ![3D printed "PCB" feasability test](3D printed "PCB" feasability test.jpg) ### Column module prototype ![2 column modules](2 column modules.jpg) ![Column module nail indent](Column module nail indent.jpg) ![Column module slider foot](Column module slider foot.jpg) ![End stop back](End stop back.jpg) ![Screws](Screws.jpg) ![Screws side view](Screws side view.jpg) ### Printing Keycaps ![3d printing keycaps sideways](3d printing keycaps sideways.jpg) ![Keycaps itterations](Keycaps itterations.jpg) Again, printed on its side for greater dimensional accuracy ### Prototype pile ![Prototype pile](Prototype pile.jpg) Here's the pile of prototypes it took to get a satisfying and functional mechanism and keycaps. ## Preliminary layout design ![Keyboard layout](Keyboard layout.jpg) This layout avoids having 2 unit wide buttons, which would interfere with the column sliding mechanism. Instead these buttons are moved to 2 thumb clusters. Which i I'm eager to try out. ## Wiring ### First module wired ![Module wired top](Module wired top.jpg) ![Module wired bottom](Module wired bottom.jpg) Soldered up the first module. I used stranded wire due to metal fatigue. This methodology seems to be feasible. I'm going to add pin header connectors to connect it to the board, so it can be disconnected and the module removed. Spanning the top is gonna be a prototype board PCB with all the diodes, connectors for modules, DIP28 GPIO expander and the TRRS headphone jack. ### Modules for left side printed ![Coulumns modules for left side WIP](Coulumns modules for left side WIP.jpg) Done printing and cleaning up all the modules for the left side. ![Left side modules in base top](Left side modules in base top.jpg) ![Left side modules in base bottom](Left side modules in base bottom.jpg) Printed the bottom for the left side it unfortunately bent slightly when the modules were put in place, even tho i was patient letting it cool down after printing. I held it over the stove, and counter bend it. Then placed it on a flat surface. Which fixed the curve. ![Left side wiring diagram](Left side wiring diagram.jpg) Planned out the circuit diagram for the left side of the keyboard, everything fit really nicely. I'm excited to make it a reality. The top features pin headers for each sliding module. Which has 6 pins, 1 for the column, and 5 for the rows. The rows are connected to the diodes, which bridge the gap to their respective colored bus bars on the bottom side. Which forms a natural ╲ ╲ ╲ ╲ ╲ pattern. The columns have busbars on the bottom left side. Both bus bar clusters are terminated in 2 flex cable connections, one for the GPIO expander chip, and one for a male pin header for testing and debugging, it's also pin compatible with my old keyboard, allowing me to do an agile partial goal, and get success feeling of trying it out, motivating me to keep working, and getting to test it before i add to many variables and unknowns, which could lead to multiple failure points, making me have to debug multiple possible error sources at the same time. There's 2 rows of connection points next to the debug connector, which is a fine place to extend the connection on to thumb cluster module, which differs because it has the diodes on the module as opposed to on the circuit board. It has 1 pin for the row, and the rest for the columns. Because it's wired up like it was a row at the bottom of the keyboard. Finally the headphone jack fits in the top right corner, pointing upwards, since there's already going to be the cables from the sliding modules looping that way. ### Circuit board initial test ![Circuit board painted](Circuit board painted.jpg) ![Circuit initial test](Circuit initial test.jpg) Painted the circuit board, to indicate where the busbars on the bottom are routed. Wired up a test setup to test the first 4x4 buttons, and it works, yay ^-^ ![Left side working prototype](Left side working prototype.jpg) ## GPIO Expander Ordered an [MCP23017](https://ww1.microchip.com/downloads/en/devicedoc/20001952c.pdf) I²C GPIO expander in [DIP28](https://en.wikipedia.org/wiki/Dual_in-line_package) package format. To use on the left side of the keyboard. ### GPIO Expander test Using this tutorial: [makerhacks.com ─ Use the MCP23017 GPIO Port Expander to Add 16 IO Pins](https://www.makerhacks.com/mcp23017/) i was able to make the [MicroPython](https://en.wikipedia.org/wiki/MicroPython) example work, but issues arise. It keeps throwing the exception: `[Errno 5] EIO`, furthermore `i2c.scan()` is not consistent with what it returns. All this is despite forgoing the breadboard, in favor of directly soldered connections :/ #### MCP23017 MicroPython code snippet ```py # https://blog.node5.net/Custom%20keyboard%20V2#mcp23017-micropython-code-snippet # Based on: https://www.makerhacks.com/mcp23017#h-using-mcp23017-with-raspberry-pi-pico-and-micropython import time import machine i2c = machine.I2C(1, sda=machine.Pin(0), scl=machine.Pin(1), ) i2cdevices = i2c.scan() print(i2cdevices) time.sleep(0.50) i = 0 while 1: try: i2c.writeto_mem(0x20, 0x00, b'\xFF') i2c.writeto_mem(0x20, 0x01, b'\x00') i2c.writeto_mem(0x20, 0x13, b'\x00') while 1: i2c.writeto_mem(0x20, 0x13, b'\xFF') time.sleep(0.50) i2c.writeto_mem(0x20, 0x13, b'\x00') time.sleep(0.50) except Exception as ex: i += 1 print(i, ex) ``` > [github.com ─ dhylands / rshell](https://github.com/dhylands/rshell) Can be used to make it easier, to work > with [MicroPython](https://en.wikipedia.org/wiki/MicroPython) The issues persisted, and i decided to move from MicroPython to C++ using the [Adafruit library](https://github.com/adafruit/Adafruit─MCP23017─Arduino─Library) And since the [github.com ─ earlephilhower/arduino─pico](https://github.com/earlephilhower/arduino─pico) functions [`bool SetSDA` and `bool SetSCL`](https://arduino─pico.readthedocs.io/en/latest/wire.html) didn't work to change I²C 0 pins, i change to the default pins `GP4` for `SDA` and `GP4` for `SCL` denoted by the Raspberry PI Pico pinout. ![Raspberry Pi Pico pinout](https://www.raspberrypi.com/documentation/microcontrollers/images/pico-pinout.svg) Still the issues persisted, still working sporadically for a bit, and then stopped working. I then tried using pull─up resistors with a value of `4.7KΩ`. Still didn't work consistently. I then searched around, and came across this forum post: [forum.arduino.cc ─ Problems with MCP23017 ─ Solved](https://forum.arduino.cc/t/problems─with─mcp23017─solved/21997) And i followed the wiring described therein. Namely, tie `A0`, `A1` and `A2` to ground, `Reset` to `3.3v` using a `1KΩ` pull-up resistor, and finally tie `SDA` and `SCL` to 3.3v using a `1KΩ` pull-up resistor (see the following ascii art diagram) ### MCP23017 wiring diagram ``` ┌── U ──┐ [ LED Anode ] GPB0 ( 8 ) ┤1 28├ GPA7 ( 7 ) GPB1 ( 9 ) ┤2 27├ GPA6 ( 6 ) GPB2 ( 10 ) ┤3 26├ GPA5 ( 5 ) GPB3 ( 11 ) ┤4 25├ GPA4 ( 4 ) GPB4 ( 12 ) ┤5 24├ GPA3 ( 3 ) GPB5 ( 13 ) ┤6 23├ GPA2 ( 2 ) GPB6 ( 14 ) ┤7 22├ GPA1 ( 1 ) GPB7 ( 15 ) ┤8 21├ GPA0 ( 0 ) [ 3.3v ] VDD ┤9 20├ INTA [ GND ] VSS ┤10 19├ INTB NC ┤11 18├ RESET [ 1KΩ → 3.3v ] [ GP5 & 1KΩ → 3.3v ] SCL ┤12 17├ A2 [ GND ] [ GP4 & 1KΩ → 3.3v ] SDA ┤13 16├ A1 [ GND ] NC ┤14 15├ A0 [ GND ] └───────┘ ( x ) = Adafruit library number for this pin [ x ] = Microcontroller pin ``` ### MCP23017 C++ code snippet ```c++ // https://blog.node5.net/Custom%20keyboard%20V2#mcp23017-c-code-snippet // Based on: https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/blob/master/examples/mcp23xxx_blink/mcp23xxx_blink.ino // Blinks an LED attached to a MCP23017 pin. #include #define LED_PIN 8 // MCP23XXX pin LED is attached to Adafruit_MCP23X17 mcp; void setup() { Serial.begin(9600); // while (!Serial); // Wait for Serial connection, enable for debug of early code Serial.println("MCP23017 Blink Test!"); // Find ID, by attempting initialization sequentially int i = 0; while (!mcp.begin_I2C(i)) { Serial.print("Error with ID:"); Serial.println(i); i++; delay(10); } Serial.print("Success with ID:"); Serial.println(i); mcp.pinMode(LED_PIN, OUTPUT); Serial.println("Looping..."); } void loop() { Serial.print("High, millis: "); Serial.println(millis()); mcp.digitalWrite(LED_PIN, HIGH); delay(250); Serial.print("Low, millis: "); Serial.println(millis()); mcp.digitalWrite(LED_PIN, LOW); delay(250); } ``` ## Thumbcluster ### Thumb cluster design vision Came across this really cool keyboard called Dygma Defy [youtube.com - video](https://www.youtube.com/watch?v=9-h5RVu_HBA) [dygma.com - Blog post](https://dygma.com/blogs/product-development/how-we-developed-the-defys-16-thumbkeys) they show their design iterations on thumb clusters they seem to align with what i envisioned, namely ergonomically shaped buttons, which is possible due to the 3D printing manufacturing. They've done lots ### Thumb cluster prototype iterations I've iterated on the thumb cluster design (based on the amazing work by the [Dygma Defy](https://dygma.com/pages/defy) team) and I've reached a design that works for me. ![Thumb cluster CAD based on Dygma Defy](Thumb cluster CAD based on Dygma Defy.png) ![Thumb cluster itterations](Thumb cluster itterations.jpg) ### MCP23017 breadboard TRRS cable ![MCP23017 breadboard TRRS cable](MCP23017 breadboard TRRS cable.jpg) I've now moved to using 2 separate breadboards to test if the I²C is stable over the cable (it seems to be). Pulling the TRRS cable while powered, doesn't break it, but does require a power cycle to function again. ### MCP23017 button code ```c++ // https://blog.node5.net/Custom%20keyboard%20V2#mcp23017-button-code // Based on: https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/blob/master/examples/mcp23xxx_combo/mcp23xxx_combo.ino #include #define BLINK_FREQUENCY 1000 // Milliseconds #define LED_PIN 8 // LED pin on MCP23017 #define BUTTON_PIN 7 // Button pin on MCP23017 Adafruit_MCP23X17 mcp; int blink_frequency; // Milliseconds void setup() { Serial.begin(9600); //while (!Serial); Serial.println("MCP23017 Blink Test!"); int i = 0; while (!mcp.begin_I2C(i)) { Serial.print("Error with ID:"); Serial.println(i); i++; delay(10); } Serial.print("Success with ID:"); Serial.println(i); mcp.pinMode(LED_PIN, OUTPUT); mcp.pinMode(BUTTON_PIN, INPUT_PULLUP); Serial.println("Looping..."); } void loop() { // What is an interupt? if (!mcp.digitalRead(BUTTON_PIN)) { // Button pushed, light LED blink_frequency = BLINK_FREQUENCY / 20; } else { blink_frequency = BLINK_FREQUENCY; // Milliseconds } // Alternate state every blink_frequency milliseconds bool state = (millis() % (blink_frequency * 2)) > blink_frequency; Serial.print("State: "); Serial.println(state); mcp.digitalWrite(LED_PIN, state); } ``` ### Other QMK keyboards using MCP23017 MCP23017 working principle has been tested. Now it's time to make it work with QMK. The following keyboards implement the MCP23017. ```bash # List keyboards containing mcp23017 case insensitive grep -I --color=always -rnie "mcp23017" | cut -d'/' -f2 | uniq # List files containing mcp23017 case insensitive with the file extension .h or .c grep -I --color=always -rnie "mcp23017" --include \*.h --include \*.c | cut -d':' -f1 | uniq ``` - [github.com - nek_type_a](https://github.com/qmk/qmk_firmware/tree/master/keyboards/nek_type_a) - [github.com - hotdox](https://github.com/qmk/qmk_firmware/tree/master/keyboards/hotdox) - [github.com - ergodox_stm32](https://github.com/qmk/qmk_firmware/tree/master/keyboards/ergodox_stm32) - [github.com - ingrained](https://github.com/qmk/qmk_firmware/tree/master/keyboards/ingrained) - [github.com - ferris](https://github.com/qmk/qmk_firmware/tree/master/keyboards/ferris) ### LED Indicator I planned to add an indicator LED, it's an RGB LED, meaning I'll have to add a current limiting resistor per color, with a unique value for each. I then run into the issue that the forward voltage of the blue LED is higher than the supply voltage, which is about 3v. [What will happen to an LED if the forward voltage (Vf) is greater than its supply voltage? - electronics.stackexchange.com](https://electronics.stackexchange.com/questions/573214/what-will-happen-to-an-led-if-the-forward-voltage-vf-is-greater-than-its-suppl) ## Full stop Got a bit burned out on the project, shelfing it for now. So up to this point, i had the intention of making this into a full hand wired keyboard. But I don't like how the wires at the top ended up looking, so I've chosen to cut my losses and use my prototype to decide how I want the offsets to be, and as a test bed to remove my last few unknowns, namely, thumb cluster and I/O expander chip. I should have cut more corners, to test the core concept, before spending time, on the niceties. ## Next up: PCB This article is followed up in: [Custom keyboard V2 - part 2 - PCB](/Keyboard%20V2%20-%20Part%202%20-%20PCB/) Also checkout [my V1 keyboard](https://blog.node5.net/Custom%20keyboard/).