Mechanical Keyboard Prototype With V-USB & QMK
This is a relatively complete guide on how to build a mechanical keyboard prototype and get it functioning with QMK. Two different microcontrollers will be demonstrated (ATMegs32A, ATMega328P) and it should provide a solid starting point for anyone wishing to build a keyboard from the ground up. This is going to the the base I build on with an aim to designing, testing and producing a selection of full keyboards.
Required Hardware
The hardware you will require for this project is as follows
- A ATMega32A or ATMega328P AVR microcontroller, either will do for this test, the 32A may be preferred if you plan to build a larger keyboard as it has more available lines.
- Something to program a bootloader on the microcontroller, I use a Pro Micro for this task, you can use a Raspberry Pi.
- An old USB cable or a USB header, something to get the connection from your pc to the microcontroller. I used a handmade cable for one setup and aUSB-C header board for another. It makes no difference what you use, you just require VCC / GND / D+ / D – from a USB port to your project.
- A 16Mhz crystal, part of the clock circuit.
- 2 x 22pF ceramic capacitors, part of the clock circuit.
- 2 x 68R resistors for the USB data lines.
- A 4.7uF electrolytic capacitor to smooth the USB power lines.
- A1.5k resistor, part of the USB data line voltage drop circuit (level adjustment).
- 2 mechanical keyboard switches, any at all will do (actually any momentary switch).
- 4 x 1N4148 diodes two for the keyboard matrix and two to drop the USB data lines to the correct voltage (technically these should be 3.6v zener diodes like these but 1N4148 have worked for me and I had them already, and it should be ok for testing).
- A selection of solid cable to make up jumper wires or pre-made jumper cables.
- A breadboard to plug all the parts into.
- A two pin header or dip switch or a jumper wire, something to short two pins to force the microcontroller into bootloader mode.
- Soldering iron, snips, etc
Software Required
I do all of my work on Macs so the software will be presented as if the reader is using this platform, I believe all the tools are cross platform but I cannot comment on their use or setup on Windows or Linux as they are not platforms I have used them on.
- QMK Toolbox, this is used for flashing firmware at various points in the process.
- Pro Micro ISP Programmer firmware, to flash on to the Pro Micro (will not be needed if you are using different programmer hardware).
- A working standard build environment.
- A working QMK build environment.
- USBaspLoader source files.
- The relevant files from my dev_scarlet build of QMK that contains the keyboard.
References To Guides
It is only fair that I reference the guides that helped me with this project, they may be helpful for people reading my guide for use as additional points of reference.
One of the primary sources that I was able to find to initially get me going was a Reddit post by oldoverholt. This linked onto a very high level guide to setting this kind of project up with an ATMega328P.
I also used the Discipline keyboard project as another source of reference for both QMK code. design ideas and an overview of how this should work. The Discipline keyboard uses a ATMega32A microcontroller.
Construction
Throughout the construction I will primarily refer to the ATMega32A process but will give examples wherever it would deviate if you are using an ATMega328P. I will also provide two overview finished schematics for both microprocessors.
Flashing a bootloader and setting fuses
The first stage to the project will be flashing a bootloader on the microprocessor of choice, the process will be exactly the same regardless witch of the two chips you use (but fuse settings will be different). To flash a bootloader you will require a device to do the loading (a programmer), I chose to use a Pro Micro board as I have a few available, you could use a Raspberry PI or a Teensy. For this guide I will discuss using a Pro Micro and leave other options to the reader.
Preparing the programmer
First must flash a specific firmware to the Pro Micro, the firmware in question is mentioned above and is derived from the QMK ISP Flashing Guide. Download the firmware and QMK toolbox, install QMK toolbox and connect your Pro Micro.
You should open QMK toolbox and see that it has detected the Pro Micro, it should say something similar to the following.
*** Caterina device connected
Found port: /dev/cu.usbmodem14501
At the top of the page, click open and locate the firmware file you downloaded. Then make sure that the MCU is set to ‘atmega32u4’ (this is only if you are using a Pro Micro, otherwise the MCU will be different).
When ready click flash and you should see an output similar to the following (click for large version), you will also see at the end I have disconnected and reconnected the Pro Micro and it how reads as an AVRISP device, this confirms it is correctly configured and ready to program other microcontrollers.
Preparing the microcontroller and wiring the programmer
You will need to layout the microprocessor on a breadboard, provide power and ground lines and wire up the crystal (including two capacitors) to provide a clock signal. You will then need to connect the relevant pins from the programmer to the breadboard. I have produced a simple Fritzing diagram of the required wiring for both microprocessors. Please do not connect an external power source to the breadboard, connect the VCC and GND lines from the programmer as shown (click for large version).
Configuring, compiling and flashing the bootloader
Now we have our programmer wired and ready to go we need to configure the bootloader before we flash it onto the microcontroller.
I am going to assume you have a working build environment and have downloaded (and setup) QMK source and the USBaspLoader, if not please set this up now.
We need to make some changes to the bootloader config to reflect what microcontroller we are using and to also configure the default USB pins (QMK uses PD2 and PD3 for USB to make life easier we will use the same).
In the root directory of USBaspLoader make the following changes to the Makefile.inc file, make sure you set the correct microcontroller.
F_CPU = 16000000
# this will either be atmega32 or atmega328p depending on the
# microcontroller you are using
DEVICE = atmega32
FLASHADDRESS = 0x7000
# you will need to update the port (part after -P) to reflect the name of your
# usb port, or completely change this command if you are not using a Pro Micro
PROGRAMMER = -c avrisp -P /dev/cu.usbmodem123451
In the folder ‘firmware’ make the following changes to the bootloaderconfig.h file.
#define USB_CFG_INTPORT_BIT 2
#define USB_CFG_DMINUS_BIT 3
#define JUMPER_BIT 6
With these changes complete we can now compile the bootloader. From the root directory of USBaspLoader run the following commands.
make clean
make firmware
We are now ready to flash, but before we do we are going to check we can see the microcontroller and set some fuses on it.
Execute the following command from a terminal window, adjusting the -p atmega32 to -p atmega328p if you are using the 328p and changing -P to the correct usb port.
avrdude -c avrisp -p m32 -P /dev/cu.usbmodem123451 -v
You should get a return detailing the programmer and attached microprocessor, you should see it read ok and return normally as per the following image. If not check your wiring and make sure the programmer flashed successfully.
The final stage before flashing the bootloader is to set the fuses. Fuses are persistent settings that are written to a specific area of the microcontroller, they control such things as clock speed, debug interfaces and various other options, caution must be taken when setting as incorrect values can brick the microcontroller (more detail on fuses can be found in a video here).
Our purpose here is to set the microcontroller to use the external 16mhz clock and to ensure that brownout detection is off. Fuse settings are derived from the fuse calculator.
There are different fuse settings for the two different microcontrollers, but they are set using a similar method, execute the following commands depending on which microcontroller you are using.
#ATMega32A Fuses
avrdude -c avrisp -p m32 -P /dev/cu.usbmodem123451 -v -u -U lfuse:w:0x1F:m
avrdude -c avrisp -p m32 -P /dev/cu.usbmodem123451 -v -u -U hfuse:w:0xC0:m
#ATMega328P Fuses
avrdude -c avrisp -p m328p -P /dev/cu.usbmodem123451 -v -u -U lfuse:w:0xFF:m
avrdude -c avrisp -p m328p -P /dev/cu.usbmodem123451 -v -u -U hfuse:w:0xD8:m
avrdude -c avrisp -p m328p -P /dev/cu.usbmodem123451 -v -u -U efuse:w:0xFF:m
Assuming these fuses were set correctly we can finally move on to flashing the bootloader.
From the root directory of USBaspLoader run the following command.
make flash
This should now flash the bootloader and you should get an output similar to the following, you have now successfully flashed the bootloader.
Wiring The USB Interface & Keyboard Matrix
As the circuit starts to add complexity in regards to layout I am going to move to schematic diagrams rather than Fritzing ones. This is due to the fact it is very difficult to scale component sizes and make them fit in Fritzing.
I have produced two different schematics for wiring the two different microcontrollers. Feel free to construct the physical layout of the circuits as you see fit but ensure the correct pins are used on the microcontrollers otherwise they will not function correctly. Click on the images to see the full SVG version of the schematics.
The above schematics outline how to wire the rest of the components used in the project, please follow them closely and check your wiring, also shown is how to wire a very basic keyboard matrix using two keys and two diodes (if you would like some further background on keyboard matrices and how to hand wire them please take a look at my hand wiring post).
Net Ports (the little labels like ROW1, COL1, SCK etc) are used to indicate how the different circuits are wired together without having to run wires, just match up the names.
Whilst the schematics show the programmer and how it is wired please feel free to disconnect this as it will not be required as the bootloader is already programmed. If you do not disconnect this please make sure it is not still plugged into your pc. Flashing QMK
Now everything is wired we can proceed to configuring and flashing QMK on the keyboard, once this is done you will have a functional prototype.
I am going to assume you have configured a working QMK build environment, if you have not yet done so please do this now before proceeding.
Copy the relevant files from my dev_scarlet build of QMK into the keyboards/ghostseven/scarlet folder in your QMK environment.
Depending on what microprocessor you are using change the keyboards/ghostseven/scarlet/rules.mk file accordingly.
#Both ATmega328P and ATmega32A have been tested and work with USBasp, please ensure you configure the right one.
#MCU = atmega328p
MCU = atmega32a
Issue the following command from the QMK root folder to compile the QMK firmware.
qmk compile -kb ghostseven/scarlet -km default
This should compile and produce an output similar to the following, you should end up with a ghostseven_scarlet_default.hex file in the QMK root folder, this is the firmware.
We now need to connect the circuit via the USB port (or cable) that has been wired to the microprocessor (do not connect the programmer USB). Before we do this we need to make sure we have attached the bootloader jumper or shorted pin PD6 to GND.
Plug the circuit in and open QMK Toolbox, you should see USBAsp device connected. If this does not appear double check your circuit wiring and make sure you have shorted PD6 to GND.
Select the firmware you created in the previous step and make sure the MCU is set to the correct microcontroller (ATMega32A or ATMega328P), then click flash. You should see a positive output similar to the following.
Unplug the circuit and disconnect the bootloader jumper (or wire between PD6 and GND). Reconnect the USB and you now have a working two button keyboard prototype!
Testing The Keyboard
By default the two buttons should present the letters s and d, if they do all is working fine!
Thoughts
Whilst in this form the keyboard is not really that useful or practical, it should give you a good grounding on how to build a larger or full size keyboard from scratch. I hope that you found this helpful and informative and it has give you the knowledge to take this further.
I want to add a few reference documents in this section that may be of use for anyone working on this project.