MIDI loopback test fails with large messages on Teensy 3.2 and 3.6

Status
Not open for further replies.

sixeight

Well-known member
I ran into an issue trying to receive large MIDI messages over Serial1 or Serial2 port on both the Teensy 3.2 and 3.6. I was not receiving any data at all.

To pinpoint the issue I wrote the sketch below.

When I transmit 120 bytes, I receive 120 bytes. That works fine - using Teensy 3.6.
When I transmit 200 bytes, I receive 137 bytes using Teensy 3.6 or I receive nothing using Teensy 3.2.
I have checked the transmitted messages by connecting MIDI to a USB interface and using MIDI monitor on my Mac. The transmitted messages contain the right amount of bytes.

To test this sketch, one can simple connect Pin D0 to Pin D1 (the TX and RX of Serial1) and check the data in the serial monitor.
In the sketch you can set the message size (MSG_SIZE)

It looks like something is not keeping up, but i can't pinpoint the issue.
I would welcome any clues or other things I can test, in order to solve this problem.

Here is the sketch:
Code:
#include <MIDI.h>

#define MSG_SIZE 200 // Set message size here

struct MySettings : public midi::DefaultSettings
{
  static const unsigned SysExMaxSize = 256; // Change sysex buffersize - Zoom devices send packets up to 146 bytes
};

MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial1, MIDI1, MySettings); // Enables serial1 port for MIDI communication with custom settings

uint32_t timer = 0;
const uint32_t TIME = 1000; // 1 sec between sysex messages


void setup() {
  // put your setup code here, to run once:
  MIDI1.begin(MIDI_CHANNEL_OMNI);
  MIDI1.turnThruOff();
  MIDI1.setHandleSystemExclusive(OnSysEx);
  Serial.begin(115200);
}

void loop() {
  MIDI1.read();

  if (millis() > timer) {
    SendLargeMessage();
    timer = millis() + TIME;
    }
}

void OnSysEx(byte *sxdata, unsigned sxlength)
{
  Serial.print("Receiving " + String(sxlength) + " bytes: ");
  for (uint8_t i = 0; i < sxlength; i++) {
    if (sxdata[i] < 0x10) Serial.print("0" + String(sxdata[i], HEX) + " ");
    else Serial.print(String(sxdata[i], HEX) + " ");
  }
  Serial.println();
}

void SendLargeMessage() {
  uint8_t sxdata[MSG_SIZE];
  for (uint i = 0; i < MSG_SIZE; i++) sxdata[i] = i & 0x7F;
  MIDI1.sendSysEx(MSG_SIZE, sxdata);
  Serial.println("Sending sysex message");
}
 
I tried different buffer sizes, different speeds. Even bypassed the entire MIDI library. No difference. Max message size is 130 bytes. Above that value, data gets lost.

Has anyone been able to receive large messages using Serial1?
 
Even SoftSerial gives me incomplete data. What am I missing here. Anyone?

Code:
#include <MIDI.h>
#include <SoftwareSerial.h>

SoftwareSerial swSerial(0, 1); // RX, TX

MIDI_CREATE_INSTANCE(SoftwareSerial, swSerial, midiSw1);
#define MSG_SIZE 200 // Set message size here

struct MySettings : public midi::DefaultSettings
{
  static const unsigned SysExMaxSize = 256; // Change sysex buffersize - Zoom devices send packets up to 146 bytes
};

MIDI_CREATE_CUSTOM_INSTANCE(SoftwareSerial, swSerial, MIDI1, MySettings); // Enables serial1 port for MIDI communication with custom settings
//MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial2, MIDI2, MySettings); // Enables serial1 port for MIDI communication with custom settings

uint32_t timer = 0;
const uint32_t TIME = 1000; // 1 sec between sysex messages


void setup() {
  // put your setup code here, to run once:
  MIDI1.begin(MIDI_CHANNEL_OMNI);
  MIDI1.turnThruOff();
  MIDI1.setHandleSystemExclusive(OnSysEx);

  /*MIDI2.begin(MIDI_CHANNEL_OMNI);
  MIDI2.turnThruOff();
  MIDI2.setHandleSystemExclusive(OnSysEx);
  Serial.begin(115200);*/
}

void loop() {
  MIDI1.read();
  //MIDI2.read();

  if (millis() > timer) {
    SendLargeMessage();
    timer = millis() + TIME;
    }
}

void OnSysEx(byte *sxdata, unsigned sxlength)
{
  uint8_t buffer[MSG_SIZE + 2];
  Serial.print("Receiving " + String(sxlength) + " bytes: ");
  for (uint8_t i = 0; i < sxlength; i++) {
    buffer[i] = sxdata[i];
  }
  for (uint8_t i = 0; i < sxlength; i++) {
    if (buffer[i] < 0x10) Serial.print("0" + String(buffer[i], HEX) + " ");
    else Serial.print(String(buffer[i], HEX) + " ");
  }
  Serial.println();
}

void SendLargeMessage() {
  uint8_t sxdata[MSG_SIZE];
  for (uint16_t i = 0; i < MSG_SIZE; i++) sxdata[i] = i & 0x7F;
  MIDI1.sendSysEx(MSG_SIZE, sxdata);
  //MIDI2.sendSysEx(MSG_SIZE, sxdata);
  Serial.println("Sending sysex message");
}
 
Finally fixed this issue.
The solution: default buffersize for Serial1 is 64 bytes. I changed this to 255 bytes and all is well.

This value can be changed in the following file on Mac:
/Applications/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/serial1.c

Code:
////////////////////////////////////////////////////////////////
// Tunable parameters (relatively safe to edit these numbers)
////////////////////////////////////////////////////////////////

#ifndef SERIAL1_TX_BUFFER_SIZE
#define SERIAL1_TX_BUFFER_SIZE     64 // number of outgoing bytes to buffer
#endif
#ifndef SERIAL1_RX_BUFFER_SIZE
#define SERIAL1_RX_BUFFER_SIZE     255 // number of incoming bytes to buffer
#endif
#define RTS_HIGH_WATERMARK (SERIAL1_RX_BUFFER_SIZE-24) // RTS requests sender to pause
#define RTS_LOW_WATERMARK  (SERIAL1_RX_BUFFER_SIZE-38) // RTS allows sender to resume
#define IRQ_PRIORITY  64  // 0 = highest priority, 255 = lowest
 
Status
Not open for further replies.
Back
Top