1

I'm working on an Arduino code which will interpret a given MIDI note message and output the corresponding note number to a string of LEDs as a binary integer. I have adapted it from existing code found on the site Notes & Volts which features a similar circuit designed to trigger an LED every time a key is pressed.

My circuit takes this further by telling the user exactly which note is being pressed. The note value byte is information is passed to a 74HC595 shift register which displays the note as a binary via a line of LEDs.

In a loose sense the code I have adapted "works". When a key is pressed a series of LEDs light up corresponding to the MIDI note designated to that key. The issue is that this only happens sporadically. Many times a key press won’t be followed by any LEDs but other times it will. Even quick, successive presses tend to result in only a handful of "read" notes.

Why does this happen? To my intuition it would seem that the Arduino is "missing" notes, that is, spending so many clock cycles writing bits to the shift register that it falls out of sync with incoming bytes from the keyboard. Notes & Volts describes almost this exact situation in one of their instructional videos (relevant part at around 6:57). The author cautions against including too many time consuming processes in the code but doesn't mention how many is too many. I can only assume that a ShiftOut command takes a good deal longer than a digitalWrite and that this explains why the example code works but my adaptation does not. Given this information, how long exactly does ShiftOut take and what could be done to speed up my program?

#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();

int latchPin = 8;
int clockPin = 12;
int dataPin = 11;  //The pins I am using

void note_On(byte channel, byte pitch, byte velocity) {  //Runs when note is pressed

  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, pitch);
  digitalWrite(latchPin, HIGH);  //Write 'pitch' to 74HC595. Standard fare
}

void note_Off(byte channel, byte pitch, byte velocity){ //Writes '0' when note is off (all LEDs off)
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, 0x00);
  digitalWrite(latchPin, HIGH);  
}
void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

  MIDI.begin(MIDI_CHANNEL_OMNI);
  MIDI.setHandleNoteOn(note_On);
  MIDI.setHandleNoteOff(note_Off);
}

  void loop() {
  MIDI.read();  //This function which must be re-run in quick succession
}

UPDATE

@CL @Nick I wrote a code comparing the execution time difference between shiftOut and digitalWrite. While I am not perfectly confident in all of the numbers (1K digitalWrites takes a full 44mS??) one result did not surprise me - shiftOut is slower. By my numbers it is 3.75 times slower. That said, I welcome critiques on my methodology and I will address them as soon as I can. In the meantime I will make a point to research Arduino SPI and welcome any other alternatives to shiftOut.

int latchPin = 8;       //Declaration of serial register pins
int clockPin = 12;
int dataPin = 11;

int led = 13;          //On-board LED

void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

  Serial.begin(9600);

  pinMode(led, OUTPUT);

}

void loop() {

  unsigned long startTime = millis();    //Writes to SR 1K times.
  for(int i = 0; i < 1000; i++){       //Prints difference between
    digitalWrite(latchPin, LOW);       //start and end times.
    shiftOut(dataPin, clockPin, MSBFIRST, 0xFF);
    digitalWrite(latchPin, HIGH);  
  }

  Serial.print("\nsO:");
  Serial.print(millis() - startTime);

  delay(1000);

  startTime = millis();
  for(int i = 0; i < 8000; i++){    //Performs digitalWrite 8K times
    digitalWrite(led, HIGH);
  }

  Serial.print("\t\tdW:");          //
  Serial.print(millis() - startTime);

  delay(1000);
}

UPDATE While working on a similar issue I discovered that a dramatic change to my code seems to perfectly clear up the issue. I'd still like to know why this particular example does not, however, so I'll keep poking around until I get somewhere.

5
  • 1
    Is your MIDI input circuit the same as in the link? (I.e., does it omit the decoupling capacitor?) If you're using a 6N138, can you try with a faster optocoupler, like the H11L1 or 6N137?
    – CL.
    Commented Jul 11, 2015 at 8:29
  • Can't you measure how fast shiftOut executes? (Execute it ten thousand times, and run millis() before and afterwards.)
    – CL.
    Commented Jul 11, 2015 at 8:33
  • 1
    I'll try your and other people's suggestions today but I'll chime in now just to say that I am already using an H11L1 so I think I have isolated the issue to the code itself. The input circuit I copied directly from the datasheet with the addition of a 220 Ohm resistor and a protection diode at the MIDI input. I got nice sharp pulses on the oscilloscope. Commented Jul 11, 2015 at 13:33
  • I still don't think that shiftOut is the issue, even if it is slower. My code did serial prints which are a lot slower again. Try the code I linked in my answer. The hardware should be the same, except move the MIDI input to pin D2 - leaving D0 and D1 for communicating with the Serial Monitor. You haven't answered my question about how you wired the LEDs. If you don't have a series resistor you may be overloading the 74HC595 output pins. Also the 74HC595 should have a decoupling capacitor.
    – Nick Gammon
    Commented Jul 12, 2015 at 0:50
  • Just to clarify, using SPI is a good idea. I don't argue with that. But I don't think it will fix this issue.
    – Nick Gammon
    Commented Jul 12, 2015 at 1:20

2 Answers 2

3

shiftOut is slow, yes. It is basically "bit banging" a synchronous serial interface, which is a bit daft really when the Arduino has a hardware synchronous serial interface built in that can operate at much higher speeds.

That built in synchronous serial interface is called SPI. I suggest you switch to SPI instead of shiftOut.

Also you should check what codes the MIDI keyboard is actually sending out. I had a similar experience to you recently, but as far as I can tell it's down to the keyboard, not my software. I built a system which reads in MIDI NoteOn codes through a serial port and plays a sample of a bass guitar at the right pitch. The system worked perfectly when wired to the computer through a USB MIDI adapter, but as soon as I connected it to a keyboard (I don't have one, so I only had the one chance to test it recently with a real keyboard) it would only react to a key pressed after a long delay. Almost as if the keyboard only sends a NoteOn if there is nothing happening for a while, and sends something else at other times. I need to examine the keyboard's output data in more detail to see exactly what is being sent and why.

You might like to manually examine the MIDI codes being sent by the keyboard to be sure that it is actually sending a NoteOn when you think it should be and not something else (it'd be very interesting to see the results of your experiments too).

5
  • The keyboard problem sounds as if your code did not support running status.
    – CL.
    Commented Jul 11, 2015 at 8:07
  • @CL quite possibly, since I have never heard of that, and none of the references I read while writing it mentioned it. Do you have a link?
    – Majenko
    Commented Jul 11, 2015 at 8:10
  • 1
    MIDI Specification: Running Status
    – CL.
    Commented Jul 11, 2015 at 8:15
  • That's interesting stuff. No, my code doesn't implement that and it explains perfectly why it failed on the keyboard. I wonder if the same is true for the MIDI class used by the OP?
    – Majenko
    Commented Jul 11, 2015 at 8:21
  • The OP's problem sounds more random.
    – CL.
    Commented Jul 11, 2015 at 8:23
1

I can't believe it is the shiftOut that is the issue. There is more going on here than meets the eye. I wrote a MIDI decoder a while back. That reads from MIDI and outputs to serial. That would be a lot slower than doing one shiftOut. It runs perfectly, not just with you sitting there tapping notes, but with the synth generating its inbuilt music. See video of it in action.

Either the library is doing something weird, or your 74HC595 is wired strangely. Do you have current-limiting resistors for each LED? Please show your wiring.

Also add a Serial print to display when your note_On and note_Off are called, and with what values. In my test I was able to connect MIDI up to Software Serial (pins D2 and D3 in my case) which was fine for receiving MIDI.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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