Posts tagged as firmware
16nx, and the value of giving work away
27 January 2025In September this year, I released a new version of the open source 16-fader MIDI controller I maintain - 16nx. This was a complete redesign of the hardware of the device, and as a result, also a completely new firmware.
Redesigning the device was in one sense, a necessity. 16n - the original faderbank - was designed around the Teensy 3.2, a microcontroller development board that had effectively become end-of-life, and was no longer available. Given that, it was impossible to make the device. If it was to be buildable again, it would need designing around a new part.
If I was going to take on the necessity of a redesign, I may as well also take up the opportunity to make changes or improvements, particularly based on what I’d learned in the years since I’d made those original designs.
I eventually released the project in September 2024 under the same open-source licences as its predecessor. As well as examining the changes in this new version, I wanted to write a little about why I’d give my work away.
The easiest approach to replacing the Teensy 3.2 would be to use its successor, the Teensy 4 - mechanically identical, it’d just take a software rewrite. But it’s vastly overpowered for the relatively simple tasks the 16n does.
And I didn’t really want a drop-in replacement. I was going to redesign the electronics anyway; I had a few goals for them:
- update the analog electronics to improve the control voltage (CV) outputs.
- get rid of the horizontal jacks on the front and rear, to make it easier to push flat against stuff. Connections would just be on the left, right, and top surface.
- change the USB connector to a more robust USB-C connector.
And if I’m redesigning the analog circuitry, maybe a more thorough redesign was in order.
Since I’d designed 16n, small-scale overseas electronics manufacture had become even easier. Assembly of boards, particularly via pick-and-place for surface mount components, was now very accessible and relatively affordable.
The original 16n was a combination of through-hole and large surface-mount components, designed for manual assembly. But in reality, even the chunky surface-mount I’d chosen to go with was fiddly for many people assembling it; the number of bugs that came down to mis-soldered resistors was quite high.
So I had an idea: perhaps all the electronics, including the microcontroller, could be on the board, and assembled in a factory. Save the manual soldering for the chunky through-hole components DIYers are happiest with, and let a pick-and-place do the rest - with cheaper, smaller components. (Tom at Music Thing Modular had already had success with this “easy-bake” approach; it turned out people don’t have to make absolutely every part of something to still get the pleasure of making something).
The project could still be open source, but for people who didn’t want to wrestle with PCBA, I could… sell these “motherboards” myself - maybe to individuals, but perhaps, more likely, to the small manufacturers who assembled faderbanks for clients.
I was attracted to this idea: the project would be easier to assemble, more robust (and less prone to assembly error by hobbyists), and I might see some ROI on the project I’d put so much effort into.
I’d base this new board around the RP2040 chip I was using for so much work now - £1 for the bare chip, a dollar or two for the rest of the required components. It’s far more powerful than low-end 8-but Arduinos, not quite as meaty as a Teensy 3.2 or 4.0, but more powerful than a Teensy LC. And its UF2 bootloader - letting users update their firmware just by copying a file on their desktop - would make end-user firmware upgrades even easier than before, a huge accessibility win.
I wrote the firmware the native C++ Pico SDK. The impact for the end-user was low - they’d get UF2s to upload - but for me was high, letting me work with a powerful toolset and a genuine debugger. I even added a mini JST connector to the board, designed to connect to the official Pico Debug Probe. It was a great help in developing the project, and felt like a good gesture to end users - you should try this approach, there’s a socket ready for you, it works with the official tools.
The trade-off to moving to Pico SDK was that the firmware would get a little less accessible for the hobbyist market. The Teensy project was written in Arduino. When I was working on that, I believed that the more people could contribute to the project, the better, so using a framework popular with makers was important. What I found out was that whilst a lot of people want to contribute bug reports or feature requests, far fewer of them wish to hack on them. No matter how much I would write, sincerely, “that sounds like a great first issue - why don’t you look at that?”, I received relatively few pull requests or forks of the firmware. So I decided to stop making choices about platforms based on what other people might do in the future, and instead choose what I thought was best.
In the end, the assembled 16nx main boards, excluding jacks, switches, and faders, would cost about a third of the equivalent parts - unassembled - for the 16n. And that’s before you consider any savings in terms of how much faster it is to assemble a 16nx - there’s no longer about 60 surface-mount chips and resistors to put on the board by hand.
The electronics redesign took a good while. 16n had been designed inside EAGLE, which was now also end-of-life, and had been subsumed inside Fusion 360 - a good product, but hardly hobbyist-budget. An open source tool made sense for an open source project, so I designed it all inside KiCad - my ECAD tool of choice - keeping the same physical form factor. The layout took a few passes to get right, mainly down to all the routing around the MCU:
The 16nx PCB layout around the RP2040
16n at the time was the most complex thing I’d ever routed. It’s a sign of where I’ve gone since that 16nx isn’t - just - but I’m still very proud of the electronics work on it.
I also spent some time messing around with logos, designing things that would silkscreen nicely with a little inspiration from 90s music hardware…
A render of the board reverse
With the firmware written, and test boards on my desk, it was time to bring it into the world.
And then… I froze.
I’d fixated on the “selling populated boards” idea as a way of generating a bit of revenue without making “full kits”, or going near sales and support of finished products. I know what I enjoy - and what I don’t - and I find support for end-users stressful (whether or not the support overhead actually materialises - the idea alone gets to me). This other approach would be less stressful than selling complete products, but still find a way for generating ROI.
But I kept getting stuck in a train of thought:
- I don’t want to do customer support at all, really. It’s bad for my brain and stress levels. Even supporting the assemblers/manufacturers I sell to might still be a pressure I wouldn’t like.
- I know enough to know I probably ought to do some form EM testing, even for a bare board. EM testing in the hobbyist industry is uneven, but do I want to take the risk of working out if I’m selling a “partial assembly” or not, and do I want to sell it on, knowing that? Conversely: will EM testing knock any margin on the head?
- This is beginning to look like a lot of work.
- What did I want out of this again?
And the answer is: I want it cheaper, and easier to make, and back in the world again for music makers, and actually, making a small amount of money probably wasn’t my highest priority.
Making a small amount of money would be more expensive, probably, than making no money.
The project was always going to be open source - it’s under an attribution licence that allows commercial derivatives. I wasn’t choosing between an open-source release, and a commercial one. But I was choosing between revenue, and not.
On my birthday, in September 2024, I published the updated 16n website, and made the first open-source release. I igave up on the idea of selling anything; easier to let people who wanted one find a way to bring it to life, just as they had done before. My main goals were met: the faderbank was back in the world, it was now possible to make one again, and it was a bit better designed, even if it did nothing new. It was quite satisfying to quell any “Gear Acquisition Syndrome” with the simple lines in the documentation:
If you already have a 16n that works: you will gain nothing by upgrading. If, however, you’re looking to acquire a faderbank in 2024+, then 16nx is your best route to do so.
There’s a long thread about it on Lines, the spiritual home of the project, and it was once again exciting to see people bringing them to life without me and enjoying the experience. That’s not nothing; I’m proud and buoyed by the response to the project.
It’s not really a “loss” in the slightest. I’ve got a great deal out of the project over the years:
- developing skills and techniques, even within tools I know well.
- facilitating new paying work: the recent Lunar hardware project wouldn’t have been doable without this, and made about as much as I’d have made trying to sell ~100 motherboards.
- building new clients: 16n led to a custom commission from a US composer that ended being a lovely project and a good working relationship.
- the value, to me, of contributing back to a community I care about of musicians and DIY makers.
When I made the decision to give it away, what I felt was relief. It turned out I was agonising over a commercial idea that wasn’t really worth enough to me, and giving that up freed me up in a lot of ways. The final release was smooth and straightforward after that.
Since launch, I’ve largely just let people get on with making them, dropping into Github or forum threads to offer some advice, and in the first week of the year, doing some point releases - upgrading the editor to Svelte 5, building a reasonably sized new feature that’s been requested and getting that ready to launch.
It continues to be a favourite project, and I’m glad that I’ve found a way to keep it going for more years to come, in a way I’m happy with.
-
I recently released the 2.0.0 firmware for 16n, the open-source fader controller I maintain and support. This update, though substantial, is focused on one thing: improving the end-user experience around customisation. It allows users to customise the settings of their 16n using only a web browser. Not only that, but their settings will now persist between firmware updates.
I wanted to unpick the interaction going on here - why I built it and, in particular, how it works - because I find it highly interesting and more than a little strange: tight coupling between a computer browser and a hardware device.
To demonstrate, here’s a video where I explain the update for new users:
Background
16n is designed around a 32-bit microcontroller - Paul Stoffregen’s Teensy - which can be programmed for via the popular Arduino IDE. Prior to version 2.0.0, all configuration took place inside a single file that the end-user could edit. To alter how their device behaved, they had to edit some settings inside
config.h
, and then recompile the firmware and “flash” it onto the device.This is a complex demand to make of a user. And whilst the 16n was always envisaged as a DIY device, many people attracted to it who might not have been able to make their own have, entirely understandably, bought their own from other makers. As the project took off, “compile your own firmware“ was a less attractive solution - not to mention one that was harder to support.
It had long seemed to me that the configuration of the device should be quite a straightforward task for the user; certainly not something that required recompiling the firmware to change. I’d been planning such a move for a successor device to 16n, and whilst that project was a bit stalled, the editor workflow was solid and fully working. I realised that I could backport the editor experience to the current device - and thus the foundation for 2.0.0 was laid.
MIDI in the browser
The browser communicates with 16n using MIDI, a relatively ancient serial protocol designed for interconnecting electronic musical instruments (on which more later). And it does this thanks to WebMIDI, a draft specification for a browser API for sending and receiving MIDI. Currently, it’s a bit patchily supported - but there’s good support inside Chrome, as well as Edge and Opera (so it’s not just a single-browser product). And it’s also viable inside Electron, making a cross-platform, standalone editor app possible.
Before I can explain what’s going on, it’s worth quickly reviewing what MIDI is and what it supports.
MIDI: a crash course
MIDI - Musical Instrument Digital Interface describes several things:
- a protocol for a serial communication format
- an electronic spec for that serial communication
- a set of connectors (5-pin DIN) and how they’re wired to support that.
It is old. The first MIDI instruments were produced around 1981-1982, and their implementation still works today. It is somewhat simple, but really robust and reliable: it is used in thousands of studios, live shows and bedrooms around the world, to make electronic instruments talk to one another. The component with the most longevity is the protocol itself, which is now often transmitted over a USB connection (as opposed to the MIDI-specific DIN-connections of yore). “MIDI” has for many younger musicians just come to describe note-data (as opposed to audio-data) in electronic music programs, or what looks like a USB connection; five-pin DIN cables are a distant memory..
The serial protocol consists of a set of messages that get sent between MIDI devices. There are relatively few messages. They fall into a few categories, the most obvious of which are:
- timing messages, to indicate the tempo or pulse of a piece of music (a bit like a metronome), and whether instruments should be started, stopped, or reset to the beginning.
- note data: when a note is ‘on’ or ‘off’, and if it’s on, what velocity it’s been played it (the spec is designed around keyboard instruments)
- other non-note controls that are also relevant - whether a sustain pedal is pushed, or a pitch wheel bent, or if one of 127 “continuous controllers” - essentially, knobs or sliders - has been set to a particular value.
16n itself transmits “continuous controllers” - CCs - from each of its sliders, for instance.
There’s also a separate category of message called System Exclusive which describe messages that an instrument manufacturer has got their own implementation for at the device end. One of the most common uses for ‘SysEx’ data was transmitting and receiving the “patch data” of a synthesizer - all the settings to define a specific sound. SysEx could be used to backup sound programs, or transmit them to a device, and this meant musicians could keep many more sounds to hand than their instrument could store. SysEx was also used by early samplers as a slow way of transmitting sample data - you could send an audio file from a computer, slowly, down a MIDI cable. And it could be also used to enable computer-based “editors”, whereby a patch could be edited on a large screen, and then transmitted to the device as it was edited.
Each SysEx message begins with a few bytes for a manufacturer to identify themselves (so as not to send it to any other devices on the MIDI chain), a byte to define a message number, and then a stream of data. What that data is is up to the manufacturer - and usually described somewhere in the back pages of the manual.
Like the DX7 editors of the past, the 16n editor uses MIDI SysEx to send data to and from the hardware.
How the 16n editor uses SysEx
With all the background laid out, it’s perhaps easiest just to describe the flow of data in the 16n editor’s code.
- When a user opens the editor in a web browser, the browser waits for a MIDI interface called 16n to connect. It hears about this via a callback from the WebMIDI API.
- When it finds one, it starts polling that connection with a message meaning give me your config!
- If 16n sees a message aimed at a 16n requesting a config, it takes its current configuration, and emits it as a stream of hex inside a SysEx message: here is my config.
- The editor app can then stop polling, and instantiate a
Configuration
object from that data, which in turn will spin up the reactive Svelte UI. - Once a user has made some edits in the browser, they choose to transmit the config to the device: this again transmits over SysEx, saying to the device: here is a new config for you.
- The 16n receives the config, stores it in its EEPROM, and then sets itself to use that config.
- If a 16n interface disconnects, the WebMIDI API sends another callback, and the configuration interface dismantles itself.
Each message in italics is a different message ID, but that’s the limit of the SysEx vocabulary for 16n: transmitting current state, receiving a new one, and being prompted to send current state.
With all that in place, the changes to the firmware are relatively few. Firstly, it now checks if the EEPROM looks blank, at first boot, and if it is, 16n will itself store a “default” configuration into EEPROM before reading it. Then, there’s just some extra code to listen for SysEx data, process it and store it on arrival, and to transmit it when asked for.
What this means for users
Initially, this is a “breaking change”: at first install, a 16n will go back to a ‘default’ configuration. Except it’s then very quick to re-edit the config in a browser to what it should be, and transmit it. And from that point on, any configuration will persist between firmware upgrades. Also, users can store JSON backups of their configuration(s) on their computer, making it easy to swap between configs, or as a safeguard against user error.
The new firwmare also makes it much easier to distribute the firmware as a binary, which is easier to install: run the loader program, drag the hex file on, and that’s that. No compilation. The source code is still available if they want it, but there’s no need to install the Arduino IDE to modify a 16n’s settings.
As well as the settings for what MIDI channel and CC each fader transmits, the editor let users set configuration flags such as whether the LED should blink on data transmission, or how I2C should be configured. We’ve still got some bytes free to play with there, so future configuration options that should be user-settable can also be extracted like this.
The 16n editor showing an available firmware update Finally, because I store the firmware version inside the firmware itself, the device can communicate this to the editor, and thus the editor can alert the user when there’s a new firmware to download, which should help everybody stay up-to-date: particularly important with a device that has such diverse users and manufacturers.
None of this is a particular new pattern. Novation, for instance, are using this to transfer patch settings, samples, and even firmware updates to their recent synthesizers via their Components tool. It’s a very user-friendly way of approaching this task, though: it’s reliable, uses a tool that’s easy to hand, and because the browser can read configurations from the physical device, you can adjust your settings on any computer to hand, not just your own.
I also think that by making configuration an easier task, more people will be willing to play with or explore configuration options for their device.
The point of this post isn’t just to talk about the code and technology that makes this interaction possible, though; it’s also to look at what it feels like to use, the benefits for users, and interactions that might be possible. It’s an unusual interaction - perhaps jarring, or surprising - to configure an object by firing up a web browser and “speaking” directly to it. No wifi to set up, no hub application, no shared password. A cable between two objects, and then a tool - the browser - that usually takes to the wireless world, not the wired. WebUSB also enables similar weird, tangible interactions, in a similar way to the one I’ve performed here, but with a more flexible API.
I think this an unusual, interesting and empowering interaction, and certainly something I’ll consider for any future connected devices: making configuration as simple and welcoming as possible, using tools a user already understands.