Using a CAN bus to distribute MIDI messages in a modular synthesizer

Similar projects worth following
This is a prototype for a bus connection to distribute MIDI messages in modular systems like eurorack.

The project was originally intended as an entry to the 2021 hackaday Designlab contest, but university was kicking my ass so I could not make it presentable in time.

This is a proposed MIDI transport with support for MIDI 2.0. These specifications may not be final.

Hardware specs:

  • 4-wire flat ribbon-cable
  • MicroMatch or WR-MM connector
  • Outermost pins of the connector is connected to an RC filter
  • Selectable end-termination on every module
  • CAN FD controller and transceiver

End termination can be enabled on a module with a DPDT switch, or with jumpers. And the terminated position should be clearly marked on the PCB. Split termination is preferred to minimize EMR.

Communication specs:

  • Bus speed is 1MHz: TSEG1 = 600ns, TSEG2 = 300ns, Sync = 100ns.
  • 11-bit standard ID, where every device on the bus should have a unique ID
  • MIDI messages are sent over the bus using the UMP format

The ID field of the CAN frame contains the ID of the transmitting device for arbitration purposes. These IDs should be randomly generated. Also, the device should generate a new ID if it receives a frame with its own ID.


A divider for the CV16 led matrix to prevent bleed between the pixels

Standard Tesselated Geometry - 217.07 kB - 10/22/2021 at 12:52


  • Project update

    David07/25/2022 at 11:32 0 comments

    I have been making some progress this past month, mostly on the USB module. I'm trying to verify the current hardware before doing another revision of the PCBs. So I also got the SAM-BA bootloader from Microchip working on one of the modules.

    For the USB stack I ended up using the TinyUSB library because it has both audio and MIDI device drivers ready. It took a while to get it working even with the library, but it is now mostly working in device mode. I have some issues with the audio streaming, the left and right channels are constantly switching and the sample rate is too fast. The channel switching is probably a firmware issue, it is quite annoying as it degrades the audio quality. I have tried using separate DMA channels for each audio channel and checking the word select signal, to no avail. The fast sample rate is caused by an inaccuracy of the internal oscillator, so that's another reason to add an external crystal.

    I also made a fork of the library to attempt implementing host mode on the SAMD21 controller. Luckily the library handles all the high-level USB stuff, and "only" a set of functions must be defined to let it interface with the hardware. I got it partially working with the host hid_example. When the PS4 controller is directly connected to the MCU it works, but if it is connected via a USB hub the device will stall forever. The code also gets stuck in a wait function occasionally because the frame number does not increment when no device is connected, but it can recover from this state. My fork is currently limited to 8 endpoints, but the SAMD21 supports virtual pipes to increase this. I will probably implement this later. The host stack is apparently a work in progress, so I will wait a bit to see if it improves.

    This was the peak debugging setup. Picoscope to probe the physical I2S signals, In-circuit debugger to read internal data. A loopback connection from DAC to ADC and a speaker on one of the channels.

    Next, I will probably improve the firmware of the CV module.

  • MIDI A2B

    David07/25/2022 at 10:57 0 comments

    During my break from this project, the MIDI association announced a new transport supporting MIDI 2.0. The A2B bus is capable of transferring multiple channels of audio over a single UTP cable while also delivering power and additional data. This is interesting because it could replace the CAN bus used in this project while also providing audio streaming between nodes.

    The full specs of this transport have not been published as I'm writing this, so some things are unclear. The announcement says a maximum of 17 nodes are supported with sub-buses, is that a hard limit? Can a sub-bus have sub-buses? The MIDI announcement says SPI will be used for MIDI, but none of the A2B transceivers have an SPI interface.

    Anyway, I will continue using the CAN bus at least until the A2B transport is better defined.

  • Current state of the project

    David02/18/2022 at 21:17 0 comments

    This project was originally intended as an entry in the 2021 hackaday Designlab contest. It was totally too ambitious, given that university was taking up most of my time. I am currently working on (or procrastinating from) my master's thesis, so I won't have time to continue this project until July. But I want to put it out there, even in its current state. Unfortunately I haven't made any demo of the modules yet.

    I do feel like the name is a bit too generic, since people may refer to any MIDI connection as a "MIDI bus". Also, there are a couple other projects with the name. Maybe the name should be changed to CAN-MIDI, or Modular MIDI (M2IDI), or something else.

    Firmware status:

    The code is a mess. And I have not used a bootloader so far, because the bootloaders need a button to activate.

    CV module: Turns out programming flexible firmware is difficult, so the menu does not work yet. But most of the other features are present to some degree.

    USB module: I have not found a perfect USB driver, and the notion of writing a driver is intimidating. This firmware has practically not been started.

    DIN and Tangle: Are mostly done.

    MIDI driver: MIDI 1.0 and 2.0 parsing is implemented, as well as conversion between these formats. However, their compliance with the standard should be double checked. Other features like capability exchange are not implemented.

    Hardware status:

    A couple issues were found after the PCBs were ordered. These should be mentioned in the CADLab annotations.

    The USB-C connector's footprint was not within the capabilities of the PCB fabricator, so I had to reduce hole sizes. This means they are a bit tight. They also require thinner (1.2mm or less) PCBs to be soldered properly. I will probably change these to connectors with SMD pins for data and power, and through-hole for the shield to help with mechanical strength.

    I discovered that the ATSAMD21G MCUs don't have an integrated EEPROM, they have flash as emulated EEPROM. Which isn't ideal, so I will likely add an external chip to save settings in.

    The MIDI out on the DIN module does not work because its signal is inverted. This happened because the MCU I used in the previous version (Attiny406) could invert any pin's function from the firmware.

    According to the ATSAMD21G datasheet its internal oscillator has too much jitter to be used in a (compliant) USB host, and it's recommended for USB devices as well. So it will need an external crystal. I should have discovered this before ordering the PCBs, it was in the schematic checklist.

    The USB module has decent DACs and ADCs which in some situations wouldn't be used as an audio interface. It can be cool to add more RAM to this module so it can be used for delay and reverb effects if people want.

  • Module #4 - USB

    David10/15/2021 at 15:51 0 comments

    The USB module will provide a gateway between the USB MIDI transport and the CAN bus. Which means it needs to support both MIDI 1.0 and 2.0 over USB. This module also has an ADC and a DAC, both having 24-bits resolution and two channels for stereo. This let's it act as an audio interface so audio can be sent between the modular and a DAW. The schematics and PCBs can be viewed on CADLab.

    This module can act both as a USB device, and as a host. There is a TUSB320 chip handling the USB-C direction logic, so the microcontroller behaves like a USB-OTG device. Devices connected to the port can draw up to 500mA, otherwise a powered hub would be needed.

    The top-side contains mostly analog circuits, like the opamps, ADC, and DAC.

    This PCB was mounted orthogonal to the front-plate, because it makes the module slimmer. The 3.5mm jacks are holding these boards together. This module has a 4-layer PCB to make the routing more compact, because deep modules won't fit in some eurorack cases.

    The bottom-side contains digital circuits like the microcontroller, and CAN circuits.

  • Module #3 - Multiplexer

    David10/15/2021 at 15:50 0 comments

    The multiplexer module (or tangle module) provides MIDI controlled routing. It can change patches with a program change message. The thought is that it can be used to recall patches during a performance, or between songs. The schematics and PCBs can (eventually) be viewed on CADLab.

    This circuit consists of eight analog multiplexers, where each output is buffered and can select one of the inputs. This means that several outputs can select the same input, but an output can not give a mix of two inputs. There is a bi-color LED on each output indicating their voltage.

    The buttons are connected in a 2x4 matrix to save pins on the MCU. Actually, the red LED is connected to the data pin of the programming interface because absolutely all the pins were used.

    Laying out this PCB (left) has been my biggest routing challenge to date. I all the parallel traces pretty satisfying.

    I had to do some botching (right PCB) because floating inputs would pick up signals from other inputs.

  • Module #2 - Control Voltage

    David10/15/2021 at 15:48 0 comments

    This module is a general control voltage module. It can generate DC voltages, low frequency signals and envelopes. It is intended to be configurable so it can be used in many different setups. It should also be possible to save configurations to EEPROM to recall them later, and quickly change between them. The schematics and PCBs can be viewed on CADLab.

    The analog voltages are generated by filtering PWM. This leads to a trade-off between speed, ripple, and resolution. The speed of the outputs doesn't need to be higher than 20Hz. A resolution around 16-bits should be plenty for a prototype. And the ripple should be very low, we don't want it to sound shaky. This design is using four PWM outputs which are multiplexed, using a sample-and-hold method. The capacitors used in the sampling are also part of the low-pass filters, to reduce the part count. The voltage is then scaled, offset, and buffered by an opamp. Bi-color LEDs are connected to these outputs to indicate their current voltage.

    A general module like this will need a good user interface so it isn't frustrating to configure. A display module would be very versatile, but I've had some bad experience with them. So I decided to use an 8x5 LED-matrix instead. This means the info will be a bit cryptic, but it is easy to read, and a stylized look like this can be cool. This module is meant to be "set and forget" so it doesn't need immediate access to all parameters. So it has three buttons to navigate menus. It should be good enough for a prototype anyway.

    The module is a sandwich of two PCBs.

    After some testing I discovered that the LED-matrix was a bit dim, but there was still a lot of bleed between the pixels. I did expect it to bleed, but I was somehow surprised by the amount. To fix the bleeding I 3D-printed a separator. As for them being dim: I should get some brighter LEDs, 50mcd was not enough.

    Without the separator

    With the separator

  • Module #1 - DIN

    David10/15/2021 at 15:44 0 comments

    The DIN-5 module was the most straight forward. Most of this circuit is retained from the previous I2C version. Its purpose is to act as a gateway between the classical DIN-5 MIDI transport, and the CAN bus. The schematics and PCBs can be viewed on CADLab.

    This module has one DIN input, and one DIN output. There is a switch to decide if messages from the input should be merged with the output (Thru + Out). It also has a USB-C connector to program it via a bootloader.

    The assembled module looks like this.

    The front-plate is held in place by the DIN connectors and can't be removed after it has been assembled. This made reaching the programming header a challenge.

    The LEDs shine through the PCB. The Solder mask and copper has been removed from both sides in that area, and the FR-4 acts as a diffuser.

  • Bus protocol

    David10/14/2021 at 00:36 0 comments

    Deciding how the bus should behave is a bit easier as it can be adjusted afterward. The simplest solution is to use the CAN frame as a wrapper for the MIDI message. I did think about using one or two bits of the ID to define special messages, but it seems unnecessary.

    The CAN ID could contain some info about the MIDI message like type, or channel. That way some modules can filter out messages in the CAN controller, which means the CPU will see fewer interruptions. However, as far as I've understood the CAN bus it only uses the message header for arbitration. So, using the ID field like this will lead to more collisions and a reduced bandwidth. It may be better to use randomly generated IDs, so that each module on the bus has a unique ID. This would probably require a mechanism to detect address collisions to generate a new ID.

    One thing I'm unsure about is the 7-bit sysex messages. The specification says no messages should be interleaved with the sysex message. We could reserve CAN ID 0 for these messages so they always win arbitration, but that assumes we only have one sysex transmitter. But we can also use the CAN ID to determine which device sent the message, to reconstruct the sysex.

  • Defining the bus

    David10/13/2021 at 23:41 0 comments

    So, I had to decide which communication bus, connectors, and cables to use. Here I try to explain my thoughts, and why these choices were made. Some of my choices are likely a bit naive or not properly thought through, but I also feel like I'm overthinking things. So, some feedback would be appreciated.

    The bus should have half-duplex communication, allowing modules to answer messages from other modules. But most messages will be broadcasts without requiring an answer. Preferably, the bus should not need an arbiter to control the communication. That way any combination of modules will work together. It would be great if the bus datarate was comparable to USB 2.0, but there is no hard requirement. MIDI 1.0 has been in use for several decades, and its datarate was 31.25kbit/s.

    I did consider some other choices before deciding to go with CAN, like staying with I2C. Which is cheap to implement since most modern MCUs have it integrated. But it will limit the length and speed of the bus because of its lack of robustness. One way to improve robustness is differential I2C, but it isn't used as much so the choice of transceivers is limited.

    Another possibility was to use UART over RS-485. However, this does not have built-in arbitration or collision detection. Since RS-485 transceivers are push-pull a collision would result in high short-circuit currents, which is not ideal. So RS-485 does not make sense in a multi-master system.

    M-LVDS has similar problems as RS-485, only with lower short-circuit currents. But it will likely have the lowest EMR of all these choices during normal operation, due to the low voltage swings. Whether electromagnetic radiation is a problem in this project remains to be seen.

    And finally the CAN bus. This is a bit more complex than the other choices, it may need an external CAN controller depending on the MCU. But it handles arbitration, collision detection, and even re-transmission automatically. Which means writing the driver will be simpler. One limitation of CAN 2.0 is the maximum payload size of 8 bytes, while MIDI 2.0 can have messages up to 16 bytes. Here we have two choices: re-construct the messages afterward, or use CAN-FD which has a maximum payload of 64 bytes.

    I decided to go for CAN-FD because it seemed like the least amount of hassle to implement. Since many of the issues with multi-point communication are already handled. It can achieve datarates of 1Mbit/s with the possibility of increasing it. This should be enough for a decent sized system.

    Twisted pair cables look like the most natural choice for a CAN bus, but it needs a way to connect many short cables. The space in eurorack enclosures can be limited, so the solution shouldn't be too bulky either. One way is daisy-chaining connectors, which can be really awkward to assemble and leaves little room for changing module placement. Another way is using T-connections, which requires more space in the enclosure. Or having two connectors on every module, which I did on the previous iteration of this concept.

    Flat ribbon cables are most convenient, as it's just one cable where connectors are added as needed. They are known to be good antennas though, so the system may be more susceptible to electromagnetic forces. However, this being just one cable leads to short stubs and low signal skew on the bus, which helps with EMR.

    This time I decided to try ribbon cables for convenience. It seems like the best practice for differential signals in ribbon cables is to have the pair close, and surround it with ground (gnd  s+  s-  gnd). The idea with ground on the edges is providing a return path for any radiated current, and to prevent ground loops a high-pass RC filter is used on the PCB.

    The connectors should be non-reversible, so they can't be inserted the wrong way (unlike the eurorack power connectors). Connectors being distinct in eurorack would be a plus, so no unshrouded pin-headers with 2.54mm pitch. However, the...

    Read more »

  • The motivation

    David10/12/2021 at 18:01 0 comments

    This is technically a continuation of an earlier project I did. There I used an I2C connection to send MIDI messages between eurorack modules. This does work with low frequencies over short distances. However, I2C is not exactly known for its robustness. Also, the MIDI 2.0 specification was made public during the development of those first modules. So I wanted to make those modules more future-proof.

    MIDI in eurorack is usually only used to generate control voltages. And I think more digital control in eurorack could be cool. Being able to recall settings and patches using program change messages would definetively be useful in a performance setting. Remapping the functions of knobs would be possible, they don't even need to be on the module they're controlling. And with the improved resolution of MIDI 2.0 a controller knob can be indistinguishable from an analog knob. This will probably end up being a niche within a niche, but I believe having more options is positive.

    The main purpose of this project is to integrate MIDI 2.0 in eurorack. Currently the only transport for MIDI 2.0 is USB, but having USB on many modules can be inconvenient both for developers and end-user. For users this simply means several USB cables and hubs. For devs the USB stack may provide a lot of overhead in simple applications. Also, the modular synth community has a lot of small manufacturers, and hobbyists. So the USB licensing may prevent this part of the community from taking advantage of MIDI 2.0.

    Therefore I think defining a new transport for MIDI would be useful for eurorack and other modular systems. And to this end a multi-point bus would work great with MIDI, since most messages should be broadcast to every other module on the bus.

    The prototype to demonstrate this transport will be four modules: A DIN-5 gateway for the old MIDI 1.0 transport, a control voltage module to interact with the analog modules, a multiplexer module to change patches with MIDI, and a USB gateway for MIDI 2.0.

View all 10 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates