Teensy 3.6 - USB MIDI INPUT - Random CRASHS

Status
Not open for further replies.

Eloi

New member
Hello guys,

I developped a small projet which consist to drive somes LEDS (APA102) and spots over DMX.
I used Ableton in order to send midi note to Teensy.

I'm confronted to some random crashs when I send multiple midi notes in same time.

Teensy have a limited buffer size for incoming midi data ?
Does exist a specific function which can flush buffer before FIFO becomes oversized ?

Best regards
Eloi

View attachment a_global.zip

Code:
#include "MIDIUSB.h"

#include <DmxSimple.h>

byte mode = 0;
int current_brightness[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
byte fade_speed[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
byte fade_spd_led = 0;
unsigned long start_millis[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
unsigned long start_millis_led = 0;
unsigned long current_millis = 0;

#include "FastLED.h"

byte ledmode = 0;
#define DATA_PIN  11
#define CLK_PIN  14
#define LED_TYPE  APA102
#define COLOR_ORDER  BGR
#define NUM_LEDS  63
CRGB leds[NUM_LEDS];
unsigned int NUM_triangle = 63;
unsigned int bright = 0;
byte rouge = 0;
byte vert = 0;
byte bleue = 0;
unsigned int pos = 0;
uint8_t gHue = 0;

#define BRIGHTNESS          255
#define FRAMES_PER_SECOND  60

Code:
void setup()
{
    delay(1000);
    
    FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
    FastLED.setBrightness(BRIGHTNESS);

    for(int dot = 0; dot < NUM_LEDS; dot++)
    { 
      leds[dot] = CRGB::Black;
    }
    FastLED.show();
  
    DmxSimple.usePin(1);
    DmxSimple.maxChannel(26);
   
    usbMIDI.setHandleNoteOn(handleNoteOn);  // Put only the name of the function


    usbMIDI.setHandleNoteOff(handleNoteOff);

    usbMIDI.setHandleControlChange(HandleControlChange);

}

Code:
void loop()
{

  usbMIDI.read(2);
  
  fadeoff_update(); 
    
 
}

Code:
void handleNoteOn(byte channel, byte pitch, byte velocity)
{
    //VELOCITY -----------------------------------
    if (pitch > 23 && pitch < 48) //C0 to B1
    {
      mode = 0;
      DmxSimple.write(pitch - 23,  velocity);
      //analogWrite(9, velocity);
    }

    // FADE OUT ----------------------------------
    if (pitch >=48 && pitch < 72) //C2 to B3
    {
      mode = 1;
      current_brightness[pitch - 48] = 255;
      fade_speed[pitch - 48] = (byte)(127 - velocity);   
      start_millis[pitch - 48] = millis();
    }

     //LED -----------------------------------
     if (pitch == 72) //C4
     {
        rouge = velocity;
     }
     if (pitch == 73) //C#4
     {
        vert = velocity;
     }
     if (pitch == 74) //D4
     {
        bleue = velocity;
     }
       
    if (pitch == 75) //D#4 RGB mode
    {
      ledmode = 1;
    }

    if (pitch == 76) // E4 fade off
    {
      ledmode = 2;
      bright = 255;
      fade_spd_led = (byte)(127 - velocity);  
      start_millis_led = millis();
    }
    
    if (pitch == 77) // F4 cylon 3
    {
      ledmode = 3;
      pos = 0;
      fade_spd_led = (byte)(127 - velocity);  
      start_millis_led = millis();
    }
  
    if (pitch == 78) // F#4 cylon 4
    {
      ledmode = 4;
      pos = 0;
      fade_spd_led = (byte)(127 - velocity);  
      start_millis_led = millis();
    }
    
    if (pitch == 79) // G4 circle
    {
      ledmode = 5;
      fade_spd_led = (byte)(127 - velocity);  
      start_millis_led = millis();
    }
    
    if (pitch == 80) // G#4 meteorRain
    {
      ledmode = 6;
      pos = 0;
      fade_spd_led = (byte)(127 - velocity);  
      start_millis_led = millis();
    }
    
    if (pitch == 81) // A5 LED_RGB_rdm
    {
      ledmode = 7;
      fade_spd_led = (byte)(127 - velocity);  
      gHue = 0;
      start_millis_led = millis();
    }
  
    if (pitch == 82) // A#5 White rdm
    {
      ledmode = 8;
      fade_spd_led = (byte)(127 - velocity);  
      start_millis_led = millis();
    }
}

void handleNoteOff(byte channel, byte pitch, byte velocity)
{
  if (pitch > 23 && pitch < 48)
  {
    mode = 0;
    DmxSimple.write(pitch - 23,  0);
    //analogWrite(9, 0);
  }
  
  if (pitch == 75) //D#4 RGB mode
  {
    ledmode = 9;
  }
}

void HandleControlChange (byte channel, byte number, byte value)
{
  if (number == 1) // modulation
  {
    //servo pos X
    //analogWrite(9, value);
  }
  if (number == 2) // breath control
  {
    //servo pos Y
  }
}

Code:
void fadeoff(byte ch)
{
  
  if ((current_millis - start_millis[ch - 1]) > fade_speed[ch - 1])
  {
    
    if (current_brightness[ch - 1] > 0)
    { 
      DmxSimple.write(ch , current_brightness[ch - 1]);
      //analogWrite(9 + spot_nbr, current_bright);

      if (fade_speed[ch - 1] < 10)
      {
        current_brightness[ch - 1] = current_brightness[ch - 1] - 8;
      }
      if (fade_speed[ch - 1] >= 10 && fade_speed[ch - 1] < 50)
      {
        current_brightness[ch - 1] = current_brightness[ch - 1] - 5;
      }
      if (fade_speed[ch - 1] >= 50 && fade_speed[ch - 1] < 90)
      {
        current_brightness[ch - 1] = current_brightness[ch - 1] - 2;  
      }
      else 
      {
        current_brightness[ch - 1] = current_brightness[ch - 1] - 1;
      }
    }
    else if (current_brightness[ch - 1] < 0)
    {
      DmxSimple.write(ch , 0);
      current_brightness[ch - 1] = 0;
    }
  
  start_millis[ch - 1] = current_millis;  
  
  }      
}

void LED_OFF()
{
  if (ledmode == 9)
  {
      for(int dot = 0; dot < NUM_LEDS; dot++)
      { 
        leds[dot] = CRGB::Black;
      }
      FastLED.show();
      ledmode = 0;
  }    
}

void LED_RGB()
{
  if (ledmode == 1)
  {
      for(int dot = 0; dot < NUM_LEDS; dot++)
      { 
        leds[dot] = CRGB( rouge, vert, bleue);
      }
      FastLED.show();
  }    
}

void LED_fadeoff()
{
  if (ledmode == 2)
  {
    if ((current_millis - start_millis_led) > fade_spd_led)
    {
      if (bright == 255 )
      {
        for(int dot = 0; dot < NUM_LEDS; dot++)
        { 
          leds[dot] = CRGB( rouge, vert, bleue);
        }
      }
      fadeToBlackBy( leds, NUM_LEDS, 10);
      FastLED.show();

      if (bright != 0 ){bright --;}

      start_millis_led = current_millis;  
    }
  }    
}

void LED_cylon3() //cylon bas ==> haut
{ 
  if (ledmode == 3)
  {
    if ((current_millis - start_millis_led) > fade_spd_led)
    {
      if (pos < (NUM_triangle / 2) + 1)
      {
        leds[pos] = CRGB( rouge, vert, bleue);
        leds[NUM_triangle - pos] = CRGB( rouge, vert, bleue);
      }            
      
      FastLED.show();
      fadeToBlackBy( leds, NUM_LEDS, 26);

      pos ++;

      start_millis_led = current_millis;
    }
  }
}

void LED_cylon4() //triangle 3 pos cylon
{ 
  if (ledmode == 4)
  {
    if ((current_millis - start_millis_led) > fade_spd_led)
    {
      if (pos < 12)
      {
        leds[12 + pos] = CRGB( rouge, vert, bleue);
        leds[12 - pos] = CRGB( rouge, vert, bleue);
        leds[50 + pos] = CRGB( rouge, vert, bleue);
        leds[50 - pos] = CRGB( rouge, vert, bleue);
        pos++;
      }      
      if (pos < 10)
      {
        leds[31 + pos] = CRGB( rouge, vert, bleue);
        leds[31 - pos] = CRGB( rouge, vert, bleue);
      }
      
      FastLED.show();
      fadeToBlackBy( leds, NUM_LEDS, 70);

      start_millis_led = current_millis;
    }
  }
}

void LED_circle()  //cercle
{ 
  if (ledmode == 5)
  {
    if ((current_millis - start_millis_led) > fade_spd_led)
    {
      leds[pos] = CRGB( rouge, vert, bleue);
      
      if (pos < NUM_triangle){pos++;}
      else {pos = 0;}
      
      FastLED.show();
      fadeToBlackBy( leds, NUM_triangle, 13);
      

      start_millis_led = current_millis;
    }
  }
}

void meteorRain()
{ 
  if (ledmode == 6)
  {
    if ((current_millis - start_millis_led) > fade_spd_led)
    {
      // fade brightness all LEDs one step
      for(int j=0; j < NUM_LEDS; j++)
      {
        if( (!NUM_LEDS) || (random(8) > 5) ) {
          fadeToBlackBy(leds, NUM_LEDS, 5);        
        }
      } 
        
      // draw meteor
      for(int j = 0; j < 10; j++) {
        if( ( pos - j < NUM_LEDS) && (pos - j >= 0) ) {
          leds[pos - j] = CRGB(rouge, vert, bleue);
        } 
      }
      
      FastLED.show();
      
      pos++;
      start_millis_led = current_millis;
    }
  }
}

void LED_rdm_RGB() //RGB random blinking
{ 
  if (ledmode == 7)
  {
    if ((current_millis - start_millis_led) > fade_spd_led)
    {
      pos = random16(NUM_LEDS);
      leds[pos] += CHSV( gHue + random8(64), 255 , 255); 
      
      FastLED.show();
      fadeToBlackBy( leds, NUM_LEDS, 10);

      gHue++;
      start_millis_led = current_millis;
    }
  }
}

void LED_white_rdm() //White random blinking
{ 
  if (ledmode == 8)
  {
    if ((current_millis - start_millis_led) > 50)
    {
      for(int dot = 0; dot < NUM_LEDS; dot++)
        { 
          leds[dot] = CRGB( rouge, vert, bleue);
        }
      
      if( random8() < 150)
      {
        leds[ random16(NUM_LEDS) ] += CRGB::White;
      }
      if( random8() < 150)
      {
        leds[ random16(NUM_LEDS) ] += CRGB::White;
      }
      if( random8() < 150)
      {
        leds[ random16(NUM_LEDS) ] += CRGB::White;
      }

      FastLED.show();
      
      start_millis_led = current_millis;
    }
  }
}

Code:
void fadeoff_update (void)
{
 
  current_millis = millis();

  if (mode == 1)
  {
    fadeoff(1);
    fadeoff(2);
    fadeoff(3);
    fadeoff(4);

    fadeoff(5);
    fadeoff(6);
    fadeoff(7);
    fadeoff(8); 

    fadeoff(9);
    fadeoff(10);
    fadeoff(11);
    fadeoff(12); 

    fadeoff(13);
    fadeoff(14);
    fadeoff(15);
    fadeoff(16); 

    fadeoff(17);
    fadeoff(18);
    fadeoff(19);
    fadeoff(20); 

    fadeoff(21);
    fadeoff(22);
    fadeoff(23);
    fadeoff(24); 
  }

  LED_OFF();        //ledmode = 9
  LED_RGB();        //ledmode = 1
  LED_fadeoff();    //ledmode = 2
  LED_cylon3();     //ledmode = 3
  LED_cylon4();     //ledmode = 4
  LED_circle();     //ledmode = 5
  meteorRain();     //ledmode = 6
  LED_rdm_RGB();    //ledmode = 7
  LED_white_rdm();  //ledmode = 8

  
}
 
First, to answer your question...

Teensy have a limited buffer size for incoming midi data ?
Does exist a specific function which can flush buffer before FIFO becomes oversized ?

The way USB buffers work is complicated, but in a nutshell, the USB protocol automatically handles the all-buffers-used scenario. The USB host automatically waits and send the data later if the buffers are all used. How this works is quite complex... going to skip all that to keep this message sort.

My main concern in your program would be use of DmxSimple. It is a very old library which transmits DMX using direct pin I/O. That sort of approach is very likely to cause problems when trying to do other stuff.

I would recommend using any of the other DMX libs or examples which use Serial1 to transmit. Look at the 4 alternate links on the DmxSimple page:

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

Also you should be aware that APA102 LEDs have problems when the clock is very fast. I recommend using WS2812 and the WS2812Serial library (which can be used from FastLED). If you must use APA102, check the clock speed. On Teensy 3.6 you can force slower speeds by reducing the CPU clock, with Tools > CPU Speed in Arduino.
 
Thank you very much for your speed answer guys !

I just find error source :D
It provides in "Note_off" callcall which tryed to write "led_mode" variable in same time of other :)
I just add a status boolean to this function in order to avoid teensy's crash.

Paul, I will try WS2812Serial library and serial DMX. This seems to be a very good advice for a more advance LED setup and DMX fixtures.

NewLinuxFan, Yes I use your example at the begining of my project. Thank you so much ! Very weel made and well explain.

Regards
Eloi
 
Status
Not open for further replies.
Back
Top