Simple MIDI Serial Monitor – Part 2

In this second part of my Simple MIDI Serial Monitor I show how to use MIDI callbacks to handle the data and show how an independent serial interface could be used as the diagnostic port, thus allowing the hardware serial port to be used with MIDI.

IMG_6044

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 Arduino tutorials for the main concepts used in this project:

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

Parts list

  • Either Arduino Uno or Nano (ATmega328 based Arduino)
  • OR Pro Micro or Arduino Leonardo (ATmega32U4 based Arduino)
  • MIDI Interface (e.g. one of the Ready-Made MIDI Modules)
  • Optional: Second Arduino Uno or Nano
  • Optional: USB serial interface (e.g. based on FTDI or CH340 chips – see text)
  • MIDI source device
  • Jumper wires

The Circuit

As previously mentioned one of the issues with attempting to do a serial port based MIDI data dumper is that if we are using an Arduino Uno or Nano then the serial port can’t be used for data and MIDI at the same time.

The previous part described several ways around this, including:

  • Using boards with a second hardware UART (e.g. Pro Micro, 2560 based boards).
  • Using SoftwareSerial MIDI on others.

This post presents another option: using SoftwareSerial as the diagnostic output and using a second device to act as a “Arduino digital pins to USB/PC” interface.

Here are a selection of third party USB serial boards, all of which are available quite cheaply from the usual places and all of which have standard drivers available from somewhere.

Going from left to right, these have the following properties:

  1. CH340G interface; 5V logic; “USB to TTL, HW-567” label; pinouts (L to R): GND-RX-TX-3V3-VCC-5V; USB A plug; appears in Windows Device Manager as “USB-SERIAL CH340”
  2. CP2102 interface; 5V logic; no markings; pinouts (L to R): 3V3-GND-5V-TX-RX-DTR; USB A plug; appears in Windows Device Manager as “Silicon Labs CP210x USB to UART Bridge”
  3. FT232RL interface; 5V or 3V3 logic (switchable); “Deek-Robot” label; pinouts (L to R): DTR-RX-TX-5V-CTS-GND; mini USB socket; appears in Windows Device Manager as “USB Serial Port”
  4. PL2303 interface; 5V logic; no markings; wires: Red (5V), Black (GND), Green (TX), White (RX); USB A plug; appears in Windows Device Manager as “Prolific USB-to-Serial Comm Port”

SimpleMIDISerialMonitor2-A_bb

The above circuit shows in principle how everything should be wired up.  It shows an Adafruit FTDI Friend which is based on the FT232RL device, but the principles are the same for any USB to serial (TTL) device:

  • Connect Arduino GND to GND on the device
  • Connect Arduino Software RX (D2) to TX on the device
  • Connect Arduino Software TX (D3) to RX on the device

As the device will be powered over USB you should NOT connect the 5V or VCC connections.  And you pay particular attention to any 3V3 options.  We’re not going to be using them here, but if you manage to send 5V into a device expecting 3V3 signals then Bad Things are likely to happen.

Note, that whilst some devices appear to allow you to select 3V3 or 5V, from experience I’ve found this can often be problematic.

For example, the device I’ve shown above has a switch, but it only switches the serial logic levels, not the VCC level.  To be fair, the pin is labelled 5V, but it would be easy to see that as “VCC” (as I initially did) and expect that to change to 3V3 too – it doesn’t!

Similarly some of the devices have both 3V3 and 5V pins so the implication being that you can connect to either types of logic systems.  But again from experience I’ve found that often the logic signals are still 5V regardless.  So whilst you can use a 5V RX pin quite happily with a 3V3 TX from a microcontroller, plugging a 5V TX from the device into a microcontroller’s RX port that is expecting 3V3 might lead to problems.  Some microcontrollers will protect against it and accept an “over voltage” but others might not, so you could end up damaging an IO port.

Basically read datasheets and measure signals before you connect things up to be sure!

SimpleMIDISerialMonitor2-B_bb

Another option, if you don’t have a USB to serial interface, could be to use a second Arduino.  Here I’m using a Nano as a “Software Seral to Hardware Serial Bridge”.  The principle is the same as before – connect GND to GND, RX to TX, TX to RX.  This will need some code to map between the two ports to work though.

The Code

This code presents an alternative implementation to my previous project: the use of MIDI callback functions.  In this mode, we define a function that should be called whenever a specific MIDI message is received and then in our function do whatever we like with in response to the message.

The full list of “set callback” routines can be find in the MIDI.h file and the prototype definitions that they require can be seen in midi_Defs.h.

I’ve set up callbacks for NoteOn, NoteOff, ProgramChange and ControlChange as shown below.

void handleNoteOn(byte channel, byte pitch, byte velocity) { }

void handleNoteOff(byte channel, byte pitch, byte velocity) { }

void handleProgramChange(byte channel, byte program) { }

void handleControlChange(byte channel, byte control, byte value) { }

void setup() {
  MIDI_I.begin(MIDI_CHANNEL);
  MIDI_I.turnThruOff();
  MIDI_I.setHandleNoteOff(handleNoteOff);
  MIDI_I.setHandleNoteOn(handleNoteOn);
  MIDI_I.setHandleControlChange(handleControlChange);
  MIDI_I.setHandleProgramChange(handleProgramChange);
}

This is a good basis for any kind of code to respond to specific MIDI messages, which is one reason I’ve put the “first hardware serial” port option back into this code too.

The demo will print the received message out to the serial port if it isn’t being used as the MIDI input.  Otherwise you could just treat this as a template for a generic “MIDI message handler”.

You can use this “as is” with any Arduino that has a second serial port or if you connect the MIDI interface to a Software Serial port.  But there is also another option.

Software Serial DBG Port

This code allows for the use of a hardware or software serial port for the diagnostic outputs. If you are using an ATmega32U4 based device (such as a Leonardo or Pro Micro) you don’t need to do this, but for an Arduino Uno or Nano this is an option.

You need to use one of the USB to serial (TTL) options described above – either a separate device or another Arduino in “bridge” mode.

// If serial port output is required, decide if this is to be over
// the hardware serial port or a Software Serial link.
//
//#define DBG_HW_SERIAL 1
#define DBG_SW_SERIAL 2

You can choose either or neither by commenting out or in the options as shown above.  With neither being used, there is still the option to define MIDI_LED and just have an LED flash on reception of MIDI data!

NOTE: There are some limitations for which pins can be used for Software Serial links.  For details, see the documentation from the SoftwareSerial Library.

Find it on GitHub here.

The Arduino Software to Hardware Serial Bridge

To use another Arduino as a the USB to Serial interface, you need to load it with some relatively simple bridging code as follows (this is based on the SoftwareSerialExample code).

#include <SoftwareSerial.h>

#define SS_RX 2
#define SS_TX 3
SoftwareSerial sSerial = SoftwareSerial(SS_RX, SS_TX);

void setup() {
  Serial.begin(9600);
  sSerial.begin(9600);
}

void loop() {
  if (sSerial.available()) {
    Serial.write(sSerial.read());
  }
  if (Serial.available()) {
    sSerial.write(Serial.read());
  }
}

Closing Thoughts

As I said last time, it might be quite a nice thing to build a “MIDI data dumper” into a stand-alone unit but this gives plenty of options for adding MIDI debug and diagnostic functionality even if the MIDI link is using the only hardware serial port.

The callback version of the code presented here should make quite a nice template for any general “do something when I receive a MIDI message” application.

Kevin

Leave a comment