Code stops working when I try to output to serial

Status
Not open for further replies.

harald25

Well-known member
Hey.
I'm trying to debug my code by adding a Serial.println. When I do my code stops running (or so it seems).
My setup is a Teensy LC controlling 5 LEDs. I want these LEDs to light up at random intervals. I'm not getting this to work and therefore wanted to output som values to the serial monitor.
When I add a Serial.prinln() inside the loop that runs through my LEDs, the program stops running. The LEDs just freeze in the color they where currently holding when I uploaded the code.
If I add a Serial.println() inside loop() it works without a problem.

Here is my code. If I uncomment any of the Serial.println()-lines, the code stops working.
Code:
void BlinkUpdate()
    {
      for (int i = 0; i < 5; i++)
      {
        if (millis() >= NextBlink_LEDi[i])
        {
          leds[i] = ColorFromPalette( heatcolorPalette, Index_LEDi[i]);
          Index_LEDi[i]++;
          
          if (Index_LEDi[i] > TotalSteps)
          {
            Index_LEDi[i] = 0;
            NextBlink_LEDi[i] = millis()+(random16()%50000);
            //Serial.println("Time until next blink for LED: ");
            //Serial.print(i);
            //Serial.println(NextBlink_LEDi[i]);  
          }
        }
      }
      FastLED.show();  
    }
 
Here is the complete program.
The part that I'm having troubles with is only a small part of the code.

Code:
#include "FastLED.h"
/////////// CANDLE PARAMETERS \\\\\\\\\\

// The data-in pin of the NeoPixel
// #define WICK_PIN                6
// Any unconnected pin, to try to generate a random seed
#define UNCONNECTED_PIN         23

// The LED can be in only one of these states at any given time
#define BRIGHT                  0
#define UP                      1
#define DOWN                    2
#define DIM                     3
#define BRIGHT_HOLD             4
#define DIM_HOLD                5

// Percent chance the LED will suddenly fall to minimum brightness
#define INDEX_BOTTOM_PERCENT    10
// Absolute minimum red value (green value is a function of red's value)
#define INDEX_BOTTOM            128
// Minimum red value during "normal" flickering (not a dramatic change)
#define INDEX_MIN               192
// Maximum red value
#define INDEX_MAX               255

// Decreasing brightness will take place over a number of milliseconds in this range
#define DOWN_MIN_MSECS          20
#define DOWN_MAX_MSECS          250
// Increasing brightness will take place over a number of milliseconds in this range
#define UP_MIN_MSECS            20
#define UP_MAX_MSECS            250
// Percent chance the color will hold unchanged after brightening
#define BRIGHT_HOLD_PERCENT     20
// When holding after brightening, hold for a number of milliseconds in this range
#define BRIGHT_HOLD_MIN_MSECS   0
#define BRIGHT_HOLD_MAX_MSECS   100
// Percent chance the color will hold unchanged after dimming
#define DIM_HOLD_PERCENT        5
// When holding after dimming, hold for a number of milliseconds in this range
#define DIM_HOLD_MIN_MSECS      0
#define DIM_HOLD_MAX_MSECS      50

#define MINVAL(A,B)             (((A) < (B)) ? (A) : (B))
#define MAXVAL(A,B)             (((A) > (B)) ? (A) : (B))

byte state;
unsigned long flicker_msecs;
unsigned long flicker_start;
byte index_start;
byte index_end;
unsigned long current_time;

///////////////////      \\\\\\\\\\\\\\\\\\\\\\\

#define NUM_LEDS 5
#define LED_PIN 6
#define BUTTON 0
uint8_t sat = 255;
uint8_t val = 255;
enum pattern { NONE, RAINBOW_CYCLE, CANDLE, HEAT_COLOR, LOVE, BLINK};
uint8_t patternID;
int buttonState;
int lastButtonState;

DEFINE_GRADIENT_PALETTE( love_gp ) {
  0,    255,  255,  255,    //White
  127,  255,  0,    255,    //Pink
  255,  128,  0,    128};   //Purple

DEFINE_GRADIENT_PALETTE( heatmap_gp ) {
  0,     0,  0,  0,   //black
128,   255,  0,  0,   //red
224,   255,255,  0,   //bright yellow
255,   255,255,255 }; //full white

CRGB leds[NUM_LEDS];

class LedsMultitask
{
  public:

    pattern ActivePattern;

    unsigned long Interval;
    unsigned long LastUpdate;

    uint16_t TotalSteps;
    int16_t Index;

    uint8_t Hue1;
    uint8_t Value1;
    uint8_t Saturation1;
    uint8_t ColorDistance;

    uint8_t Index_LEDi[5];
    uint16_t NextBlink_LEDi[5];
    
    CRGBPalette16 heatcolorPalette = heatmap_gp;
    CRGBPalette16 lovePalette = love_gp;

        
    LedsMultitask() {};

    void Update()
    {
      if((millis() - LastUpdate) > Interval) // time to update
      {
        LastUpdate = millis();
        switch (ActivePattern)
        {
          case RAINBOW_CYCLE:
             RainbowCycleUpdate();
             break;
          case CANDLE:
             CandleCycleUpdate();
             break;
          case HEAT_COLOR:
              HeatcolorUpdate();
              break;
          case LOVE:
              LoveUpdate();
              break;
          case BLINK:
              BlinkUpdate();
              break;
          default:
            break;
        }
      }
    }

    void Blink()
    {
      ActivePattern = BLINK;
      for (int i = 0; i < 5; i++) {
        Index_LEDi[i] = 0;
        NextBlink_LEDi[i] = millis()+(random16()%5000);
      }
      TotalSteps = 255;
    }

    // Update the Blink pattern
    void BlinkUpdate()
    {
      //Runs through each LED
      for (int i = 0; i < 5; i++)
      {
        //Checks if time now is greater or eaqual to next blink time
        if (millis() >= NextBlink_LEDi[i])
        {
          
          leds[i] = ColorFromPalette( heatcolorPalette, Index_LEDi[i]);   //Sets the color of the LED to a value in a previously generated palette
          Index_LEDi[i]++;                                                //Increases index so that the next color in the palette will be selected on the next round

          //Checks if we have run through the entire color palette
          if (Index_LEDi[i] > TotalSteps)
          {
            Index_LEDi[i] = 0;                                            //Resets the index to 0
            NextBlink_LEDi[i] = millis()+(random16()%50000);              //Generates a new time for the next blink
             //Serial.println("Time until next blink for LED: ");
            //Serial.print(i);
            //Serial.println(NextBlink_LEDi[i]);
          }
        }
      }
      FastLED.show();  
    }
    
    void RainbowCycle()
    {
      ActivePattern = RAINBOW_CYCLE;
      Interval = 100;
      TotalSteps = 255;
      Index = 0;
      Value1 = 255;
      Saturation1 = 255;
      ColorDistance = 100;
    }

    // Update the Rainbow Cycle Pattern
    void RainbowCycleUpdate()
    {
      for (int i = 0; i < NUM_LEDS; i++)
      {
        uint8_t hue = (Index+(i*ColorDistance));
        leds[i] = CHSV(hue, Saturation1, Value1);
      }
      FastLED.show();
      Increment();    
     }


     // CANDLE
     void CandleCycle()
    {
      ActivePattern = CANDLE;
      Interval = 0;
      TotalSteps = 255;
      Index = 0;
      set_color(255);
      index_start = 255;
      index_end = 255;
      state = BRIGHT;
    }

    void CandleCycleUpdate()
    {
      current_time = millis();
    
      switch (state)
        {
        case BRIGHT:
          flicker_msecs = random(DOWN_MAX_MSECS - DOWN_MIN_MSECS) + DOWN_MIN_MSECS;
          flicker_start = current_time;
          index_start = index_end;
          if ((index_start > INDEX_BOTTOM) &&
              (random(100) < INDEX_BOTTOM_PERCENT))
            index_end = random(index_start - INDEX_BOTTOM) + INDEX_BOTTOM;
          else
            index_end = random(index_start - INDEX_MIN) + INDEX_MIN;
    
          state = DOWN;
          break;
        case DIM:
          flicker_msecs = random(UP_MAX_MSECS - UP_MIN_MSECS) + UP_MIN_MSECS;
          flicker_start = current_time;
          index_start = index_end;
          index_end = random(INDEX_MAX - index_start) + INDEX_MIN;
          state = UP;
          break;
        case BRIGHT_HOLD:
        case DIM_HOLD:
          if (current_time >= (flicker_start + flicker_msecs))
            state = (state == BRIGHT_HOLD) ? BRIGHT : DIM;
    
          break;
        case UP:
        case DOWN:
          if (current_time < (flicker_start + flicker_msecs))
            set_color(index_start + ((index_end - index_start) * (((current_time - flicker_start) * 1.0) / flicker_msecs)));
          else
            {
            set_color(index_end);
    
            if (state == DOWN)
              {
              if (random(100) < DIM_HOLD_PERCENT)
                {
                flicker_start = current_time;
                flicker_msecs = random(DIM_HOLD_MAX_MSECS - DIM_HOLD_MIN_MSECS) + DIM_HOLD_MIN_MSECS;
                state = DIM_HOLD;
                }
              else
                state = DIM;
              }
            else
              {
              if (random(100) < BRIGHT_HOLD_PERCENT)
                {
                flicker_start = current_time;
                flicker_msecs = random(BRIGHT_HOLD_MAX_MSECS - BRIGHT_HOLD_MIN_MSECS) + BRIGHT_HOLD_MIN_MSECS;
                state = BRIGHT_HOLD;
                }
              else
                state = BRIGHT;
              }
            }
    
          break;
        }
    }

    void set_color(byte index)
    {
      index = MAXVAL(MINVAL(index, INDEX_MAX), INDEX_BOTTOM);
      if (index >= INDEX_MIN)
      {
        for (int i = 0; i < 5; i++) {
          leds[i] = CRGB(index, (index * 3) / 8, 0);
        }
      }
      else if (index < INDEX_MIN)
      {
        for (int i = 0; i < 5; i++) {
          leds[i] = CRGB(index, (index * 3.25) / 8, 0);
        }
      }
    
      FastLED.show();
    }

    void Heatcolor()
    {
      ActivePattern = HEAT_COLOR;
      Interval = 75;
      TotalSteps = 255;
      Index = 0;
      ColorDistance = 25;
    }
    
    void HeatcolorUpdate()
    {
      for (int i = 0; i < NUM_LEDS; i++)
      {
        uint8_t paletteindex = (Index+(i*ColorDistance));
        leds[i] = ColorFromPalette( heatcolorPalette, paletteindex);
      }
      FastLED.show();
      Increment();
    }

    void Love()
    {
      ActivePattern = LOVE;
      Interval = 75;
      TotalSteps = 255;
      Index = 0;
      ColorDistance = 25;
    }
    
    void LoveUpdate()
    {
      for (int i = 0; i < NUM_LEDS; i++)
      {
        uint8_t paletteindex = (Index+(i*ColorDistance));
        leds[i] = ColorFromPalette( lovePalette, paletteindex);
      }
      FastLED.show();
      Increment();
    }


    // Increment the Index and reset at the end
    void Increment()
    {
      Index++;
      if (Index >= TotalSteps)
      {
        Index = 0;
      }
    }

    void SetHue1(uint8_t hue) {
      Hue1 = hue;
    }
    void SetSaturation1(uint8_t sat) {
      Saturation1 = sat;
    }
    void SetValue1(uint8_t val) {
      Value1 = val;
    }
    void SetInterval(uint8_t inter) {
      Interval = inter;
    }
    void SetColorDistance(uint8_t dist) {
      ColorDistance = dist;
    }
};

LedsMultitask Bordlys;

void setup() {
  FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS);
  randomSeed(analogRead(UNCONNECTED_PIN));
  random16_add_entropy( analogRead(UNCONNECTED_PIN) );
  patternID = 0;
  pinMode(BUTTON, INPUT_PULLUP);
  Bordlys.Blink();
  Serial.begin(9600);
}

void loop() {

  
  Bordlys.Update();
  random16_add_entropy( analogRead(UNCONNECTED_PIN) );
  
  
  buttonState = digitalRead(BUTTON);
  
  if (buttonState != lastButtonState)
  {
    if(buttonState == LOW)
    {
      NextPattern();
    }
  }
  delay(10);
  lastButtonState = buttonState;
}

void NextPattern()
{
  patternID ++;
  if(patternID >= 11)
  {
    patternID = 0;
  }

  switch(patternID)
  {  
      // Candle light  
      case 0:
          Bordlys.CandleCycle();
          break;
      // Standard rainbow
      case 1:
          Bordlys.RainbowCycle();
          Bordlys.SetInterval(100);
          Bordlys.SetColorDistance(100);
          Bordlys.SetValue1(255);
          break;
      // fast rainbow   
      case 2:
          Bordlys.SetInterval(10);
          Bordlys.SetValue1(255);
          Bordlys.SetColorDistance(100);
          break;
      // Standard, dimmed rainbow
      case 3:
          Bordlys.SetInterval(100);
          Bordlys.SetValue1(175);
          Bordlys.SetColorDistance(100);
          break;
      // Fast, dimmed rainbow 
      case 4:
          Bordlys.SetInterval(10);
          Bordlys.SetValue1(175);
          Bordlys.SetColorDistance(100);
          break;
      // Low color distance rainbow
      case 5:
          Bordlys.SetInterval(100);
          Bordlys.SetValue1(255);
          Bordlys.SetColorDistance(25);
          break;
      // Low color distance rainbow, fast
      case 6:
          Bordlys.SetInterval(10);
          Bordlys.SetValue1(255);
          Bordlys.SetColorDistance(25);
          break;
       // Low color distance rainbow, dimmed
      case 7:
          Bordlys.SetInterval(100);
          Bordlys.SetValue1(175);
          Bordlys.SetColorDistance(25);
          break;
      // Low color distance rainbow,dimmed, fast
      case 8:
          Bordlys.SetInterval(10);
          Bordlys.SetValue1(175);
          Bordlys.SetColorDistance(25);
          break;
      // Heat colors
      case 9:
          Bordlys.Heatcolor();
          Bordlys.SetInterval(75);
          Bordlys.SetColorDistance(25);
          break;
      // Love
      case 10:
          Bordlys.Love();
          Bordlys.SetInterval(75);
          Bordlys.SetColorDistance(25);
          break;       
      default:
          break;
  }

  //Serial.println(patternID);
}
 
Last edited:
As I mentioned in other thread, I would maybe change some of the uint16_t values to uint32_t values.

As for println... I would probably start up your code at the start something like:
Code:
void setup() {
    while (!Serial() && (millis() < 3000)) ; // wait until serial port is created
    Serial.begin(115200);
    delay (250);
    Serial.println("Program started");
...
The above code gives time for the serial port initialize and outputs something so you can make sure it did start plus if you get that message again it shows the program faulted and started over...

You might take a different approach for handling the timing and instead of doing your own check for millis, you could used the teensy object elapsedMillis.

With this you could keep an array of these, where when the elapsedMillis is nice wrapper class that makes it easier to deal with timers and not have to worry about overflows and the like.

Where you might have something like:
Code:
   elapsedMillis leds_elapsed[5]; 
   uint16_t next_times[5];

    .... 

   if (leds_elapsed[i] > next_times[i]) {
       do your stuff
        leds_elapsed[i] = 0;
        next_times[i] = random16()%50000;
    }
This handles the issues of overflows. That is if your random can use up almost all of your int16_t max value, when you add it onto your current millis() which is 32 bits and then it is truncated to 16 bits, you can easily have the issue that resultant is less than the current millis()...
 
I'm working on this now, and indeed it's a very strange problem.

These 2 lines appear to be the main issue, but I don't know enough about the FastLED internals yet to understand why they cause a crash.

Code:
    CRGBPalette16 heatcolorPalette = heatmap_gp;
    CRGBPalette16 lovePalette = love_gp;
 
Well, I trimmed it down to just this:

Code:
#include "FastLED.h"

DEFINE_GRADIENT_PALETTE( heatmap_gp ) {
  0,   0,   0,   0,   //black
128, 255,   0,   0,   //red
224, 255, 255,   0,   //bright yellow
255, 255, 255, 255 }; //full white

class LedsMultitask {
  CRGBPalette16 heatcolorPalette = heatmap_gp;
};

// Run on Teensy LC to reproduce this problem.

// merely having this object created causes the program to crash
// comment out this line to get see the 3 Serial.print() output
LedsMultitask Bordlys;

void setup() {
  while (!Serial) ; // wait for Arduino Serial Monitor
  delay(10);
  Serial.println("setup begin");
  Serial.println("setup2"); // must print 2+ strings to reproduce problem
  Serial.println(sizeof(LedsMultitask));
}

void loop() {
}

I posted a question on the FastLED Google+ group. I'm afraid this is getting much deeper into FastLED than I can reasonably troubleshoot....
 
Seems to be an alignment problem, FastLED library reads gradient palette information in dword chunks.

Code:
__attribute__ ((aligned (4)))  DEFINE_GRADIENT_PALETTE( heatmap_gp ) {

This keeps the program alive, changing the number of characters in the print statements can also give the same effect.
 
Last edited:
fastled_progmem.h:
#define FL_PGM_READ_DWORD_NEAR(x) (*((const uint32_t*)(x)))

That's just wrong. It violates aliasing rules and relies on undefined behavior. If it works or not is playing russian roulette.

In this case, an uint8_t[] array is read as uint32_t[].
 
I've got to say I think it's really cool that you went back to my post and figured this out!
This problem, I realise, was way beyond me, but I find it really interesting to read about what was actually causing the problem!

Great work! :)
 
I exchanged a few messages yesterday with Mark, one of the FastLED authors. We sent him a Teensy LC for testing. He saw the latest info here and understands the problem. Odds are good he'll commit a permanent fix to FastLED in a week or two.
 
Thanks Paul, and everyone for help in isolate the problem here. It's now found and fixed. I've just committed a fix to the FastLED github repository that fixes this on TeensyLC, and other ARM-based boards that might have had the same situation. We love the Teensy boards, and are happy to support them in FastLED.
 
Status
Not open for further replies.
Back
Top