123 lines
7.5 KiB
Markdown
123 lines
7.5 KiB
Markdown
+++
|
|
title = "Rust on the Ferris Sweep"
|
|
date = 2025-03-10T17:28:15+01:00
|
|
draft = true
|
|
[cover]
|
|
image = "keyboard-with-rust"
|
|
+++
|
|
|
|
The other day, I stumbled upon [RMK](https://github.com/haobogu/rmk),
|
|
a keyboard firmware written in Rust.
|
|
Given that my [Ferris Sweep](../ferris-sweep-keyboard/) has a Ferris the crab logo on the silkscreen,
|
|
it felt only fitting that I flash it with RMK.
|
|
|
|
Since I first built it, my Ferris Sweep has been running [QMK](https://qmk.fm/),
|
|
a very mature C-based keyboard firmware.
|
|
QMK is a great project, and doing basic keymaps for an already-supported keyboard is straightforward and well-documented.
|
|
However if you are designing your own keyboard, or want to use certan advanced QMK features,
|
|
you wont be able to use QMKs JSON-based 'data driven' features.
|
|
Instead, you will have to use its C macro based configuration,
|
|
which can be daunting and may require understanding QMKs complex build system.
|
|
|
|
RMK is a much newer project than QMK.
|
|
QMK provides premade configurations for over 1,000 keyboards,
|
|
allowing you to build someone else's design and get straight to designing a keymap,
|
|
without having to fuss about with matrices or pin mappings.
|
|
RMK has no such definitions, just documentation of how to write them and a few example projects,
|
|
which made the journey to put it on my Ferris Sweep interesting enough to write about.
|
|
|
|
## Configuring the firmware
|
|
|
|
Unlike QMK, you don't clone the entire RMK repo, rather you make your own repo,
|
|
which uses Rusts package manager, `cargo`, to depend on RMK.
|
|
Setup of this repo is aided by the `rmkit` command line tool.
|
|
|
|
I started by installing a few tools via cargo, running
|
|
|
|
```
|
|
cargo install rmkit flip-link elf2uf2-rs probe-rs-tools
|
|
```
|
|
|
|
Then I ran `rmkit init` and answered a few questions about my keyboard, which generated a template for me to further modify.
|
|
I modified `.cargo/config.toml` to use `elf2uf2-rs` as documented in the templates README, as I cant exactly set up a debug link on an already assembled keyboard.
|
|
The docs say I need to modify the `memory.x` file for my microcontroller, but I found the `rmkit` tool had already set it with the right contents.
|
|
|
|
Then came the hard work, configuring `keyboard.toml`.
|
|
I followed [the docs](https://haobogu.github.io/rmk/keyboard_configuration.html),
|
|
carefully started porting my [Ferris Sweep layout](https://github.com/gabevenberg/qmk_firmware/blob/personal/keyboards/ferris/keymaps/almost_default/keymap.json) to the `keyboard.toml`.
|
|
|
|
First off, for the keyboard metadata, I simply took from [QMK's Ferris Sweep info.json](https://github.com/gabevenberg/qmk_firmware/blob/personal/keyboards/ferris/sweep/info.json).
|
|
|
|
Then for the tricky part. We have to define our pin mappings using the peripheral names as [defined by embassy](https://docs.embassy.dev/embassy-rp/git/rp2040/struct.Peripherals.html)
|
|
This is hard because the QMK mappings given in the [keyboard.json](https://github.com/qmk/qmk_firmware/blob/master/keyboards/ferris/sweep/keyboard.json)
|
|
are for the Aurdino pro-micro pin names,
|
|
and I wasn't able to figure out what magic QMK does to convert those into the RP2040 [Elite-pi](https://keeb.io/products/elite-pi-usb-c-pro-micro-replacement-rp2040) equivalents.
|
|
In the end, I just cloned the Ferris sweep [repo](https://github.com/davidphilipbarr/Sweep) and opened the files in Kicad,
|
|
cross referencing the schematic with the elite-pis [usage guide](https://docs.keeb.io/elite-pi-guide)
|
|
One stumbling block is that the Ferris sweep ran out of pins to use full-duplex UART, and therefore only uses half-duplex.
|
|
To solve this, RMK supports (only on the RP2040) a PIO driver for half duplex, gated behind a crate feature in `cargo.toml`.
|
|
With it, we can set our Tx and Rx pins to the same pin.
|
|
In order to do this, however, I had to set the `rmk` dependency to a direct link to the Github repo,
|
|
because as of the time of writing, the `rp2040_pio` feature had not made it into a release.
|
|
|
|
After the painstaking process of tracing all the pins and putting them in the matrix, we can define the keymap.
|
|
My [keymap](https://github.com/gabevenberg/qmk_firmware/blob/personal/keyboards/ferris/keymaps/almost_default/keymap.json)
|
|
is a bit complex, so it took some time to port.
|
|
It was mostly tedium rather than anything truly head scratching, however.
|
|
|
|
## `vial.json`
|
|
|
|
Next, and the most complicated step, was creating a `vial.json`.
|
|
The JSON file [provided by the via project](https://github.com/the-via/keyboards/blob/master/src/ferris/sweep/sweep.json) was wrong,
|
|
as it laid out the keyboard as a 8x5, rather than a 4x10 that I had done in RMK.
|
|
So I had to take that file, load it into the [keyboard layout editor](https://www.keyboard-layout-editor.com/),
|
|
and follow [vials guide](https://get.vial.today/docs/porting-to-via.html) to remake the `vial.json` in the right layout.
|
|
|
|
## Flashing and troubleshooting
|
|
|
|
Finally, I could flash my keyboard.
|
|
I flashed it, and... It didn't work.
|
|
The left hand side, the one plugged into USB, worked fine, all keys worked.
|
|
But the right hand side, connected to the main by TRRS, did nothing.
|
|
A day or 2 of investigation later revealed that the half-duplex serial implementation
|
|
only used the RP2040's internal pull-up resistors, which for my keyboard and TRRS cable,
|
|
were insufficient for a baud rate of 115200.
|
|
This was (temporarily) fixed by setting a lower baud rate,
|
|
but for the long term, I've made a PR mirroring [QMKs solution](https://github.com/qmk/qmk_firmware/blob/6d0e5728aa61b442885d48caf49d29e5c60e8197/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c#L133) to this problem. (Ill update this article when it gets merged.)
|
|
|
|
But, after all that, I had a Ferris Sweep running Rust,
|
|
just as the silkscreen demands.
|
|
Granted, until the PR gets merged and a new release is cut,
|
|
its running a modified version of RMK from my own repo, but Rust is Rust.
|
|
|
|
The final firmware repo is [here](https://github.com/gabevenberg/ferris-sweep-rmk),
|
|
if you want to use it for your own RP2040, wired Ferris Sweep,
|
|
or just want an example to help you along.
|
|
|
|
## Using RMK.
|
|
|
|
I then proceeded to use RMK for a few tasks, including writing this article.
|
|
It did not feel the exact same as QMK,
|
|
I think some of the timings on tap-hold and debouncing might be different,
|
|
but, apart from a few repeated keys (which should be fixed once configurable debouncing [lands](https://github.com/HaoboGu/rmk/issues/289),
|
|
it was a very serviceable keyboard firmware.
|
|
Obviously, being a much newer project than QMK,
|
|
it has not yet implemented some of the more advanced features QMK has,
|
|
such as support for displays, per-key RGB, or pointing devices.
|
|
The next release is focusing on input devices,
|
|
so in the future RMK will also support keyboards with encoders and pointing devices like trackballs and touchpads.
|
|
|
|
## Final thoughts
|
|
|
|
Due to the difficulty I had in setting up RMK,
|
|
I would not recommend it to anyone who is not already familiar with configuring another keyboard firmware,
|
|
and you should have at least some knowledge of microcontrollers, such as how to figure out your keyboards pinout.
|
|
However, if you are interested and have some prior experience, it has some really cool ideas,
|
|
such as the use of an async runtime in a microcontroller (thanks to embassy),
|
|
and compile time parsing of its `keyboard.toml` file with a proc-macro to generate code for the firmware without forcing the user to write Rust.
|
|
It is also a great example of a complex Rust codebase using Embassy.
|
|
|
|
As for myself, I plan on continuing to use RMK for my Ferris Sweep,
|
|
and will probably use it for any other keyboard I build that it supports.
|
|
I also plan on continuing to contribute to the project, fixing issues as I find them.
|