4

I tried to use the SoftwareSerial library for MIDI (by 47 effects), but it seems I get regularly corrupted/unexpected messages.

The circuit I'm using works perfectly when I connect it with the HardwareSerial solution (so the problem must lay in software).

What I see is:

  • When I press notes and release notes, LED 13 goes on and off correctly.
  • When I use Serial.print for debugging I get correct messages. However, in the example below I removed the print statements to have a minimal example).
  • When I use SoftwareSerial, LED 13 goes on and off for every note correctly. However, when I send many messages (for example by aftertouch/pitch bend which send a lot of messages in a short time), I noticed Note On/Off commands with 'random' values are sent.

Some sources say SoftwareSerial should work for MIDI, however, so far it is far from perfect. Do I make some mistake?

(btw, the baudrate of MIDI is 31.250 bps, when I use pitchband several hundreds of bytes per second are sent, so far within the MIDI spec).

The sketch I use is:

#include <MIDI.h>  // Add Midi Library
#include <SoftwareSerial.h>

SoftwareSerial swSerial(2, 11); // RX, TX

MIDI_CREATE_INSTANCE(SoftwareSerial, swSerial, midiSw1);

#define LED 13    // Arduino Board LED is on Pin 13

void setup()
{
  pinMode (LED, OUTPUT); // Set Arduino board pin 13 to output

  midiSw1.begin(MIDI_CHANNEL_OMNI);
  midiSw1.setHandleNoteOn(MyHandleNoteOn);
  midiSw1.setHandleNoteOff(MyHandleNoteOff);
}

void loop()
{
  midiSw1.read();
}

void MyHandleNoteOn(byte channel, byte pitch, byte velocity)
{
  digitalWrite(LED, HIGH); //Turn LED on
}

void MyHandleNoteOff(byte channel, byte pitch, byte velocity)
{
  digitalWrite(LED, LOW); //Turn LED off
}
  • 1
    I've experienced the exact same problem. In my experience SoftwareSerial isn't fast enough to handle quick, successive MIDI messages. I found I got the best results by using the hardware serial for MIDI and using SoftwareSerial + another Arduino for debugging. Although this was the best setup, it still wasn't perfect. Even the hardware serial dropped/corrupted messages once in a while. – Mazaryk May 20 '17 at 2:39
  • 1
    digitalWrite might be too slow. Try replacing it with PORTB |= 0x20; and PORTB &= ~0x20;. But there's nothing much you can do to speed up all the MIDI handling code. – CL. May 20 '17 at 8:20
  • @Mazaryk ... I already use a Mega which has 4 hardware serials, so far I use 3 for MIDI, one for debugging (for now, later can be the 4th MIDI). And when the 4th is used for MIDI I probably will use another Arduino as debugging. I did a lot of testing and so far I never got dropped/corrupted messages ... and CL proposed to use the even better H11L1 opto couplers instead of the 6N138 which I use now. – Michel Keijzers May 20 '17 at 11:32
  • @CL: Thanks ... everything to speed up might be good ... however, since the hardware serial solution worked well with digitalWrite and the software serial not, I still think it is too unpredictable if I have to use such 'tricks'.... later I want to do also additional processing which might make the software solution unworkable (again). – Michel Keijzers May 20 '17 at 11:33
2

The problem with SoftwareSerial is that while it is receiving a packet the Arduino is unable to do anything else - that includes reading bytes from the RX buffer, so it will easily overflow if you send things too rapidly. With HardwareSerial you are able to read from the buffer while it's receiving data, so overflowing is less of a problem.

As soon as the START bit of a packet is received it enters an ISR and reads each of the remaining 9 bits of data (including the stop bit) in a tight loop. That ISR doesn't exit until the whole packet has been received and stored in the RX buffer. If another byte is sent straight away there is little time between the ISR finishing and it being triggered again. The rest of the code, including the MIDI parsing routines which read data from the RX buffer, are then starved of CPU cycles and can't run properly. Send too many bytes together and the limited RX buffer (64 bytes) fills up and overflows, and you lose data.

Another issue with SoftwareSerial is that it has to capture the START bit at the moment it arrives. Any delay in capturing that edge will result in a drift in the bit sampling timing. If there is anything else that is using interrupts at the same time (such as the millis() timer) will delay the triggering of the PCINT interrupt used for the START bit detection. Even the SoftwareSerial interrupt itself has a certain amount of time after it has finished receiving the packet where it stores it in the RX buffer and returns from the interrupt routine. If the next packet arrives before the ISR is ready to service it there will be a delay - and any delay is bad.

Personally I am of the opinion that SoftwareSerial should never be used for anything, ever. If you need more serial ports then you either need a more powerful chip or you need more than one chip and get them communicating together through another higher speed hardware channel (SPI or I2C, for instance).

SoftwareSerial is only suitable for sending short bursts of data (since it blocks completely while sending) or receiving very short messages sent infrequently.

  • Very helpful information (as always) ... I tried to make the buffer 128 bytes but I didn't see any improvement. Of course I can make it 256 of maybe 512, but probably it's just 'delaying' the time before getting into problems if I read your explanation. – Michel Keijzers May 20 '17 at 11:56
  • 1
    If you're sending lots and lots all the time then yes, all you will be doing is delaying the time before you see problems. Also there is always the chance that if the next packet comes too fast the ISR won't be able to respond fast enough and you may lose the start of the next packet, triggering part way through on the next falling edge within it. – Majenko May 20 '17 at 11:58
  • 1
    Maybe even three ;) You can never have too many. It can be good to split a project down into component blocks and have them separately controlled and managed. Maybe have one central master controller than tells all the others what to do. – Majenko May 20 '17 at 12:00
  • 1
    Yeah, I know MIDI quite well. As I mentioned in a comment above it's not just the quantity that can be a problem but the gap between successive packets. Even just two packets sent too close together can be problematic. – Majenko May 20 '17 at 12:02
  • 1
    Absolutely. It can be useful to program a "kill switch" which stops all sounds in an emergency. Just in case. – Majenko May 20 '17 at 12:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.