Incoming MIDI messages are shorted to output

Status
Not open for further replies.

alexandros

Well-known member
I'm testing a Teensy 3.2 as a MIDI device with a 5-pin DIN output. Outputting MIDI messages works fine, but when I send MIDI messages from my Raspberry Pi to the Teensy, I receive the same messages in the Raspberry Pi, sent from the Teensy, even though the Teensy is supposed to receive only and not send.

I'm trying things out based on Teensy's MIDI page (https://www.pjrc.com/teensy/td_libs_MIDI.html) including the two code examples, with a slightly modified circuit.
Here's the circuit I'm using (the optocoupler I'm using though is a 4N35, but couldn't find a schematic part in Kicad):
teensy_midi.png

Is there's something wrong with the circuit?
 
47 ohm not Kohm

That's right, it's a mistake on the schematic, not the actual circuit. I don't think the code has an issue, I just copied the code from Teensy's website and only added a "while (!Serial) {}". Here it is:
Code:
#include <MIDI.h>

MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);

void setup() {
  MIDI.begin(MIDI_CHANNEL_OMNI);
  Serial.begin(57600);
  while (!Serial) {}
  Serial.println("MIDI Input Test");
}

unsigned long t=0;

void loop() {
  int type, note, velocity, channel, d1, d2;
  if (MIDI.read()) {                    // Is there a MIDI message incoming ?
    byte type = MIDI.getType();
    switch (type) {
      case midi::NoteOn:
        note = MIDI.getData1();
        velocity = MIDI.getData2();
        channel = MIDI.getChannel();
        if (velocity > 0) {
          Serial.println(String("Note On:  ch=") + channel + ", note=" + note + ", velocity=" + velocity);
        } else {
          Serial.println(String("Note Off: ch=") + channel + ", note=" + note);
        }
        break;
      case midi::NoteOff:
        note = MIDI.getData1();
        velocity = MIDI.getData2();
        channel = MIDI.getChannel();
        Serial.println(String("Note Off: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
        break;
      default:
        d1 = MIDI.getData1();
        d2 = MIDI.getData2();
        Serial.println(String("Message, type=") + type + ", data = " + d1 + " " + d2);
    }
    t = millis();
  }
  if (millis() - t > 10000) {
    t += 10000;
    Serial.println("(inactivity)");
  }
}

What I'm doing is send a Note Out MIDI message from Pure Data to the Teensy, but I'm also getting it back into Pd. I'm using the pisound sound card, which has LEDs for the MIDI input and output, and both LEDs are blinking when sending MIDI message from the pisound (Pure Data) to the Teensy, while only the output LED should blink.
 
The very first step is the test without the cables plugged into Teensy at all. There's a chance this problem is happening on the Linux side, where software automatically does loopback of messages. So run the test without Teensy connected at all.

Then try with only the input cable connected. Make sure the unwanted messages stop when you unplug the cable from Teensy's MIDI output.

If Teensy is in a socket, try removing the Teensy, so you have only the MIDI in and out circuits with no Teensy connected at all. Or if Teensy is soldered in place, try removing or cutting just the wires which connect to pins 0 & 1. There's a very good chance the problem could be in the circuitry, maybe a short somewhere causing the input and output to connect.

If these tests do show the circuits are working, before you put the Teensy back into the circuit, try connecting a wire between the input and output circuits, to intentionally send the data back. Does the problem happen with the wire, and stop happening when you remove the wire?

Do these hardware tests first. There's nothing in your code which should transmit anything. The problem is almost certainly a problem somewhere in the hardware.
 
I did unplug the MIDI cables, or removed either the receive or send jumper from the breadboard, and this loop doesn't happen (if I remove the Teensy there won't be any power in the MIDI circuit since all resistors are connected to Teensy's 3.3V and ground).
Having a "while (!Serial) {}" in the code, I tried uploading the code to the Teensy and not opening the serial monitor, then I sent a MIDI note out message from Pd to the Teensy, which did not loop back into Pd. After that I opened the serial monitor and saw that the MIDI message I had sent was printed into the serial monitor. Once I open the serial monitor, any messages I send from Pd to the Teensy are looped back into Pd.

Isn't this a hint that the problem lies somewhere in the software? If there was a hardware short, should the message loop back into Pd even if the serial monitor in the Arduino IDE was not open?
 
I ran a quick test here, using a Teensy LC to transmit MIDI data and a Teensy 3.2 running the code from msg #4.

This is the code I used on the Teensy LC:

Code:
void setup() {
  Serial1.begin(31250);
}

void loop() {
  Serial1.write(0x90); // note on
  Serial1.write(64);
  Serial1.write(100);
  delay(2);
  Serial1.write(0x80); // note off
  Serial1.write(64);
  Serial1.write(0);
  delay(100);
}

Here's what I see on my oscilloscope, where the yellow trace is the data from Teensy LC going into pin 0 on the Teensy 3.2, and the green trace is the output of Teensy 3.2 on pin 1.

file1.png

Just in case the data was being somehow delayed, I zoomed out a wide enough time scale to see the message repeat every 0.1 second.

file2.png

As a final check, to make sure I really have the hardware connected properly, I programmed the Teensy 3.2 with this code to intentionally echo the data.

Code:
void setup() {
  Serial1.begin(31250);
}

void loop() {
  if (Serial1.available()) {
    int n = Serial1.read();
    Serial1.write(n);
  }
}

When Teensy 3.2 runs that code, here's what my scope shows.

file3.png

Here's a photo of the boards connected on my desk with the scope probes still attached, so you can see how I tested.

DSC_0253_web.jpg

From these results, I'm confident your problem is not coming from the Teensy software side.
 
Your tests look persuasive, but I can't find any short on my breadboard. Also, it troubles me that if I send a MIDI message before I open the serial monitor, I don't get the feedback into Pd.

Does the circuit schematic in the OP look like it should work? Only a short between Teensy pins 0 and 1 could cause this message echo?
Since I'm using a different optocoupler and a slightly modified circuit (and that's because the local electronics store doesn't have the optocoupler mentioned in the Teensy page I posted in the OP at stock), could it be something that's not configured right?

I tried the same circuit with a Teensy LC, just to make sure that my Teensy 3.2 is not faulty in any way, and I got the exact same behaviour.
 
Does the circuit schematic in the OP look like it should work?

Usually faster optocouplers are used. I have personally tested 6N138 and PC900. The schematics on this page.

https://www.pjrc.com/teensy/td_libs_MIDI.html

That might 4N25 or 4N35 work, or it might be too slow. The bias resistor on the base can be tricky to get right. Even if it does seem to work, the signal quality might be very poor. An oscilloscope really is needed to proper verify to waveforms.
 
Usually faster optocouplers are used. I have personally tested 6N138 and PC900. The schematics on this page.

https://www.pjrc.com/teensy/td_libs_MIDI.html

That might 4N25 or 4N35 work, or it might be too slow. The bias resistor on the base can be tricky to get right. Even if it does seem to work, the signal quality might be very poor. An oscilloscope really is needed to proper verify to waveforms.
Then I'll order the 6N138 which you mention on your reference page and copy your circuit. I'll come back to report whether it worked or not.
Thanks for the help!
 
Oh, opps... in the tests I ran on msg #7, the Teensy 3.2 was sitting at that "while(!Serial);" line!

With the serial monitor open, it is indeed echoing messages. Turns out this is now the default in the MIDI library. :(

I couldn't find the MIDI lib documentation, but looking through the header I found the turnThruOff() function. I hooked it back up to the scope and I can confirm this code works and does not echo input to the output.

Code:
#include <MIDI.h>

MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);

void setup() {
  MIDI.begin(MIDI_CHANNEL_OMNI);
  MIDI.turnThruOff();
  Serial.begin(57600);
  while (!Serial) {}
  Serial.println("MIDI Input Test");
}

unsigned long t=0;

void loop() {
  int type, note, velocity, channel, d1, d2;
  if (MIDI.read()) {                    // Is there a MIDI message incoming ?
    byte type = MIDI.getType();
    switch (type) {
      case midi::NoteOn:
        note = MIDI.getData1();
        velocity = MIDI.getData2();
        channel = MIDI.getChannel();
        if (velocity > 0) {
          Serial.println(String("Note On:  ch=") + channel + ", note=" + note + ", velocity=" + velocity);
        } else {
          Serial.println(String("Note Off: ch=") + channel + ", note=" + note);
        }
        break;
      case midi::NoteOff:
        note = MIDI.getData1();
        velocity = MIDI.getData2();
        channel = MIDI.getChannel();
        Serial.println(String("Note Off: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
        break;
      default:
        d1 = MIDI.getData1();
        d2 = MIDI.getData2();
        Serial.println(String("Message, type=") + type + ", data = " + d1 + " " + d2);
    }
    t = millis();
  }
  if (millis() - t > 10000) {
    t += 10000;
    Serial.println("(inactivity)");
  }
}
 
Coming back to this thread after quite some time. Eventually I changed my approach and used a serial communication through Teensy's hardware serial1. This works great and it's way faster than MIDI, so I'm aborting the whole MIDI approach altogether.

Thanks for the help!
 
Status
Not open for further replies.
Back
Top