USB-MIDI to MIDI Revisited

Ever since building my Mini USB-MIDI to MIDI I’ve wanted something a little more self contained.  Most of these projects have been built with 8-bit microcontrollers, but the costs of more powerful microcontrollers is coming down all the time and you can now get very powerful 32-bit ARM based boards for really not very much so there are now a large number of boards based on the SAMD21 and SAMD51 processors.

The extra processing power and memory means you can either do more with them directly, if you are fine carrying on programming them from the Arduino environment, or switch over to programming them in python.

I now have several, but the one that has caught my eye for this application is the Adafruit Trinket M0.

2021-03-11 21.22.02

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

These are the key tutorials for the main concepts used in this project:

If you are new to microcontrollers, see the Getting Started pages.

Parts list

  • Adafruit Trinket M0 (buy in the UK from Pimoroni, The Pi Hut, and others) – make sure it is the M0 and not the original Trinket or “Trinket Pro”.
  • USB OTG adaptor (micro-USB male to USB A female).
  • USB MIDI device (for testing).
  • 3v logic microcontroller (for testing).
  • Breadboard and jumper wires.

The Circuit

USBMIDI-TrinketM0_bb

The Trinket M0 is a 3.3V SAMD21 based microcontroller with full Arduino IDE and Circuitpython support, that can be powered by USB or battery, has 5 IO pins, and will support USB device or host modes.

Eventually I plan to add a MIDI In for 3.3V Microcontrollers interface to create a fully self-contained USB to 5 pin DIN MIDI unit, but for now this is linking USB MIDI via the micro-USB port to serial MIDI using the UART.

This test circuit shows how it can be powered and connected to a Raspberry Pi Pico.  As the Trinket will be used as a USB host, it needs a 5V power supply on its USB pin.  This is provided from the Pico’s VBUS output, which itself comes from the Pico’s own micro-USB connector.  The Trinket’s TX pin (4) is connected to the Pico’s RX pin (GP1).  I’m not hooking up the Trinkets RX pin to the Pico’s TX yet, so this is only going USB-MIDI to MIDI at present, and not the reverse.

My test circuit also takes advantage of the fact that both the Trinket and the Pico are 3.3V microcontrollers, so no level-shifting is required for the serial connection. If I stick to USB-MIDI to MIDI, then the Trinket’s 3.3V TX can be connected to another microcontrollers 5V RX fine anyway, it is going in the other direction that will need extra care (and circuitry).

The USB device (in this case my Korg Microkeys) is connected to the micro-USB port on the Trinket using a micro-USB OTG adaptor, as shown in the diagram below.

2021-03-11 21.22.26micro-usb-otg

The Code

One of the reasons for using the Trinket M0 was stumbling across this project from “gdsports”: the USB Host Co-Processor.  This uses a port of the USB Host Shield code over to the SAMD processors alongside the Arduino MIDI Library to do exactly what I need – provide a bi-directional USB MIDI to Serial MIDI converter.

This is what is needed:

  • Arduino MIDI Library – installed in the usual way.
  • USB Host Library SAMD – installed by downloading the code from GitHub as a ZIP file and then using “Install .ZIP Library” from within the Arduino environment.
  • Your Arduino environment needs to be configured for the Adafruit SAMD family of boards.  Full details for how to do that can be found here.
  • The Adafruit DotStar library – installed by searching for dotstar from within the Arduino Library Manager.
  • gdsports’ MIDIUARTUSBH application, which comes as a single Arduino INO file (download it here as a “raw” file) and needs saving in your own src area in a directory called MIDIUARTUSBH.  Update: you might get on better with a different one – see below!

Once all this is gathered together, it is just a matter of selecting the Trinket M0 from the list of Adafruit SAMD boards (if you spot an entry for the Trinket or Trinket Pro, ignore these – these are older versions – we need the M0 version), plugging it in and uploading as usual.

There is one code change to be done if you want to use standard Serial MIDI.  By default, the USBUARTMIDIH application uses a serial baud rate of 115200.  To change it to the standard MIDI baud rate (which I wanted for widest compatibility) change this to 31250 in the following code:

struct MySettings : public midi::DefaultSettings
{
   static const bool Use1ByteParsing = false;
   static const unsigned SysExMaxSize = 1026; // Accept SysEx messages up to 1024 bytes long.
   static const long BaudRate = 31250;
};

Whilst building I had a load of compiler warnings about a redefinition of LITTLE_ENDIAN.  I don’t know if this is common or a weird aspect of the collection of boards and libraries I have installed in my Arduino environment.  Either way, it didn’t seem to matter, the code loaded and ran fine.

Update Oct 2022

I was finding I was losing MIDI messages with the original gdsports sketch.  I can’t remember why now I went with this one over the example that comes with the SAMD USB Host library, but I switched over to that one and it seems to work better for me.  See how you go!

Note: to turn off the Trinket’s DotStar LED needs a little extra code at the start as follows:

#ifdef ADAFRUIT_TRINKET_M0
// setup Dotstar LED on Trinket M0
#include <Adafruit_DotStar.h>
#define DATAPIN 7
#define CLOCKPIN 8
Adafruit_DotStar strip = Adafruit_DotStar(1, DATAPIN, CLOCKPIN, DOTSTAR_BRG);
#endif

And then in the setup() code the following:

#ifdef ADAFRUIT_TRINKET_M0
// Turn off built-in Dotstar RGB LED
strip.begin();
strip.clear();
strip.show();
#endif

While I was at it, I’ve also added a midiLedOn() and midiLedOff() routine to use LED_BUILTIN as a MIDI activity indicator.

Find my slightly updated code on GitHub here.

Closing Thoughts

This is another great example of finding something that just does exactly what you’d like it to do, so hats off to “gdsports” for the USB Host Co-Processor work, and by extension all those whose work they have built on themselves.

Next up will be to add the simple circuitry to make it a true MIDI out port, and perhaps also a MIDI In, seeing as the application should support it.

I’ve used my Pico as the MIDI receiver in this case, but the Pico will also act as a USB host itself according to the documentation, so in principle I should be able to use that directly for this type of application too.

I also have a few other SAMD based devices that I might explore.  I did want to see if all this could be done in Circuitpython, but I couldn’t find any mention of USB host support in Circuitpython, just USB devices, but that might also be something to explore further, although it would add a lot of software overhead that really isn’t required in this case.

At the end of the day though, I’m talking here about using this as a USB to serial MIDI interface for potential use with other microcontrollers… but this is a 32-bit ARM Cortex M0+ processor with its own IO, including a true analog DAC output… so actually, it can probably do everything I’ve been interested in so far just on its own.  So that is another angle to explore too.

Kevin

8 thoughts on “USB-MIDI to MIDI Revisited

  1. Hi Kevin.

    Thanks for this I’m using your TrinketM0_USB_MIDI_converter.ino for making a Bluetooth-midi enabled keyboard and it’s working great. But CC messages does not seem to work is that so?

    Like

    1. I’m not aware of any specific intelligence in the MIDI routing as far as I recall for this one so I’d have thought if MIDI data is received at all then it would be passed on regardless of the type of message.

      If you can let on a little more about your setup I could have a think – but I suggest getting it down to the simplest thing possible and using something with good MIDI logging (like MidiOx) to attempt to see what is going on.

      Like

  2. Thanks for the quick reply, Keyboard is an Akai MPK Mini mkII. Arduino-setup is similar to the one above with the Pico and Trinket but I’m using a Supermini NRF52840 (programmed with circuitpython) instead of the Pico. I guess it could be the circuitpython code that’s faulty in some way, but NoteOn, NoteOff and pitchbend gets passed on correctly but no CC messages gets through. I haven’t been able to test the Trinket by itself to see if it’s really sending CC messages, but if I look around I think I have some optocouplers somewhere and could build a simple Midi RX setup and connect to the computer. That’s next I think.

    Like

    1. I’m not really sure what to suggest – but as I say, I’m not aware of anything in the code that should filter them out and the fact you get pitch bend though seems to back that up.

      Like

      1. Ok, thanks anyhow. I also find it rather odd. I’ll continue the investigations.

        And thanks again for your updated code, it works good. The original one had problems with losing MIDI messages as you say.

        Like

      2. I must admit I’m still not entirely clear on your setup. If it was me, I’d be trying to get some debug outputs/etc on the various stages.

        I do know with Circuitpython there is weirdness in that if you aren’t including and explicitly checking for the different MIDI message objects in the Adafruit code then it ignores them… it might be something weird like that? There is a bit more about that here: https://diyelectromusic.com/2022/04/21/circuitpython-usb-to-serial-midi-router/

        Can you post the Circuitpython you’re using? And maybe a sketch (ASCII is fine!!) of your setup?

        Kevin

        Like

Leave a comment