Firmware implementation notes - jkominek/piano-conversion Wiki

Inter-board protocol

The main board and the ADC boards communicate over 3Mbit/s full duplex RS485 links. While ADC boards will not normally need nearly that much bandwidth, maxing out the data rate was chosen to reduce communication latency. As a convenient side effect, it makes a significant amount of bandwidth available during calibration activities.

Initial setup

The main board will, after powering up the ADC board, check to see if the board is in factory bootloader mode. It will take actions as necessary to upgrade the ADC board firmware, and then command it to boot said firmware. Communications during this time will be covered by ST AN3155.


After successful boot, all messages will use HDLC asynchronous framing. This ensures both ends can determine message boundaries with ease, and detect errors.

Message types

This represents what we'll call version 0 of the protocol. There is no need for forwards/backwards compatibility, as the main board should be able to reflash the ADC boards to make them compatible with it. We'll try to avoid assigning message codes with a high bit of 1, to leave a stable space for anyone doing custom things in their firmware.

Message structure should probably be something like:

Many messages from the ADC board should contain the clock, which would just be a 32 bit count of systicks, wrapping around. This will let the main board adjust for any variation in the ADC board oscillator, since it just uses the built-in RC oscillator. It may either take those values and just apply a timing correction on its end, or compute adjusted low pass filter coefficients and send them back to the ADC board.

Firmware design

ADC Board

No RTOS here. Just bare C. Command handling via the UARTs and the USB port.

Main feature will be ADC and DMA configuration to sample all of the ADCs at a constant rate. In normal mode, the ADCs will all be low pass filtered, and the signals monitored according to whether they're on keys, or hammers, etc. In a calibration mode, one or more ADCs can have all of their data streamed off the board via UART or USB.

Messages to the board will configure the trip points / slopes / whatever for sensing, command high data rate mode for individual sensors, reboot the board, etc.

Main board

The main board will run FreeRTOS. The UART interrupts are to be considered the highest priority. They'll receive messages, roughly categorize them, and then dispatch them into FreeRTOS queues, for various threads to handle.

The highest priority thread will be the one handling MIDI generation. It will have to, internally, prioritize high-velocity note-ons, followed by low-velocity note-ons, and then note-offs at the lowest priority. Once that's done, it will dispatch MIDI messages to all of the currently active destinations. Networked MIDI sinks first, then UART-based MIDI sinks, then finally the USB output. (Reversed latency order) It should also dump all MIDI into a larger queue, so that it can be written to SD card, if that feature is active.

The next thread priority will concern itself with scanning the pedals, and making determinations about what pedal MIDI messages to send.

Beneath that will be threads for scanning/updating the various other pieces of hardware attached to the system, and writing the overall MIDI queue to SD card.

Some things to remember when implementing the firmware

Velocity and timing

This occurred to me after reading

We'll likely have the hammer velocity computed before the hammer would actually hit a string and begin to make noise, if only by some small fraction of a second. But when the hammer is moving slowly, our computation of velocity will finish with much more time before the impact, than if the hammer were moving quickly. We'll need to adjust for that, and send lower velocity messages slightly later.