While discussing Dan Luu’s keyboard latency experiments I realized that I had never tested my keyboard’s latency. I use a custom keyboard I designed and built, but when I wrote the firmware I was focused on getting it working and didn’t pay any attention to latency. When I took a look at the source code and immediately saw a 10ms delay that was there for no other reason than paranoia, I knew I was in for some fun.
After a bunch of measuring, finding and squashing sources of latency, I managed to improve the latency of the main loop from 30 milliseconds to 700 microseconds. I then added a feature that changed the colour of the keyboard’s RGB LEDs on every key press so that I could use the Is It Snappy app with my iPhone’s high speed camera mode to do some latency testing.
The first thing I found was that with my improved firmware the end to end latency of typing a character in Sublime Text and XCode 9 near the top of my Macbook display is around 42ms1. This is pretty good, but the astonishing thing is that it means that before I fixed the firmware my keyboard used to account for almost half of my end-to-end typing latency. This is measuring from the LED colour change so it doesn’t count the around 15ms1 according to my testing from starting to press one of my keys the switch activating.
I also tested my Macbook keyboard, as well as a few older low speed USB Apple keyboards, and found that they had around 67ms1 of end-to-end latency, measuring from when the switch was fully depressed while hitting the key as fast as I could. I suspect part of the reason for this is that these keyboards only poll at 8ms and 10ms intervals according to USB Prober (an old Apple dev tool), whereas the Teensy in my custom keyboard polls every millisecond. According to Dan’s post newer Apple external keyboards also poll at 1000hz.
Note that the 700us main loop doesn’t translate into 700us switch-to-USB latency, since the USB transfer is done asynchronously via DMA by the Teensy’s USB controller when it is polled, which happens at 1000hz.
It’s interesting that I used my keyboard for 3 years without noticing that it added 30ms of latency. I have a few guesses why:
Anyhow here’s how I managed to bring the latency down from 30ms to 700us:
The specifics are only relevant to other people building keyboard firmware, especially the fast i2c one which I don’t think most ErgoDox firmwares use. But I think it’s interesting to see how easy it was to improve the latency of software that wasn’t designed for it with only a few hours work.