Serial Transfer Problem - Data is Lost

Hi everyone,

Here’s what I’m trying to do:

piano —(usb)—> computer —(usb)—> Arduino UNO —> LED strip

Basically, I play a piano and an LED strip illuminates the active notes.

Problem:

It works fine, until I play a chord (+ ~4 notes concurrently). Example: if I play a 7 note chord, sometimes only 5 LEDs light up (missing 2 notes). My controller software (on the computer) is receiving 100% of the note data from the piano, but it gets lost after I write to the Arduino serial port.

What I tried:

increasing the baud rate
increasing poll rate (on the controller) < 1ms
implementing the controller in ruby, python, and c++ (no change)

Implementation:

Each byte sent to the Arduino is the positional value of a note. The last bit indicates whether the note is ON, or OFF(0,1). So:

10000010 = note 2,OFF
00000010 = note 2,ON

Arduino code:

#include <Adafruit_NeoPixel.h>
#define PIXEL_COUNT 250
#define PIN 6

Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIN, NEO_GRB + NEO_KHZ800);

int color[3] = {255, 255, 255}; // default to white  

uint32_t output_color() {
 return(strip.Color(color[0], color[1], color[2])); 
}

void setup() {
 Serial.begin(115200);
 strip.setBrightness(10);
 strip.begin(); 
 strip.show();  
}

uint32_t clr = output_color();

void loop() {
 if(Serial.available()) {
   int ledPosition = (int)(Serial.read());

   if ((ledPosition >> 7) & 0x01) {
     strip.setPixelColor(ledPosition ^ 128, 0); // turn OFF LED
   } else {
     strip.setPixelColor(ledPosition, clr);  // turn ON lED
   }
   strip.show(); 
 }
}

Update:

I added some logging to the Arduino: Serial.write(ledPosition);

It confirms that the data is lost before updating the LED strip. Example: I play a 9 note chord, and only 7 notes are logged.

Perhaps my Macintosh processor is failing to send this data? Or the Arduino is receiving it, but it's not getting into the buffer for some reason?

:frowning:

Updated loop with logging:

void loop() {
  if(Serial.available()) {
    int ledPosition = Serial.read();
    
    Serial.write(ledPosition);   // log to terminal:   notes are missing at this point

    if ((ledPosition >> 7) & 0x01) {
      strip.setPixelColor(ledPosition ^ 128, 0);
    } else {
      strip.setPixelColor(ledPosition, clr); 
    }
    strip.show(); 
  }

Comment out out all these lines and see if you are still missing data.

My guess is that the strip() functions are too slow - but I have never used them myself

If the data is all there when the strip() functions are inactive then re-enable the code line by line to see which line causes the problem.

Have you tried a higher baud rate? An Uno will work happily at 500,000 baud.

Also, while the data is being sent in a very simple way it is not a reliable way. Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

The technique in the 3rd example will be the most reliable.

You can send data in a compatible format with code like this - the technique can be adapted to any programming language

Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker

Your PC program seems to be sending data one byte at a time. Is it possible for multiple key-presses to send all the relevant bytes in a single message? I think if this was my project (and keep in mind that I an not a musician) and if the maximum number of key presses at any one time is 10 then I would send 10 bytes every time even if most of them were 0.

…R

That neopixel library heavily uses interrupts. If you receive more than one byte during the interrupt, data is lost. You cannot use neopixels and serial communication at the same time on an Arduino UNO. You could use a Teensy, and use one of the other UART peripherals for the Neopixels, or you could use a different type of addressable LEDs.

Pieter

    int ledPosition = Serial.read();

If you KNOW that there is data to read, as you do because you only call read() when available() returned a positive value, then the byte that you actually read could be stored in a byte, saving the overhead of manipulating a 2 byte variable when only one byte contains useful data.