Arduino Forum

Using Arduino => Audio => Topic started by: crx091081gb on Apr 04, 2012, 01:06 am

Title: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 04, 2012, 01:06 am
I made this MIDI to CV box and for years it worked just fine receiving MIDI from my computer's M4UXL USB controlled 4 in / 4 out MIDI box. Then I decided to go back to my roots and use my Atari and the damn thing doesn't work with it, every fourth or fifth MIDI note seems to get through but the rest don't. I'm guessing this is something to do with the way I wired the MIDI input, I used an opto isolator and left the shield ground unconnected at the input as per the MIDI spec.

Any ideas why it would work for one MIDI generating device but not another?
Title: Re: MIDI input works but not for all MIDI signals
Post by: RuggedCircuits on Apr 04, 2012, 01:50 am
What did you use for a pull-up resistor at the MIDI input? Lots of people use a popular schematic on the 'net that's not robust -- the resistor is too large. Your pullup resistor should be <1k, and something like 220ohms-330ohms is best. It could be the optoisolator is "on the edge" with respect to forward current on the LED side and the M4UXL just puts out more current than the Atari does, which shows up on the isolated side as marginal signals.

Just a theory.

--
The Flexible MIDI Shield (http://ruggedcircuits.com/html/flexible_midi_shield.html): MIDI IN/OUT, stacking headers, your choice of I/O pins
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 04, 2012, 02:59 am
Like this one I drew up yesterday?

(http://www.gammon.com.au/images/Arduino/MIDI_connections.png)

Are you saying that the 1.8K resistor should be 330 ohms?

(edit) Fixed image to change 1.8K to 330 ohms.

(edit) Changed on 12th April 2012 to reflect discussion below. Optocoupler changed from TLP521-1 to one with 100% CTR (current transfer ratio) (4N35) and resistor changed from 1.8K to 560 ohms.
Title: Re: MIDI input works but not for all MIDI signals
Post by: RuggedCircuits on Apr 04, 2012, 03:08 am
Yes. Here are the suggested schematics from the MIDI Manufacturer's Association (which suggests 280 ohms):

http://www.midi.org/techspecs/electrispec.php

I don't know why people keep rolling their own when this circuit has been around since 1985 :)

--
The Ruggeduino (http://ruggedcircuits.com/html/ruggeduino.html): compatible with Arduino UNO, 24V operation, all I/O's fused and protected
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 04, 2012, 03:33 am
Well, I don't know if that was better ...

Here is a single bit, using 330 ohms in the circuit above:

(http://www.gammon.com.au/images/Arduino/Arduino_forum_99767_330ohm.png)




And how it was before, with 1.8K:

(http://www.gammon.com.au/images/Arduino/Arduino_forum_99767_1800ohm.png)

It seems to me that the 1.8K gives a better looking bit.

(Cursor B was about a pixel out - it was supposed to be on 0V).
Title: Re: MIDI input works but not for all MIDI signals
Post by: RuggedCircuits on Apr 04, 2012, 03:42 am
Now the other factors come into play. The MMA does not specify an optoisolator but its CTR (current transfer ratio) can be important. Your TLP521-1 has (in its least expensive rating) a 50% CTR. You may need to find one with a higher CTR. For example, an Avago 4N35-000E has a 100% CTR and will probably do much better.

You can test this theory by (temporarily) lowering the 220ohm resistor on the input side (could be dangerous if what's driving it can't handle the current), or driving the input side yourself with a controlled voltage source to see at what input current level the output starts looking nice again.

--
The QuadRAM shield (http://ruggedcircuits.com/html/quadram.html): add 512 kilobytes of external RAM to your Arduino Mega/Mega2560
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 04, 2012, 03:53 am
Just so I understand this, are you saying that with the 330 ohm resistor, the fact that the bit only goes "halfway down" is because the optcoupler is only driving it 50%?

And therefore, if connecting up a different MIDI device which puts out less current, it might not even go that far, and thus I would not get 0 bits when I expect them?
Title: Re: MIDI input works but not for all MIDI signals
Post by: RuggedCircuits on Apr 04, 2012, 04:00 am
Correct. Either that or the device driving the input side of the optoisolator cannot supply enough current to sustain ~8mA of current through the LED.

--
The Aussie Shield (http://ruggedcircuits.com/html/aussie_shield.html): breakout all 28 pins to quick-connect terminals
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 04, 2012, 04:08 am
From what I've been just reading the frequency response suffers on the higher CTR designs.

My local supplier doesn't have Avago 4N35-000E in stock, does this look like a reasonable alternative?

VISHAY - 4N35 - OPTO COUPLER

http://au.element14.com/vishay/4n35/opto-coupler/dp/1328375

Title: Re: MIDI input works but not for all MIDI signals
Post by: RuggedCircuits on Apr 04, 2012, 04:28 am
Yes, that looks appropriate; it also has a 100% CTR though upon further reflection you might want something even stronger. I miscalculated the typical input current -- with 5V in, 3 220 ohm resistors (two on the MIDI OUT, one on the MIDI IN), and 1.4V LED voltage drop that gives about 5mA. It *should* be OK, but if you want to be super-safe how about this 200% CTR device:

http://www.digikey.com.au/product-detail/en/PS2501-1-L-A/PS2501-1-L-A-ND/990595

--
The Rugged Circuits Yellowjacket (http://ruggedcircuits.com/html/yellowjacket.html): 802.11 WiFi module with ATmega328P microcontroller, only 1.6" x 1.2", bootloader
Title: Re: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 05, 2012, 01:22 am
Cheers Rugged, Nick. I was using the diagram off this post from way back when http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1187962258/ (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1187962258/) and you're right 3.3k is way higher than the MIDI spec, I'm soldering a new one in now. Hopefully that's it.
Title: Re: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 05, 2012, 07:52 pm
Hmm well I swapped it and just like Nick when I looked on the scope I didn't get a very low bit and it didn't work (with anything). It seems 1.5k is as low as it can go before the Arduino doesn't recognise the bit.

I checked the opto-isolator (it was a Vishay ILQ74 one that I picked up from Maplin purely because it was the only one they had) and it's CTR is 35% so maybe that's part of the problem.

http://www.datasheetcatalog.org/datasheet/vishay/83640.pdf (http://www.datasheetcatalog.org/datasheet/vishay/83640.pdf)

I'll try and find a better one...
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 06, 2012, 12:24 am
I think for me, until I get better optoisolators, I have to go back to the earlier resistor. I'm going to order some others after Easter. In my particular case, it worked with the MIDI device on the bench, so there is no rush. But it sounds like the better isolator, and proper resistor, would give better and more reliable long-term results.
Title: Re: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 06, 2012, 12:38 am
Yeah I'm going to go back to the 3.3k one till I can get a better one.

One more question though, when I use the Atari for input the bits still seem to go as low on the scope as they do for the other MIDI signals that do work. Does this rule out the current being too low from the Atari? Or could a low current cause some change in the rise and fall of the signal that screws with the UART?

Could it be some variation in baud rates that other gear is more lenient with (unlikely I know) or some extra junk data that the Atari's putting out (also probably unlikely).


Title: Re: MIDI input works but not for all MIDI signals
Post by: RuggedCircuits on Apr 06, 2012, 12:42 am
If the bits go as low as necessary with the Atari then it's likely not an electrical problem. It could be a timing problem. The MIDI baud rate is 31250 bps, and that's not always exactly achievable using standard crystal frequencies and clock dividers.

Can you use your oscilloscope to measure the exact bit period?

--
The Gadget Shield (http://ruggedcircuits.com/html/gadget_shield.html): accelerometer, RGB LED, IR transmit/receive, speaker, microphone, light sensor, potentiometer, pushbuttons
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 06, 2012, 12:58 am

Then I decided to go back to my roots and use my Atari and the damn thing doesn't work with it, every fourth or fifth MIDI note seems to get through but the rest don't. I'm guessing this is something to do with the way I wired the MIDI input ...


It would be funny if this was a coding bug, after all the work we put into the electrical side (work not wasted mind you).

Maybe the Atari pumps out data faster, perhaps we should see the code.
Title: Re: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 06, 2012, 02:52 am
The scope is a really old analogue one and it can't seem to trigger off the input making reading bit lengths pretty much impossible, I'm not much of a scope wizard so any tips are welcome on that front. I'm guessing I'd need to make it trigger off a falling voltage then I'd be able to get a stable reading. Hmmm

The code
http://registeringdomainnamesismorefunthandoingrealwork.com/blogs/wp-content/uploads/2009/01/midi_dac_v11.pde (http://registeringdomainnamesismorefunthandoingrealwork.com/blogs/wp-content/uploads/2009/01/midi_dac_v11.pde)
Title: Re: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 06, 2012, 02:58 am
Thinking about it I should check if the Atari is sending any extra gumph (running status etc) down the line byte wise that my code isn't handling....
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 06, 2012, 08:35 am
That's what I was getting at. My gadget sends a "timing" byte quite often. Maybe you aren't allowing for it, or it overflows your buffer or something.
Title: Re: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 06, 2012, 03:41 pm
I've checked and there are no status bytes or other gumph coming through. I've also stripped any redundant code in an effort to make sure that it doesn't complete it's main loop fast enough to pick up bytes. No joy.

Is it concievable that the baud rates on the Atari/Arduino are sufficiently different that it could be a bit length/timing issue?
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 06, 2012, 11:53 pm
I doubt that personally. Post your code and then we can see.
Title: Re: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 07, 2012, 08:23 pm
Code: [Select]
#include <avr/pgmspace.h>
#include "LUT.h"

//PIN DEFINITIONS

#define DATAOUT 3 //MOSI, DIN Pin 15 on AD5668
#define SPICLK 4 //Serial Clock In, SCLK Pin 16
#define SLAVESELECT 5//SYNC Active Low Control Input, Pin 2
#define LDAC 6//LDAC, Pin 1, Pulse this pin low to update DAC registers, can be tied permanently low.
#define CLR 7
#define PWRLED 8
#define RXLED 9

//OUTLET DEFINITIONS FOR MIDI X0X
#define GATE 0
#define CV 1
#define ACC 2
#define SLD 3
#define FILT 4

//AD5668 Command definitions
#define WRITE 0
#define UPDATE 1
#define WRITE_UPDATE_ALL 2
#define WRITE_UPDATE_N 3
#define POWER 4
#define LOAD_CC_REG 5
#define LOAD_LDAC_REG 6
#define RESET 7
#define SETUP_INTERNAL_REGISTER 8

//MIDI VARIABLES
byte incomingByte;
int action = 0; //0 not implemented/do nothing, 1 note on, 2 note off, 3 cc, 4 sysex
int note = -1;  //use -1 to indicate the value has not yet been set, this should be changed
int velocity = -1;  //in future versions to save memory (i.e. use a char or a byte)
int extra1 = -1;
int extra2 = -1;

int RX = LOW;                // previous value of the LED
unsigned long interval = 100;           // interval to blink (milliseconds)

boolean noteOn = false;
boolean sysex = false;
unsigned int voltage1 = 13400;
unsigned int voltage2 = 26500;
unsigned int voltage3 = 39550;
unsigned int voltage4 = 52625;
long voltage5 = 65735;

void setup() {
 //set pin modes

 pinMode(DATAOUT, OUTPUT);
 pinMode(SPICLK, OUTPUT);
 pinMode(SLAVESELECT, OUTPUT);
 pinMode(LDAC, OUTPUT);
 pinMode(CLR, OUTPUT);
 pinMode(PWRLED, OUTPUT);
 pinMode(RXLED, OUTPUT);
 //disable DAC to start with
 digitalWrite(DATAOUT,LOW);
 digitalWrite(SPICLK, LOW);
 digitalWrite(SLAVESELECT, LOW);
 digitalWrite(LDAC, HIGH);
 digitalWrite(PWRLED, HIGH);
 digitalWrite(RXLED, HIGH);
 digitalWrite(CLR, LOW);
 delay(500);
 digitalWrite(CLR, HIGH);
 delay(500);
 delay(1000);
 write_dac(SETUP_INTERNAL_REGISTER, 0, 1); //set up internal register on DAC
 delay(1000);
 write_dac(POWER, 0, 0);
 delay(1000);
 write_dac(RESET, 0, 0);
 delay(1000);
 digitalWrite(RXLED, LOW);
 Serial.begin(31250); //change this when you want to graduate from usb midi to real midi
}


void write_dac(byte command, byte address, unsigned int data) {
 switch (command) {
 case WRITE_UPDATE_N:
   {
     byte b1 = B11110000|command; //padding at beginning of byte
     ////Serial.print("b1 ");
     ////Serial.println(b1, BIN);
     byte b2 = address << 4 | data >> 12; //4 address bits and 4 MSBs of data
     ////Serial.print("b2 ");
     ////Serial.println(b2, BIN);
     byte b3 = (data << 4) >> 8; // middle 8 bits of data
     ////Serial.print("b3 ");
     ////Serial.println(b3, BIN);
     byte b4 = (data << 12) >> 8 | B00001111;
     ////Serial.print("b4 ");
     ////Serial.println(b4, BIN);
     ////Serial.println();
     digitalWrite(SLAVESELECT, LOW);
     delayMicroseconds(1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b2);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b3);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b4);
     delayMicroseconds(1);
     digitalWrite(LDAC, LOW);
     delayMicroseconds(1);
     digitalWrite(LDAC, HIGH);
     delayMicroseconds(1);
     digitalWrite(SLAVESELECT, HIGH);
     break;
   }
 case SETUP_INTERNAL_REGISTER:
   {
     byte b1 = B11111000; //padding at beginning of byte
     ////Serial.print("b1 ");
     ////Serial.println(b1, BIN);
     byte b2 = B00000000;
     ////Serial.print("b2 ");
     ////Serial.println(b2, BIN);
     byte b3 = B00000000;
     ////Serial.print("b2 ");
     ////Serial.println(b3, BIN);
     byte b4 = B00000000|data;
     ////Serial.print("b4 ");
     ////Serial.println(b4, BIN);
     ////Serial.println();
     digitalWrite(SLAVESELECT, LOW);
     delayMicroseconds(1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b2);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b3);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b4);
     delayMicroseconds(1);
     digitalWrite(SLAVESELECT, HIGH);
     break;
   }
 case RESET:
   {
     byte b1 = B11110111; //padding at beginning of byte
     ////Serial.print("b1 ");
     ////Serial.println(b1, BIN);
     byte b2 = B00000000;
     ////Serial.print("b2 ");
     ////Serial.println(b2, BIN);
     byte b3 = B00000000;
     ////Serial.print("b2 ");
     ////Serial.println(b3, BIN);
     byte b4 = B00000000|data;
     ////Serial.print("b4 ");
     ////Serial.println(b4, BIN);
     ////Serial.println();
     digitalWrite(SLAVESELECT, LOW);
     delayMicroseconds(1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b2);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b3);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b4);
     delayMicroseconds(1);
     digitalWrite(SLAVESELECT, HIGH);
     break;
   }
 case POWER:
   {
     byte b1 = B11110100; //padding at beginning of byte
     ////Serial.print("b1 ");
     ////Serial.println(b1, BIN);
     byte b2 = B00000000;
     ////Serial.print("b2 ");
     ////Serial.println(b2, BIN);
     byte b3 = B00000000;
     ////Serial.print("b2 ");
     ////Serial.println(b3, BIN);
     byte b4 = B11111111;
     ////Serial.print("b4 ");
     ////Serial.println(b4, BIN);
     ////Serial.println();
     digitalWrite(SLAVESELECT, LOW);
     delayMicroseconds(1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b2);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b3);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b4);
     delayMicroseconds(1);
     digitalWrite(SLAVESELECT, HIGH);
     break;
   }
 }
}
Title: Re: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 07, 2012, 08:24 pm
Code: [Select]

void playNote(int note_, int velocity) {
  unsigned int note = note_;
  unsigned int voltage = 0;
  if ((note >= 12) && (note < 24)) {
    ////Serial.println("note >= 12 && note < 24");
    voltage = (voltage1)*((note - 12)/12.0);
  }
  else if ((note >= 24) && (note < 36)) {
    ////Serial.println("note >= 24 && note < 36");
    voltage = (voltage2 - voltage1)*((note - 24)/12.0) + voltage1;
  }
  else if ((note >= 36) && (note < 48)) {
    ////Serial.println("note >= 36 && note < 48");
    voltage = (voltage3 - voltage2)*((note - 36)/12.0) + voltage2;
  }
  else if ((note >= 48) && (note < 60)) {
    ////Serial.println("note >= 48 && note < 60");
    voltage = (voltage4 - voltage3)*((note - 48)/12.0) + voltage3;
  }
  else if ((note >= 60) && (note < 72)) {
    ////Serial.println("note >= 60 && note < 72");
    voltage = (voltage5 - voltage4)*((note - 60)/12.0) + voltage4;
  }
  noteOn = true;
  /*
  if ((velocity >= 1) && (velocity < 64)) { //normal note
    write_dac(WRITE_UPDATE_N, ACC, 0);
    write_dac(WRITE_UPDATE_N, CV, voltage);
    write_dac(WRITE_UPDATE_N, GATE, 65535);
    //Serial.print("cv = ");
    //Serial.print(voltage);
    //Serial.println(", accent = OFF");
  }
  else if (velocity >= 64) { //accent
    write_dac(WRITE_UPDATE_N, ACC, 65535);
    write_dac(WRITE_UPDATE_N, CV, voltage);
    write_dac(WRITE_UPDATE_N, GATE, 65535);
    //Serial.print("cv = ");
    //Serial.print(voltage);
    //Serial.println(", accent = ON");
  }
  */
  write_dac(WRITE_UPDATE_N, CV, voltage);
  write_dac(WRITE_UPDATE_N, GATE, 65535);
}

void stopNote(int note, int velocity) {
  //Serial.println("Note off, GATE = 0");
  write_dac(WRITE_UPDATE_N, GATE, 0);
  noteOn = false;
}

void cc(int note_, int velocity_) {
  write_dac(SETUP_INTERNAL_REGISTER, 0, 1);
  unsigned int note = note_;
  unsigned int velocity = velocity_; //you wouldn't have to convert the ints if you used
                                     //something other than -1 to indicate they were empty,
                                     //just keep them as bytes through out and use 128 as
                                     //empty for MSB and LSB data byte
  if (note == 1) {
    if (velocity >= 64) {
      write_dac(SETUP_INTERNAL_REGISTER, 0, 1);
      //Serial.println("INTERNAL REGISTER ON");
    }
    else {
      write_dac(SETUP_INTERNAL_REGISTER, 0, 0);
      //Serial.println("INTERNAL REGISTER OFF");
    }
  } else if (note == 12) {
    unsigned int voltage = 65535*velocity/127.0;
    write_dac(WRITE_UPDATE_N, 2, voltage);
  }
  else if (note == 13) {
    unsigned int voltage = 65535*velocity/127.0;
    write_dac(WRITE_UPDATE_N, 3, voltage);
    //Serial.print("OUTPUT 3 = ");
    //Serial.println(voltage);
  }
  else if (note == 14) {
    unsigned int voltage = 65535*velocity/127.0;
    write_dac(WRITE_UPDATE_N, 4, voltage);
    //Serial.print("OUTPUT 4 = ");
    //Serial.println(voltage);
  }
  else if (note == 20) {
    unsigned int voltage = 65535*velocity/127.0;
    write_dac(WRITE_UPDATE_N, 5, voltage);
    //Serial.print("OUTPUT 5 = ");
    //Serial.println(voltage);
  }
  else if (note == 21) {
    unsigned int voltage = 65535*velocity/127.0;
    write_dac(WRITE_UPDATE_N, 6, voltage);
    //Serial.print("OUTPUT 6 = ");
    //Serial.println(voltage);
  }
  else if (note == 22) {
    unsigned int voltage = 65535*velocity/127.0;
    write_dac(WRITE_UPDATE_N, 7, voltage);
    //Serial.print("OUTPUT 7 = ");
    //Serial.println(voltage);
  }
}

void loop() {
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();
    if ((incomingByte == 144) &! sysex) {
      //incoming note on
      action = 1;
    }
    else if ((incomingByte == 128) &! sysex) {
      //incoming note off
      action = 2;
    }
    else if ((incomingByte == 176) &! sysex) {
      action = 3;
    }
    else if ((incomingByte == 240) &! sysex) {
      action = 4;
      sysex = true;
      //Serial.println("incoming sysex");
    }
    else if ((incomingByte == 247) && sysex) {
      sysex = false;
      //Serial.println("sysex finished");
    }
    else if ((action == 1) && (note == -1)) {
      note = incomingByte;
    }
    else if ((action == 1) && (note != -1)) {
      velocity = incomingByte;
      //Serial.print("note on 144 ");
      //Serial.print(note, DEC);
      //Serial.print(" ");
      //Serial.println(velocity, DEC);
      if (velocity == 0) {
        stopNote(note,velocity);
      }
      else {
        playNote(note,velocity);
      }
      action = 0;
      note = -1;
      velocity = -1;
    }
    else if ((action == 2) && (note == -1)) {
      note = incomingByte;
    }
    else if ((action == 2) && (note != -1)) {
      velocity = incomingByte;
      //Serial.print("note off 128 ");
      //Serial.print(note, DEC);
      //Serial.print(" ");
      //Serial.println(velocity, DEC);
      stopNote(note,velocity);
      action = 0;
      note = -1;
      velocity = -1;
    }
    else if ((action == 3) && (note == -1)) {
      note = incomingByte;
    }
    else if ((action == 3) && (note != -1)) {
      velocity = incomingByte;
      //Serial.print("cc ");
      //Serial.print(note, DEC);
      //Serial.print(" ");
      //Serial.println(velocity, DEC);
      cc(note,velocity);
      action = 0;
      note = -1;
      velocity = -1;
    }
    else if ((action == 4) && (note == -1)) {
      note = incomingByte;
    }
    else if ((action == 4) && (note != -1) && (velocity == -1)) {
      velocity = incomingByte;
    }
    else if ((action == 4) && (note != -1) && (velocity != -1) && (extra1 == -1)) {
      extra1 = incomingByte;
    }
    else if ((action == 4) && (note != -1) && (velocity != -1) && (extra1 != -1) && (extra2 == -1)) {
      extra2 = incomingByte;
      //Serial.print("sysex: ");
      //Serial.print(note);
      //Serial.print(" ");
      //Serial.print(velocity);
      //Serial.print(" ");
      //Serial.print(extra1);
      //Serial.print(" ");
      //Serial.println(extra2);
      switch (note) {
      case 1:
        voltage1 = velocity*512 + extra1*4 + extra2;
        //Serial.print("voltage1 = ");
        //Serial.println(voltage1);
        break;
      case 2:
        voltage2 = velocity*512 + extra1*4 + extra2;
        //Serial.print("voltage2 = ");
        //Serial.println(voltage2);
        break;
      case 3:
        voltage3 = velocity*512 + extra1*4 + extra2;
        //Serial.print("voltage3 = ");
        //Serial.println(voltage3);
        break;
      case 4:
        voltage4 = velocity*512 + extra1*4 + extra2;
        //Serial.print("voltage4 = ");
        //Serial.println(voltage4);
        break;
      case 5:
        voltage5 = 65535 + velocity*512 + extra1*4 + extra2;
        //Serial.print("voltage5 = ");
        //Serial.println(voltage5);
        break;
      }
      action = 0;
      note = -1;
      velocity = -1;
      extra1 = -1;
      extra2 = -1;
    }
  }
  if (noteOn) {
    RX = HIGH;
  }
  else {
    RX = LOW;
  }
  digitalWrite(RXLED, RX);
}
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 08, 2012, 12:08 am
Code: [Select]

      digitalWrite(SLAVESELECT, LOW);
      delayMicroseconds(1);
      shiftOut(DATAOUT, SPICLK, MSBFIRST, b1);
      shiftOut(DATAOUT, SPICLK, MSBFIRST, b2);
      shiftOut(DATAOUT, SPICLK, MSBFIRST, b3);
      shiftOut(DATAOUT, SPICLK, MSBFIRST, b4);
      delayMicroseconds(1);
      digitalWrite(LDAC, LOW);
      delayMicroseconds(1);
      digitalWrite(LDAC, HIGH);
      delayMicroseconds(1);
      digitalWrite(SLAVESELECT, HIGH);


Why not use SPI.transfer() rather than all these shifts and delays?

Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 08, 2012, 04:59 am

I made this MIDI to CV box and for years it worked just fine receiving MIDI from my computer's M4UXL USB controlled 4 in / 4 out MIDI box. Then I decided to go back to my roots and use my Atari and the damn thing doesn't work with it, every fourth or fifth MIDI note seems to get through but the rest don't.


Now here's a funny thing. I was playing with a sketch that reads MIDI messages, here:

http://arduino.cc/forum/index.php/topic,100382.0.html

And it worked absolutely fine on one device (a Korg synth) but quite badly on another one (a Roland keyboard). Pretty much the same symptoms - some notes got through, a lot didn't.

I'm going to order the improved optocoupler chip in the next couple of days to see if that fixes it.
Title: Re: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 10, 2012, 02:04 pm
It was written along time ago and either the SPI library wasn't there or more likely I didn't know about it, that part of the code has worked solidly these last years so I never saw any need to fiddle with it. Let us know if the better class of opto fixes matters for you. I have to wait till my list of desired components grows to the right amount to get free shipping from Farnell.  :0
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 11, 2012, 06:36 am

Yes. Here are the suggested schematics from the MIDI Manufacturer's Association (which suggests 280 ohms):


I got some 4N35 today (100% CTR). Still with 330 ohms the results aren't very good:

(http://www.gammon.com.au/images/Arduino/Aruino_forum_99767c.png)

I got better results with a 1K resistor, but I don't totally like the rounded edges:

(http://www.gammon.com.au/images/Arduino/Aruino_forum_99767d.png)

Anyway, it turns out that the problems I had with the other device were software more than hardware. :)

Despite all the documentation about MIDI, it still leaves a bit to be desired when you want to interpret the protocol at the low level.
Title: Re: MIDI input works but not for all MIDI signals
Post by: RuggedCircuits on Apr 11, 2012, 06:44 am
I am really surprised the 100% CTR devices didn't get the output down lower. Can you confirm the current coming in on the input (LED) side? Is it at least 5mA?

--
The Aussie Shield (http://ruggedcircuits.com/html/aussie_shield.html): breakout all 28 pins to quick-connect terminals
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 11, 2012, 06:50 am
I also got a few SFH618A-4X. With 330 ohms:

(http://www.gammon.com.au/images/Arduino/Aruino_forum_99767e.png)

They claim to have 160 to 320% CTR at 1 mA.
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 11, 2012, 06:54 am

I am really surprised the 100% CTR devices didn't get the output down lower. Can you confirm the current coming in on the input (LED) side? Is it at least 5mA?


With my meter in circuit with the wire from the MIDI, I am measuring an average of 0.12 mA DC.

(edit) Maximum of about 0.48 mA
Title: Re: MIDI input works but not for all MIDI signals
Post by: RuggedCircuits on Apr 11, 2012, 07:02 am
Measuring DC current won't be so helpful since there will be no current flowing when there is no transmission coming in. And when there is, the current will be oscillating and your meter will be confused. Putting an in-line series resistor (10 ohms?) and using differential measuring mode on a scope will give a clearer picture.

The SFH618A-4X certainly gives nicer results, but has a slower-than-expected turn-off (the high bits should really be squarer). I'm also a bit confused about the timing. Looking at the reception that starts at almost exactly 250us into the data record (falling edge), I would have expected it to be over in 10 bit periods (start bit + 8 data bits + stop bit), which at 31250 bps would be 320 microseconds, or 6.4 divisions of 50us on the scope. Well, it looks like another transmission is coming in much earlier than that, as there's a falling edge just about 5.8 divisions later. Could the MIDI baud rate be wrong?

--
The QuadRAM shield (http://ruggedcircuits.com/html/quadram.html): add 512 kilobytes of external RAM to your Arduino Mega/Mega2560
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 11, 2012, 07:15 am
You might not have chosen the start of a byte. The logic analyzer appears to confirm things are OK:

(http://www.gammon.com.au/images/Arduino/Aruino_forum_99767f.png)

From the start of one byte to the next is 319.75 uS.
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 11, 2012, 07:39 am

Measuring DC current won't be so helpful since there will be no current flowing when there is no transmission coming in. And when there is, the current will be oscillating and your meter will be confused. Putting an in-line series resistor (10 ohms?) and using differential measuring mode on a scope will give a clearer picture.


OK, then.

(http://www.gammon.com.au/images/Arduino/Aruino_forum_99767g.png)

That's with 10 ohms, and since that side didn't have an earth reference I just clipped the ground to one side and the probe to the other. I calculate:

Code: [Select]
current = .080 / 10 = 8 mA

Is that right? So that looks OK.
Title: Re: MIDI input works but not for all MIDI signals
Post by: RuggedCircuits on Apr 11, 2012, 04:00 pm
Everything looks right then. In hindsight 100% CTR isn't really good enough since 8mA*330ohms = 2.64V of voltage drop, down from 5V means that the signal is only expected to go down to 5V-2.64=2.36V, and you observed it going down to 2.0V with the 4N35. So either a slightly bigger resistor (500 ohms should get down to 1V) or a higher CTR isolator (like your SFH618A-4X) would be the way to go for greater robustness.

--
The MegaRAM shield (http://ruggedcircuits.com/html/megaram.html): add 128 kilobytes of external RAM to your Arduino Mega/Mega2560
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 12, 2012, 02:26 am
It's always gratifying when theory and observation meet up, is it not?

Back to the 4N35 and a 560 ohm resistor gives this:

(http://www.gammon.com.au/images/Arduino/Aruino_forum_99767h.png)

Pretty reasonable wave-form and it comes down to 200 mV.

I'll amend my suggested circuit to incorporate that.

Title: Re: MIDI input works but not for all MIDI signals
Post by: RuggedCircuits on Apr 12, 2012, 02:29 am
That's a good looking waveform! Hopefully the 4N35 you have is representative of the norm and lot-to-lot variations (and manufacturer-to-manufacturer variation) won't affect things too much.

--
The Rugged Circuits Yellowjacket (http://ruggedcircuits.com/html/yellowjacket.html): 802.11 WiFi module with ATmega328P microcontroller, only 1.6" x 1.2", bootloader
Title: Re: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 12, 2012, 03:00 am
Nick were your problems anything to do with running status? I've been thinking perhaps my code isn't handling this..

http://home.roadrunner.com/~jgglatt/tech/midispec/run.htm (http://home.roadrunner.com/~jgglatt/tech/midispec/run.htm)
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 12, 2012, 03:13 am
Yes that was exactly it. I was getting multiple bytes with the low-order bit set. I guessed, and tests confirmed, that I was getting multiple note-ons in a row. And to save switching to note off, they were sending note-on with a velocity of zero.
Title: Re: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 14, 2012, 06:22 pm
Just confirmed it was my crappy implementation of running status that was responsible. I'm surprised this doesn't come up more often. I'm just surprised that my modern DAW doesn't take advantage of running status to try and keep the MIDI bus as free as possible but then if modern computers could do MIDI with sub millisecond accuracy then I wouldn't have to use an Atari in the first place.

Ho hum.
Title: Re: MIDI input works but not for all MIDI signals
Post by: nickgammon on Apr 15, 2012, 12:35 am
Ah well, in chasing the hardware bug we both learned something about both hardware and software. So, that was time well spent. :)
Title: Re: MIDI input works but not for all MIDI signals
Post by: crx091081gb on Apr 15, 2012, 01:45 pm
I think so. :)
Title: Re: MIDI input works but not for all MIDI signals
Post by: Andy2No on Feb 09, 2015, 08:01 pm
Coming slightly late to this discussion; the problem appears to be getting a good low level, with an optoisolator output.

I've seen a circuit that gets around that, though I didn't realise at the time.  It just adds a PNP transistor stage, acting as an inverter.  The signal then needs inverting again, I guess, but you could probably just do that in software.

I have a schematic, as an image (saved a while ago - I've forgotten where from). I don't see any way to attach it here though.  

I expect you can picture it anyway.  The emitter of the PNP transistor is connected to Vcc, the collector connects through a resistor to ground.  The base is fed via a resistor from the output side of the optoisolator.

If the output of the optoisolator is off, the base of the PNP transistor is at Vcc, so the transistor is off (output low, close to 0V thanks to the collector resistor connected to ground).  If the optoisolator output is on, it only needs to drop by a little over 0.6V, to turn the PNP transistor on (output high, close to Vcc - 0.2V or so).  So, even a dip of 1V for a zero, should be fine, depending on the base resistor value, and the gain of the transistor.

The diagram showed a PC817 optoisolator, with a 390 Ohm series resistor on the output side, and the same value resistor as the base resistor of the PNP transistor, shown as a BC640.  The collector resistor is shown as 1k5 Ohms.  Almost any small PNP transistor would do, I expect, and the resistor values aren't likely to be at all critical.