Hacking the NuPhy Air60 keyboard: part 2

It's time I wrote an update on this project again!

Since my last update, I've been working on bootstrapping a development toolchain and producing a minimal firmware where I could initialize and test the core features of the SH68F90A along side of booting back into the ISP bootloader (otherwise the keyboard will become unprogramable via USB).

I am happy to say that I managed to do that, and released everything I have done so far on github.

V2 has already been released§

Before I get into what I managed to do, I should note that NuPhy have recently released V2 of the Air60 and Air75 keyboards. These new versions are powered by ARM MCUs instead of the 8051-based SH68F90A and comes with QMK support out of the box.

I originally started this project, because I wanted to have QMK-like firmware on this keyboard, but since these news have come out, it has becomes purely a learning experience.

If you're interested in this project because of the possibility of running QMK on a Air60 or Air75 I really recommend you to just get the new version of these keyboards!

But anyway, on to the toolchain...

Embracing Open-Source Tooling§

A core principle of this project is to use all open source tooling to build the firmware. That's why I am using SDCC here, instead of the proprietary Keil C51 which seems to be a standard for developing for 8051 MCUs.

I have SDCC configured with the smallest device size, so that all variables are put onto the IRAM, unless they are annotated differently (__xdata, __code, etc.).

The firmware size is 61440 leaving the remaining 4096 bytes untouched for the ISP bootloader.

When the ISP bootloader flashes the given firmware the finalisation routine looks for a ljmp instruction at 0xeffb and if considers it valid, it will place it at 0x0000, otherwise it will place a ljmp to 0xf000 (back to the bootloader itself). I gather that this is a mechanism to prevent corrupted firmware from being written to the device and then never being able to boot back into itself. Though, if you write non-corrupted, but non-working firmware, you won't be able to boot back into the ISP and you will need a programming device, like the sinolink. Be careful!. (Did I mention this is an incredibly brickable device?)

Anyway, because of this reason, I have added preboot.asm which places this ljmp that points to the start of the user firmware at the previously mentioned place.

Diving into SH68F90A's Capabilities§

The SH68F90A on the Air60 (and other Air models) come with the following code-options set. Since I would like to be able to load both the stock firmware and my own firmware through USB, I can't change these values to something else, but that also means that my firmware needs to do some specific initialization for the functionality these options require.

The first thing that needs to be setup is the 24MHz SYSCLK infrastructure, this involves initializing the PLL and then swiching SYSCLK to use the clock signal that's coming out of it, instead of the 128kHz OSC. link

Next, since we have the watchdog enabled, we need to configure the watchdog to use a comfortable overflow amount and then make sure that our firmware clears the watchdog timer before it overflows. (I wasn't able to test the WDT RESET flag, that would've helped in making this firmware a little bit less brickable). link

USB signaling also requires 3.3V, so we also need to initialize the internal voltage regulator. link

Here we're already at a point where we have done enough initialization for the ISP bootloader program to work, so already, we could jump into it if we wanted link.

GPIO setup is fairly straightforward, we setup the inputs and outputs, pull-ups according to the key matrix rows (input) and columns (output) and the RGB leds per row, per column. link

Lastly, a pretty important tool for debugging (in absence of on-chip debugging via USB) is getting UART to work. This is fairly straightforward, and explained ok-ish in the datasheet, but the macros I added to calculate SBRT and SFINE values based on the desired baudrate should make it more easy to work with. Also, since the default (TXD, RXD) UART pins are harder to reach, I am setting the MAPPING register to 0x5a to use the M_TXD and M_RXD pins instead, because they are also connected to the columns and the removable switch sockets, plugging in header cables for my USB<->SERIAL device, though it should be noted that PWM signals will interfere with the UART signals and you might get garbage in your serial output.

uart connected through 5th and 6th key columns

hello world printed on screen

On the horizon§

Moving forward I will be continuing work on sh68f90a-experiments focusing on getting the following functionalities to work:

  1. Key Matrix
  2. PWM + RGB LED Matrix
  3. USB (it's a working keyboard!)
  4. Wireless (stretch-goal)

Stay tuned for more updates!