rewrote lare parts of the RMK on ferris sweep article.
This commit is contained in:
		
							parent
							
								
									487b164e43
								
							
						
					
					
						commit
						a75393b5c6
					
				
					 1 changed files with 69 additions and 37 deletions
				
			
		| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
+++
 | 
					+++
 | 
				
			||||||
title = "Rust on the Ferris Sweep"
 | 
					title = "Rust on the Ferris Sweep"
 | 
				
			||||||
date = 2025-03-10T17:28:15+01:00
 | 
					date = 2025-03-25T17:28:15+01:00
 | 
				
			||||||
draft = true
 | 
					draft = true
 | 
				
			||||||
[cover]
 | 
					[cover]
 | 
				
			||||||
image = "keyboard-with-rust"
 | 
					image = "keyboard-with-rust"
 | 
				
			||||||
| 
						 | 
					@ -28,67 +28,99 @@ which made the journey to put it on my Ferris Sweep interesting enough to write
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Configuring the firmware
 | 
					## Configuring the firmware
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Unlike QMK, you don't clone the entire RMK repo, rather you make your own repo,
 | 
					Now, the setup between RMK and QMK is a bit different.
 | 
				
			||||||
which uses Rusts package manager, `cargo`, to depend on RMK.
 | 
					In QMK, you clone the entire QMK repo, make any keymap modifications you want,
 | 
				
			||||||
Setup of this repo is aided by the `rmkit` command line tool.
 | 
					and compile.
 | 
				
			||||||
 | 
					RMK, being written in a language with a decent package manager,
 | 
				
			||||||
I started by installing a few tools via cargo, running
 | 
					just has you make a repo from a small template that depends on the RMK crate.
 | 
				
			||||||
 | 
					RMK provides a tool, `rmkit`, to help you setup this repo.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					I started by installing `rmkit` and a few embedded tools via cargo, running:
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
cargo install rmkit flip-link elf2uf2-rs probe-rs-tools
 | 
					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.
 | 
					Then I ran `rmkit init` and answered a few questions about my keyboard,
 | 
				
			||||||
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.
 | 
					which generated my initial template.
 | 
				
			||||||
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.
 | 
					From there, I modified `.cargo/config.toml` to use `elf2uf2-rs`,
 | 
				
			||||||
 | 
					as my keyboard does not have an exposed debug header, which would be needed for `probe-rs`.
 | 
				
			||||||
 | 
					The docs mentioned I may have to modify a file called `memory.x`,
 | 
				
			||||||
 | 
					which defines the microcontrollers memory map,
 | 
				
			||||||
 | 
					but I found the template already had the correct memory map for the RP2040.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Then came the hard work, configuring `keyboard.toml`.
 | 
					### `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).
 | 
					That was the easy part done.
 | 
				
			||||||
 | 
					The next step was to configure a file called `keyboard.toml`.
 | 
				
			||||||
 | 
					This file is used by RMK to configure everything from the type of microcontroller we use,
 | 
				
			||||||
 | 
					to defining which pins on the microcontroller correspond to which keys,
 | 
				
			||||||
 | 
					and even configuring the initial keymap,
 | 
				
			||||||
 | 
					all at compile time.
 | 
				
			||||||
 | 
					Similar to QMK, RMK does provide you with the option to configure your keyboard using Rust code directly,
 | 
				
			||||||
 | 
					but I wasn't doing anything fancy enough to justify that.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
					The first part of the `keyboard.toml` contains some basic metadata about your keyboard,
 | 
				
			||||||
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)
 | 
					like its name, USB ID, and what microcontroller it uses.
 | 
				
			||||||
are for the Aurdino pro-micro pin names,
 | 
					I lifted all this info from [QMK's Ferris Sweep info.json](https://github.com/gabevenberg/qmk_firmware/blob/personal/keyboards/ferris/sweep/info.json) for consistencies sake.
 | 
				
			||||||
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.
 | 
					Then I had to configure the pin mappings, defining which pin correspond to each key (in the Ferris Sweeps case, as it is a direct wire, where each pin corresponds to exactly 1 key),
 | 
				
			||||||
My [keymap](https://github.com/gabevenberg/qmk_firmware/blob/personal/keyboards/ferris/keymaps/almost_default/keymap.json)
 | 
					or defining which pins correspond to rows and columns of the keyboard matrix (in the case of most larger keyboards.)
 | 
				
			||||||
is a bit complex, so it took some time to port.
 | 
					This proved more difficult than expected,
 | 
				
			||||||
It was mostly tedium rather than anything truly head scratching, however.
 | 
					as I planned to take the pin mappings from QMKs pin mapping configuration file,
 | 
				
			||||||
 | 
					the [`keyboard.json`](https://github.com/gabevenberg/qmk_firmware/blob/personal/keyboards/ferris/sweep/info.json).
 | 
				
			||||||
 | 
					However, it was unusable, as the `keyboard.json` gives pin mappings for a different microcontroller,
 | 
				
			||||||
 | 
					the ATmega32U4, specifically for the Aurdino Pro-Micro board.
 | 
				
			||||||
 | 
					QMK does some black magic at compile time in order to rewrite these pin mappings to their RP2040 equivalents,
 | 
				
			||||||
 | 
					but I was not able to figure out said magic in order to do the same by hand.
 | 
				
			||||||
 | 
					In the end, I cloned the [repo](https://github.com/davidphilipbarr/Sweep) for the Ferris Sweep itself and looked at the PCB design in Kicad,
 | 
				
			||||||
 | 
					Tracing where each pin went and cross referencing with the elite-pi (my specific RP2040 board) [usage guide](https://docs.keeb.io/elite-pi-guide) to get the pin number.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## `vial.json`
 | 
					Another thing I had to do was define how the 2 microcontrollers in each half of the keyboard communicate with each other,
 | 
				
			||||||
 | 
					and define the pins that are used in that communication.
 | 
				
			||||||
 | 
					Due to being a 'direct wire' design,
 | 
				
			||||||
 | 
					the Ferris Sweep only has one IO pin on each micro that's not dedicated to a key.
 | 
				
			||||||
 | 
					This means it has to use whats called 'half-duplex' UART,
 | 
				
			||||||
 | 
					where a single wire is used for 2 way communication.
 | 
				
			||||||
 | 
					Luckily, RMK supports this mode of communication through the RP2040's [PIO](https://www.raspberrypi.com/news/what-is-pio/) feature.
 | 
				
			||||||
 | 
					Unfortunately, this ability to use half-duplex over PIO is only on RMK's master branch,
 | 
				
			||||||
 | 
					and has not made it into a stable release as of this writing.
 | 
				
			||||||
 | 
					This simply means I had to do some fiddling in the `Cargo.toml` file to instruct cargo to fetch the latest commit from git, rather than getting the latest published version of the package.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Next, and the most complicated step, was creating a `vial.json`.
 | 
					After the *painful* process of tracing each pin and defining the pin mappings,
 | 
				
			||||||
 | 
					we can define the keymap.
 | 
				
			||||||
 | 
					My [keymap](https://github.com/gabevenberg/qmk_firmware/blob/personal/keyboards/ferris/keymaps/almost_default/keymap.json) is not especially fancy,
 | 
				
			||||||
 | 
					other than its extensive use of layers and tap-hold Keybinds.
 | 
				
			||||||
 | 
					(keybinds that do a different thing on being held down than they do on tapping them)
 | 
				
			||||||
 | 
					All the features I use are [well documented](https://haobogu.github.io/rmk/keyboard_configuration.html#layout) by RMK,
 | 
				
			||||||
 | 
					so while porting the keymap was tedious, it was not especially difficult or noteworthly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### `vial.json`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The next and most complicated step, was creating a `vial.json`.
 | 
				
			||||||
 | 
					This file is used by the [VIAL](https://get.vial.today/) software to allow you to remap your keyboard without re-flashing the microcontrollers,
 | 
				
			||||||
 | 
					and for 'reasons', the keyboard will fail to boot if your `vial.json` does not match your keymap.
 | 
				
			||||||
The JSON file [provided by the via project](https://github.com/the-via/keyboards/blob/master/src/ferris/sweep/sweep.json) was wrong,
 | 
					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.
 | 
					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/),
 | 
					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.
 | 
					and follow [vials guide](https://get.vial.today/docs/porting-to-via.html) to remake the `vial.json` in the right layout.
 | 
				
			||||||
 | 
					Ill be honest, I still don't fully understand what I was doing, I just messed around until it worked.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Flashing and troubleshooting
 | 
					## Flashing and debugging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Finally, I could flash my keyboard.
 | 
					Finally, I could flash my keyboard.
 | 
				
			||||||
I flashed it, and... It didn't work.
 | 
					I flashed it, and... It didn't work.
 | 
				
			||||||
The left hand side, the one plugged into USB, worked fine, all keys worked.
 | 
					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.
 | 
					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
 | 
					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,
 | 
					only used the RP2040's internal pull-up resistors,
 | 
				
			||||||
were insufficient for a baud rate of 115200.
 | 
					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,
 | 
					This was (temporarily) fixed by setting a lower baud rate in the RMK source code,
 | 
				
			||||||
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 for the long term, I've made a [PR](https://github.com/HaoboGu/rmk/pull/291) mirroring [QMKs solution](https://github.com/qmk/qmk_firmware/blob/6d0e5728aa61b442885d48caf49d29e5c60e8197/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c#L133) to this problem.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
But, after all that, I had a Ferris Sweep running Rust,
 | 
					But, after all that, I had a Ferris Sweep running Rust,
 | 
				
			||||||
just as the silkscreen demands.
 | 
					just as the silkscreen demands.
 | 
				
			||||||
Granted, until the PR gets merged and a new release is cut,
 | 
					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.
 | 
					its running a modified version of RMK from my own fork, but its still Rust.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The final firmware repo is [here](https://github.com/gabevenberg/ferris-sweep-rmk),
 | 
					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,
 | 
					if you want to use it for your own RP2040, wired Ferris Sweep,
 | 
				
			||||||
| 
						 | 
					@ -98,7 +130,7 @@ or just want an example to help you along.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
I then proceeded to use RMK for a few tasks, including writing this article.
 | 
					I then proceeded to use RMK for a few tasks, including writing this article.
 | 
				
			||||||
It did not feel the exact same as QMK,
 | 
					It did not feel the exact same as QMK,
 | 
				
			||||||
I think some of the timings on tap-hold and debouncing might be different,
 | 
					I think some of the timings on tap-hold and key 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),
 | 
					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.
 | 
					it was a very serviceable keyboard firmware.
 | 
				
			||||||
Obviously, being a much newer project than QMK,
 | 
					Obviously, being a much newer project than QMK,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue