Go Down

Topic: Receive multiple midi notes (or "chords") to control in realtime RGB leds? (Read 4063 times) previous topic - next topic

axxel

Hi everybody  ;)

I'm trying to control various RGB leds using the MIDI protocol. I don't need DMX, SERIAL or i2c. I need pure MIDI, here is the problem... :smiley-confuse:

I use 3 SPI-driven TLC5940 to get 48 precise PWM outputs.

I use an Arduino UNO (Atmega 328).

I use this hardware as a MIDI input (this one seems to work well) :



I use a USB to MIDI I/O cable and I try to drive the LED with Cubase.

I will use the MIDI like it :

NOTE ON:

Channel : 1 (I will use only one channel)

Note : 0..15 RED
 16..31 GREEN
 32..47 BLUE


Velocity : 0..255 : PWM Value of the desired output.

NOTE OFF:
Note : 0..15 RED
   16..31 GREEN
   32..47 BLUE

The PWM note value should have 0 (Shut down).0



I use the Arduino FortySevenEffects MIDI Library v4.2 :

https://github.com/FortySevenEffects/arduino_midi_library/releases/tag/4.2

My question and my problem is the following:

This example I show you work but with errors, sometimes, it looks like the data don't arrive or have errors. With only one note in one channel, it works like a charm. But when I want to use notes at the same times (chord) it is where the situation is more difficult and errors occurs.

It is an hardware error?

Code error?

The midi baud rate isn't sufficient to do this (yes, I think this is an absurd theory, but who knows...)

And mainly, is it possible to do this with arduino UNO?

Here is the code I made using the MIDI library:

Code: [Select]
#include <MIDI.h>
#include "Tlc5940.h"
MIDI_CREATE_DEFAULT_INSTANCE();

byte midirgb[48];

void setup() {
Tlc.init();
MIDI.begin();    
MIDI.setHandleNoteOn(MyHandleNoteOn);
MIDI.setHandleNoteOff(MyHandleNoteOff);
}

void MyHandleNoteOn(byte channel, byte pitch, byte velocity) {
  if (pitch <= 47) {
  midirgb[pitch] = 255;
  }
}


void MyHandleNoteOff(byte channel, byte pitch, byte velocity) {
  if (pitch <= 47) {
  midirgb[pitch] = 0;
  }
}

void loop() {
for (int i=0; i <= 47; i++){  
   MIDI.read();
   delayMicroseconds(100);
}

  

   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update();  

  
}


void RGBTLCSet256(byte ledstrip, byte r, byte g, byte b)
{
  if (ledstrip==0){
   Tlc.set(15, map(r,0,255,0,4095));
   Tlc.set(14, map(g,0,255,0,4095));
   Tlc.set(13, map(b,0,255,0,4095));
  }
  
  if (ledstrip==1){
   Tlc.set(12, map(r,0,255,0,4095));
   Tlc.set(11, map(g,0,255,0,4095));
   Tlc.set(10, map(b,0,255,0,4095));
  }
  
  if (ledstrip==2){
   Tlc.set(9, map(r,0,255,0,4095));
   Tlc.set(8, map(g,0,255,0,4095));
   Tlc.set(7, map(b,0,255,0,4095));
  }
  
  if (ledstrip==3){
   Tlc.set(6, map(r,0,255,0,4095));
   Tlc.set(5, map(g,0,255,0,4095));
   Tlc.set(4, map(b,0,255,0,4095));
  }
  
  if (ledstrip==4){
   Tlc.set(3, map(r,0,255,0,4095));
   Tlc.set(2, map(g,0,255,0,4095));
   Tlc.set(1, map(b,0,255,0,4095));
  }
  
  if (ledstrip==5){
   Tlc.set(0, map(r,0,255,0,4095));
   Tlc.set(31, map(g,0,255,0,4095));
   Tlc.set(30, map(b,0,255,0,4095));
  }
  
  if (ledstrip==6){
   Tlc.set(29, map(r,0,255,0,4095));
   Tlc.set(28, map(g,0,255,0,4095));
   Tlc.set(27, map(b,0,255,0,4095));
  }
  
 if (ledstrip==7){
   Tlc.set(26, map(r,0,255,0,4095));
   Tlc.set(25, map(g,0,255,0,4095));
   Tlc.set(24, map(b,0,255,0,4095));
  }

 if (ledstrip==8){
   Tlc.set(23, map(r,0,255,0,4095));
   Tlc.set(22, map(g,0,255,0,4095));
   Tlc.set(21, map(b,0,255,0,4095));
  }
  
 if (ledstrip==9){
   Tlc.set(20, map(r,0,255,0,4095));
   Tlc.set(19, map(g,0,255,0,4095));
   Tlc.set(18, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==10){
   Tlc.set(17, map(r,0,255,0,4095));
   Tlc.set(16, map(g,0,255,0,4095));
   Tlc.set(47, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==11){
   Tlc.set(46, map(r,0,255,0,4095));
   Tlc.set(45, map(g,0,255,0,4095));
   Tlc.set(44, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==12){
   Tlc.set(43, map(r,0,255,0,4095));
   Tlc.set(42, map(g,0,255,0,4095));
   Tlc.set(41, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==13){
   Tlc.set(40, map(r,0,255,0,4095));
   Tlc.set(39, map(g,0,255,0,4095));
   Tlc.set(38, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==14){
   Tlc.set(37, map(r,0,255,0,4095));
   Tlc.set(36, map(g,0,255,0,4095));
   Tlc.set(35, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==15){
   Tlc.set(34, map(r,0,255,0,4095));
   Tlc.set(33, map(g,0,255,0,4095));
   Tlc.set(32, map(b,0,255,0,4095));
  }    
}


Here is the code I made without library (pure serial) and the result is worstest...

Code: [Select]
#include "Tlc5940.h"

byte midirgb[48];

//These are the midi commands to interact with the arduino

byte midi_on = 0x90;
byte midi_off = 0x80;
byte location_byte;
byte in_note;
byte in_volume;

void check_midi()
 {
   while (Serial.available() >= 3)//when three bytes available
   {
     if (Serial.available())
     {
       location_byte = Serial.read();//read first byte
       in_note = Serial.read();//read next byte
       in_volume = Serial.read();//read final byte
     }
   }
 }

void setup() {
Tlc.init();
Serial.begin(31250);
}

void loop() {

/*  
for (int i=0; i <= 47; i++){
midirgb[i] = 0;
}
*/

for (int i=0; i <= 47; i++){

  check_midi();
  
  if (location_byte == midi_on)
  {
  midirgb[in_note] = in_volume;
  } else {
  midirgb[in_note] = 0;
  }

}



   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update();  
  
}


void RGBTLCSet256(byte ledstrip, byte r, byte g, byte b)
{
  if (ledstrip==0){
   Tlc.set(15, map(r,0,255,0,4095));
   Tlc.set(14, map(g,0,255,0,4095));
   Tlc.set(13, map(b,0,255,0,4095));
  }
  
  if (ledstrip==1){
   Tlc.set(12, map(r,0,255,0,4095));
   Tlc.set(11, map(g,0,255,0,4095));
   Tlc.set(10, map(b,0,255,0,4095));
  }
  
  if (ledstrip==2){
   Tlc.set(9, map(r,0,255,0,4095));
   Tlc.set(8, map(g,0,255,0,4095));
   Tlc.set(7, map(b,0,255,0,4095));
  }
  
  if (ledstrip==3){
   Tlc.set(6, map(r,0,255,0,4095));
   Tlc.set(5, map(g,0,255,0,4095));
   Tlc.set(4, map(b,0,255,0,4095));
  }
  
  if (ledstrip==4){
   Tlc.set(3, map(r,0,255,0,4095));
   Tlc.set(2, map(g,0,255,0,4095));
   Tlc.set(1, map(b,0,255,0,4095));
  }
  
  if (ledstrip==5){
   Tlc.set(0, map(r,0,255,0,4095));
   Tlc.set(31, map(g,0,255,0,4095));
   Tlc.set(30, map(b,0,255,0,4095));
  }
  
  if (ledstrip==6){
   Tlc.set(29, map(r,0,255,0,4095));
   Tlc.set(28, map(g,0,255,0,4095));
   Tlc.set(27, map(b,0,255,0,4095));
  }
  
 if (ledstrip==7){
   Tlc.set(26, map(r,0,255,0,4095));
   Tlc.set(25, map(g,0,255,0,4095));
   Tlc.set(24, map(b,0,255,0,4095));
  }

 if (ledstrip==8){
   Tlc.set(23, map(r,0,255,0,4095));
   Tlc.set(22, map(g,0,255,0,4095));
   Tlc.set(21, map(b,0,255,0,4095));
  }
  
 if (ledstrip==9){
   Tlc.set(20, map(r,0,255,0,4095));
   Tlc.set(19, map(g,0,255,0,4095));
   Tlc.set(18, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==10){
   Tlc.set(17, map(r,0,255,0,4095));
   Tlc.set(16, map(g,0,255,0,4095));
   Tlc.set(47, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==11){
   Tlc.set(46, map(r,0,255,0,4095));
   Tlc.set(45, map(g,0,255,0,4095));
   Tlc.set(44, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==12){
   Tlc.set(43, map(r,0,255,0,4095));
   Tlc.set(42, map(g,0,255,0,4095));
   Tlc.set(41, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==13){
   Tlc.set(40, map(r,0,255,0,4095));
   Tlc.set(39, map(g,0,255,0,4095));
   Tlc.set(38, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==14){
   Tlc.set(37, map(r,0,255,0,4095));
   Tlc.set(36, map(g,0,255,0,4095));
   Tlc.set(35, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==15){
   Tlc.set(34, map(r,0,255,0,4095));
   Tlc.set(33, map(g,0,255,0,4095));
   Tlc.set(32, map(b,0,255,0,4095));
  }    
}


Here is attached the Cubase file I use.

Thanks for your help and sharing your experience ;)

Grumpy_Mike

Quote
It is an hardware error?
No.

Quote
Code error?
Possibly

Quote
The midi baud rate isn't sufficient to do this
No.

Quote
And mainly, is it possible to do this with arduino UNO?
Yes.

Looking at the code it is poor. When you write the same lines over and over it is time to learn about for loops and arrays.
However I think your problem is this:-
Code: [Select]
void check_midi()
 {
   while (Serial.available() >= 3)//when three bytes available
   {
     if (Serial.available())
     {
       location_byte = Serial.read();//read first byte
       in_note = Serial.read();//read next byte
       in_volume = Serial.read();//read final byte
     }
   }
 }

What you are saying is if there are 3 or more bytes in the buffer keep taking them out in groups of three. So what happens when there are 4 bytes in the buffer. You read one message, then right over the top of that one you read one byte of the next message and then the next two bytes read an empty buffer returning 0xff and now your messages are out of sync and you get the bytes in the wrong place.

The other thing is that your keyboard could be switching to using the running status mode when it has a lot of keys to send at once and that code is not set up for running status mode.

axxel

Thanks for your help Grumpy_Mike.

I modified the code but I follow to get bad results...

Here is the serial code modified :

Code: [Select]
#include "Tlc5940.h"

byte midirgb[48];

//These are the midi commands to interact with the arduino

byte midi_on = 0x90;
byte midi_off = 0x80;
byte location_byte;
byte in_note;
byte in_volume;

void check_midi()
 {

     if (Serial.available())
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
     }
 }

void setup() {
Tlc.init();
Serial.begin(31250);
}

void loop() {

/*
for (int i=0; i <= 47; i++){
midirgb[i] = 0;
}
*/


  check_midi();
 
  if (location_byte == midi_on)
  {
  midirgb[in_note] = in_volume;
  } else {
  midirgb[in_note] = 0;
  }


   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update(); 
   
}


void RGBTLCSet256(byte ledstrip, byte r, byte g, byte b)
{
  if (ledstrip==0){
   Tlc.set(15, map(r,0,255,0,4095));
   Tlc.set(14, map(g,0,255,0,4095));
   Tlc.set(13, map(b,0,255,0,4095));
  }
 
  if (ledstrip==1){
   Tlc.set(12, map(r,0,255,0,4095));
   Tlc.set(11, map(g,0,255,0,4095));
   Tlc.set(10, map(b,0,255,0,4095));
  }
 
  if (ledstrip==2){
   Tlc.set(9, map(r,0,255,0,4095));
   Tlc.set(8, map(g,0,255,0,4095));
   Tlc.set(7, map(b,0,255,0,4095));
  }
 
  if (ledstrip==3){
   Tlc.set(6, map(r,0,255,0,4095));
   Tlc.set(5, map(g,0,255,0,4095));
   Tlc.set(4, map(b,0,255,0,4095));
  }
 
  if (ledstrip==4){
   Tlc.set(3, map(r,0,255,0,4095));
   Tlc.set(2, map(g,0,255,0,4095));
   Tlc.set(1, map(b,0,255,0,4095));
  }
 
  if (ledstrip==5){
   Tlc.set(0, map(r,0,255,0,4095));
   Tlc.set(31, map(g,0,255,0,4095));
   Tlc.set(30, map(b,0,255,0,4095));
  }
 
  if (ledstrip==6){
   Tlc.set(29, map(r,0,255,0,4095));
   Tlc.set(28, map(g,0,255,0,4095));
   Tlc.set(27, map(b,0,255,0,4095));
  }
 
 if (ledstrip==7){
   Tlc.set(26, map(r,0,255,0,4095));
   Tlc.set(25, map(g,0,255,0,4095));
   Tlc.set(24, map(b,0,255,0,4095));
  }

 if (ledstrip==8){
   Tlc.set(23, map(r,0,255,0,4095));
   Tlc.set(22, map(g,0,255,0,4095));
   Tlc.set(21, map(b,0,255,0,4095));
  }
 
 if (ledstrip==9){
   Tlc.set(20, map(r,0,255,0,4095));
   Tlc.set(19, map(g,0,255,0,4095));
   Tlc.set(18, map(b,0,255,0,4095));
  } 
 
 if (ledstrip==10){
   Tlc.set(17, map(r,0,255,0,4095));
   Tlc.set(16, map(g,0,255,0,4095));
   Tlc.set(47, map(b,0,255,0,4095));
  } 
 
 if (ledstrip==11){
   Tlc.set(46, map(r,0,255,0,4095));
   Tlc.set(45, map(g,0,255,0,4095));
   Tlc.set(44, map(b,0,255,0,4095));
  } 
 
 if (ledstrip==12){
   Tlc.set(43, map(r,0,255,0,4095));
   Tlc.set(42, map(g,0,255,0,4095));
   Tlc.set(41, map(b,0,255,0,4095));
  } 
 
 if (ledstrip==13){
   Tlc.set(40, map(r,0,255,0,4095));
   Tlc.set(39, map(g,0,255,0,4095));
   Tlc.set(38, map(b,0,255,0,4095));
  } 
 
 if (ledstrip==14){
   Tlc.set(37, map(r,0,255,0,4095));
   Tlc.set(36, map(g,0,255,0,4095));
   Tlc.set(35, map(b,0,255,0,4095));
  } 
 
 if (ledstrip==15){
   Tlc.set(34, map(r,0,255,0,4095));
   Tlc.set(33, map(g,0,255,0,4095));
   Tlc.set(32, map(b,0,255,0,4095));
  }   
}



I made a video (sorry for the accent, I'm french :) ) to explain what exactly is the problem:


https://www.youtube.com/watch?v=CTXEEFwu3iw&feature=youtu.be


The error is sometimes the midi data isn't correctly interpreted by the Arduino.

Unfortunatlty, I don't have a MIDI hardware keyboard (Only a Korg KaossPad 3 with one midi output, but it is useless in this case...) and only have a cubase sequencer with USB to midi converter... I think this configuration isn't working in running status, but in "normal midi" mode.

Regards ;)


Grumpy_Mike

You have still got exactly the same error in your thinking.
Code: [Select]
void check_midi()
 {

     if (Serial.available())
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
     }
 }


That is saying that if you have at lease one byte in the serial buffer then read three bytes. That is simply not going to work.
Try
Code: [Select]
void check_midi()
 {

     if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
     }
 }

axxel

Ohhh good! The result is a lot better!

I made another video:

https://www.youtube.com/watch?v=3Px7J1F1Orw&feature=youtu.be

Sometimes the data don't come totally to the Arduino and some leds don't turn on, the same problem I have using the MIDI Library. Of course, I totally prefer obtaining a working result without any midi library :)

Grumpy_Mike

The logic is still a bit wrong. You have nothing to say that a new note has been received and so you could be setting things based on the previous note.

I have tried adding this logic into a few routines but I haven't tested it.

Code: [Select]
boolean newNote = false;

void check_midi()
 {

     if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
       if(location_byte == midi_on || location_byte == midi_off) newNote = true;
     }
 }

void setup() {
Tlc.init();
Serial.begin(31250);
}

void loop() {
check_midi();
if(newNote){
  if (location_byte == midi_on) midirgb[in_note] = in_volume;
  if (location_byte == midi_off) midirgb[in_note] = 0;
   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update();
   newNote = false;
  }
}


Your code still assumes that you have received nothing but three byte MIDI messages, if your box throws out any two byte or single byte messages the the whole thing will get thrown out of "flunter"

axxel

Hi thanks for your answer :)

Unfortunatly, I obtain the same result  as the video : sometime the data ins't totally interpreted :(

This is the USB to MIDI converter I use, this is one of the good ones with optocoupler as input (no modification like this is needed - http://www.arvydas.co.uk/2013/07/cheap-usb-midi-cable-some-self-assembly-may-be-required/


Grumpy_Mike

Are you sure that this is correct?
Code: [Select]
byte midirgb[48];
That implies that the highest MIDI note is 47 which is B on octave -2. Any higher number will write outside the array and stamp on other variables and changes them.
Have you tried setting this array size to 128?

axxel

Hi  :)

I tried to put byte midirgb[128] but nothing changes.

This array is only here to "translate" the midi DATA to RGB DATA.

I use 16 RGB leds so 16x3 = 48 maximum.

Here this is the explaination of how works this array.


Grumpy_Mike

Quote
I tried to put byte midirgb[128] but nothing changes.
OK but:-
Quote
I use 16 RGB leds so 16x3 = 48 maximum.
That is not true. In your code you have:-
Code: [Select]
midirgb[in_note] = in_volume;
That means you can use ANY array index that is a in_note value, which is the second parameter of a note on / note off MIDI message. So that array needs to be 128 bytes in length.
Maybe you are not doing in the code what you think you are doing.

axxel

Yes, I understand what you mean, my explaination was a little bit confusing :smiley-lol:

The midi messages i will send will be always included between 0 and 47 value. I will never send a note > a 47.

According to this table it is note -1C ti 2B.



Here is the interpretation I do:



Finally I left the variable to 128, but no didn't noticied any positive change  :smiley-fat:

I tried this :

Code: [Select]
#include "Tlc5940.h"

byte midirgb[128];

//These are the midi commands to interact with the arduino

byte midi_on = 0x90;
byte midi_off = 0x80;
byte location_byte;
byte in_note;
byte in_volume;
boolean newNote = false;

void check_midi()
 {

     if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
       if(location_byte == midi_on || location_byte == midi_off) newNote = true;
     }
 }

void setup() {
Tlc.init();
Serial.begin(31250);
}

void loop() {

for (int i=0; i <= 47; i++){ 
check_midi();
if(newNote){
  if (location_byte == midi_on) midirgb[in_note] = in_volume;
  if (location_byte == midi_off) midirgb[in_note] = 0;
   newNote = false;
  }
}

   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update();
 
}

void RGBTLCSet256(byte ledstrip, byte r, byte g, byte b)
{
  if (ledstrip==0){
   Tlc.set(15, map(r,0,255,0,4095));
   Tlc.set(14, map(g,0,255,0,4095));
   Tlc.set(13, map(b,0,255,0,4095));
  }
 
  if (ledstrip==1){
   Tlc.set(12, map(r,0,255,0,4095));
   Tlc.set(11, map(g,0,255,0,4095));
   Tlc.set(10, map(b,0,255,0,4095));
  }
 
  if (ledstrip==2){
   Tlc.set(9, map(r,0,255,0,4095));
   Tlc.set(8, map(g,0,255,0,4095));
   Tlc.set(7, map(b,0,255,0,4095));
  }
 
  if (ledstrip==3){
   Tlc.set(6, map(r,0,255,0,4095));
   Tlc.set(5, map(g,0,255,0,4095));
   Tlc.set(4, map(b,0,255,0,4095));
  }
 
  if (ledstrip==4){
   Tlc.set(3, map(r,0,255,0,4095));
   Tlc.set(2, map(g,0,255,0,4095));
   Tlc.set(1, map(b,0,255,0,4095));
  }
 
  if (ledstrip==5){
   Tlc.set(0, map(r,0,255,0,4095));
   Tlc.set(31, map(g,0,255,0,4095));
   Tlc.set(30, map(b,0,255,0,4095));
  }
 
  if (ledstrip==6){
   Tlc.set(29, map(r,0,255,0,4095));
   Tlc.set(28, map(g,0,255,0,4095));
   Tlc.set(27, map(b,0,255,0,4095));
  }
 
 if (ledstrip==7){
   Tlc.set(26, map(r,0,255,0,4095));
   Tlc.set(25, map(g,0,255,0,4095));
   Tlc.set(24, map(b,0,255,0,4095));
  }

 if (ledstrip==8){
   Tlc.set(23, map(r,0,255,0,4095));
   Tlc.set(22, map(g,0,255,0,4095));
   Tlc.set(21, map(b,0,255,0,4095));
  }
 
 if (ledstrip==9){
   Tlc.set(20, map(r,0,255,0,4095));
   Tlc.set(19, map(g,0,255,0,4095));
   Tlc.set(18, map(b,0,255,0,4095));
  } 
 
 if (ledstrip==10){
   Tlc.set(17, map(r,0,255,0,4095));
   Tlc.set(16, map(g,0,255,0,4095));
   Tlc.set(47, map(b,0,255,0,4095));
  } 
 
 if (ledstrip==11){
   Tlc.set(46, map(r,0,255,0,4095));
   Tlc.set(45, map(g,0,255,0,4095));
   Tlc.set(44, map(b,0,255,0,4095));
  } 
 
 if (ledstrip==12){
   Tlc.set(43, map(r,0,255,0,4095));
   Tlc.set(42, map(g,0,255,0,4095));
   Tlc.set(41, map(b,0,255,0,4095));
  } 
 
 if (ledstrip==13){
   Tlc.set(40, map(r,0,255,0,4095));
   Tlc.set(39, map(g,0,255,0,4095));
   Tlc.set(38, map(b,0,255,0,4095));
  } 
 
 if (ledstrip==14){
   Tlc.set(37, map(r,0,255,0,4095));
   Tlc.set(36, map(g,0,255,0,4095));
   Tlc.set(35, map(b,0,255,0,4095));
  } 
 
 if (ledstrip==15){
   Tlc.set(34, map(r,0,255,0,4095));
   Tlc.set(33, map(g,0,255,0,4095));
   Tlc.set(32, map(b,0,255,0,4095));
  }   
}



Putting a loop to leave a good time to the arduino to unfill the serial buffer (in case it was it the error) but without any success...

Do you think it can be a serial buffer problem? What do you think about the Serial.flush() instruction?

https://www.arduino.cc/en/Serial/Flush

Grumpy_Mike

Quote
What do you think about the Serial.flush() instruction?
It is not what you need. It waits until the buffer is empty when sending serial data. You are only receiving data so it is irrelevant.

The Serial input buffer is 64 bytes long, if this is getting over run then it might cause the problems you are seeing.

To test this I would use the on board LED connected to pin 13. Set this pin as an output in the setup function and write a LOW to it to turn it off. Then in the loop function as the first line have this statement:-
Code: [Select]

if (Serial.available()>60)digitalWrite(13, HIGH);


If the buffer peaks above this value then you know it is over running.

axxel

I tested it, and there isn't any serial buffer overload.

Here is the code :

Code: [Select]
#include "Tlc5940.h"

byte midirgb[128];

//These are the midi commands to interact with the arduino

byte midi_on = 0x90;
byte midi_off = 0x80;
byte location_byte;
byte in_note;
byte in_volume;
boolean newNote = false;

void check_midi()
{

     if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
     }

    
  if (Serial.available()>60) {
    for (int i=0; i <= 47; i++){
      midirgb[i] = 255;
    }
  } else {
    for (int i=0; i <= 47; i++){
      midirgb[i] = 0;
    }
  }
}

void setup() {
Tlc.init();
Serial.begin(31250);
}

void loop() {

check_midi();

   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update();
  
}

void RGBTLCSet256(byte ledstrip, byte r, byte g, byte b)
{
  if (ledstrip==0){
   Tlc.set(15, map(r,0,255,0,4095));
   Tlc.set(14, map(g,0,255,0,4095));
   Tlc.set(13, map(b,0,255,0,4095));
  }
  
  if (ledstrip==1){
   Tlc.set(12, map(r,0,255,0,4095));
   Tlc.set(11, map(g,0,255,0,4095));
   Tlc.set(10, map(b,0,255,0,4095));
  }
  
  if (ledstrip==2){
   Tlc.set(9, map(r,0,255,0,4095));
   Tlc.set(8, map(g,0,255,0,4095));
   Tlc.set(7, map(b,0,255,0,4095));
  }
  
  if (ledstrip==3){
   Tlc.set(6, map(r,0,255,0,4095));
   Tlc.set(5, map(g,0,255,0,4095));
   Tlc.set(4, map(b,0,255,0,4095));
  }
  
  if (ledstrip==4){
   Tlc.set(3, map(r,0,255,0,4095));
   Tlc.set(2, map(g,0,255,0,4095));
   Tlc.set(1, map(b,0,255,0,4095));
  }
  
  if (ledstrip==5){
   Tlc.set(0, map(r,0,255,0,4095));
   Tlc.set(31, map(g,0,255,0,4095));
   Tlc.set(30, map(b,0,255,0,4095));
  }
  
  if (ledstrip==6){
   Tlc.set(29, map(r,0,255,0,4095));
   Tlc.set(28, map(g,0,255,0,4095));
   Tlc.set(27, map(b,0,255,0,4095));
  }
  
 if (ledstrip==7){
   Tlc.set(26, map(r,0,255,0,4095));
   Tlc.set(25, map(g,0,255,0,4095));
   Tlc.set(24, map(b,0,255,0,4095));
  }

 if (ledstrip==8){
   Tlc.set(23, map(r,0,255,0,4095));
   Tlc.set(22, map(g,0,255,0,4095));
   Tlc.set(21, map(b,0,255,0,4095));
  }
  
 if (ledstrip==9){
   Tlc.set(20, map(r,0,255,0,4095));
   Tlc.set(19, map(g,0,255,0,4095));
   Tlc.set(18, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==10){
   Tlc.set(17, map(r,0,255,0,4095));
   Tlc.set(16, map(g,0,255,0,4095));
   Tlc.set(47, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==11){
   Tlc.set(46, map(r,0,255,0,4095));
   Tlc.set(45, map(g,0,255,0,4095));
   Tlc.set(44, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==12){
   Tlc.set(43, map(r,0,255,0,4095));
   Tlc.set(42, map(g,0,255,0,4095));
   Tlc.set(41, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==13){
   Tlc.set(40, map(r,0,255,0,4095));
   Tlc.set(39, map(g,0,255,0,4095));
   Tlc.set(38, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==14){
   Tlc.set(37, map(r,0,255,0,4095));
   Tlc.set(36, map(g,0,255,0,4095));
   Tlc.set(35, map(b,0,255,0,4095));
  }  
  
 if (ledstrip==15){
   Tlc.set(34, map(r,0,255,0,4095));
   Tlc.set(33, map(g,0,255,0,4095));
   Tlc.set(32, map(b,0,255,0,4095));
  }    
}


So I assume with this part

Code: [Select]
    if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
     }


regulary I empty the buffer and it will have always free space.

Conclusion : The problem I have isn't related with buffer size :(

Idea : I will try this without TLC5940 but sending a feedback on a software serial port and monitorizing it with a serial monitor to see exactly what's happening...

axxel

#13
Dec 28, 2015, 02:04 am Last Edit: Dec 28, 2015, 02:12 am by axxel Reason: Results image size
Good! Here are the results  :D

Firstly, this is the hardware setup:



Secondly, this is the code :

Code: [Select]
#include <SoftwareSerial.h>

byte midi_on = 0x90;
byte midi_off = 0x80;
byte location_byte;
byte in_note;
byte in_volume;
boolean newNote = false;

SoftwareSerial FWSerial(3, 4); // RX, TX

void check_midi()
 {

     if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
       if(location_byte == midi_on || location_byte == midi_off) newNote = true;
     }
 }

void setup() {
pinMode(13, OUTPUT);
Serial.begin(31250);
FWSerial.begin(19200);
}

void loop() {
check_midi();
if(newNote){

  if (location_byte == midi_on){
    FWSerial.print("ON:");
    FWSerial.print(in_note,DEC);
    FWSerial.print(" - ");
    FWSerial.println(in_volume,DEC);
  }

  if (location_byte == midi_off){
    FWSerial.print("OFF:");
    FWSerial.print(in_note,DEC);
    FWSerial.print(" - ");
    FWSerial.println(in_volume,DEC);    
  }  

 newNote = false;
  
}
}


Third : The results (and now we know where is the problem  :smiley-twist: )

http://s8.postimg.org/ckciz4kat/results.png

Analysis :

- When the system works correctly, first I receve all the note OFF then I receive the notes ON.
- When the system gets buggy, we can see I receive two times the note off then two times the note ON, that explains why the interpretation isn't correct!

What do you think is the cause of this?

Regards.

Grumpy_Mike

That looks most odd. So it is your sequencer that is sending the extra stuff!

Not sure however why your code can't cope with this. I did notice that your code refreshes all the LEDs for every note you receive when all you need to do is to refresh the strip that corresponds to the note just received.

What I would do is to write it so that you only refresh the one strip per note. The code should be a lot shorter as well.

Go Up