Losing part of serial input when using FastLED.addLeds

Yes, if you are an experienced programmer. By that I mean one with enough experience to understand your wonderful (no sarcasm intended) article. It is very well written, but will go completely over the heads of most beginners here. They are several years away from that level and most will never reach it.

That's exactly the kind of thing beginners do. They don't write it themselves, they "find it on the web" where it may have been written by someone with only a little more experience than themselves, and for a completely different environment, but they don't know that.

We recommend beginners not to use Strings. We recommend them not to mess with mains AC voltages too. Both can be used with complete safety by someone with sufficient experience!

Who is 'we', "Which people. What are their names!" (as Margret Thatcher said when an interviewer said 'some people say your are a hard lady")

That position is NOT very defensible because Arduino CC devotes a significant portion of the 'beginners' Arduino Language Reference to Strings.
Strings are the only text manipulation methods in the Reference.
That combined with the bullet proof way they run on Uno / Mega makes Strings ideal for beginners.
Even using the + operator, they are much safer and simpler than the alternatives. You missed the point that Strings are bullet proof on Uno/Mega even if beginners don't follow my guidelines.

Strings provide intuitive high level functions and remove the need for beginners having to worry about missing null terminators, off-by-one indexing, precise char array sizing or buffer overflow.

All beginners should start with Strings. As their sketches become more complex then they can start following the guidelines I have published, but beginners don't need to start there.

You see, i already mentioned this in the 'do you like the new forum thread' that these threads are not discussions, unless.... it is about 'Strings'.

The 'String' class it self may be bullet proof, but if the heap is full of String, and there is a function that needs part of the stack, it is not going to free that up for it. It's like wearing a bullet proof vest and getting shot in the head.

Which is highly educative. I think it is good people are aware of limitations, but then i learned programming on a 1K RAM 8k ROM machine that i could connect to the TV.
Anyway let the OP figure out what he want to do, in my opinion, if you have a big buffer (like 250 leds, wow that is more than a universe) you should not be doubling up on it.

It does not need to. On Uno and Mega2560 the malloc ensures there is always 128 bytes available for program stack. Which is why String are essentially bullet proof on those original small Arduino boards. Check out the out-of-memory example sketches in my tutorial.

Beginners cannot learn very thing at once. Using Strings safely postpones some of that learning until later. Here the OP's problem is not that they are using Strings but that they are trying to hold too much data in RAM at the same time. Moving away from the safety of Strings will not fix that.

You are the first senior forum member I can remember who has defended use of Strings by beginners at all, especially with such conviction and authority. Bravo. I'm still not entirely sure how what you say about it being "bullet proof" can be true on a system with no garbage collection, but I will try to stay open minded about it and look at the evidence as it arrives.

Ok as an update I have managed to get it to do what I want by splitting string into smaller chunks in the app and sending them one at a time with a delay in between this works fine.

thank you for your help, well most of you anyway.

Now it is working I have time to try out some of your suggestions. I am trying to process the data on the fly but I was wondering how to empty the buffer after the LED has been lit. here is my code (Now in code tags :wink:

#include <Wire.h>

#include <FastLED.h>

// How many leds in your strip?
#define NUM_LEDS 200
//1602  outside wire SCL to A5  SDA to A4
#define DATA_PIN 13

#define BRIGHTNESS  255;

CRGB leds[NUM_LEDS];

String inputString = "";         // a String to hold incoming data
bool stringComplete = false;  // whether the string is complete


String colHa="";
String colBa="";
String colFa="";
String ledNo="";

String Red1="";
String Green1="";
String Blue1="";
String allLeds="";

String colH ="255, 0, 0";
String colB ="0, 255, 0";
String colF ="0, 0, 255";
int ind1;


void setup() {
  // initialize serial:
  Serial.begin(9600);
  
  Serial.println("serial delimit test 28-4-21"); // so I can keep track of what is loaded
  FastLED.addLeds<WS2811, DATA_PIN, GBR>(leds, NUM_LEDS);  // GRB ordering is typical
  
}

void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
      
    inputString = "\0";
    
     
    stringComplete = false;
    
  }
}


void serialEvent()
{
  // sterretje: changed while to if
  if (Serial.available()) {
    
    char inChar = (char)Serial.read();

    // sterretje: echo received character
    Serial.write(inChar);

    
    inputString += inChar;
   
    if (inChar == '$') {
         getLEDS2();     
      }
    
  }
}      
      
void getLEDS2(){
        
        allLeds=inputString;
        Serial.println("after star "+allLeds);
        delay(40);
         
        
        //Serial.println(inputString);
        //delay(100);
        
        
          
        
                ind1 = allLeds.indexOf(',');  //finds led no
                ledNo = allLeds.substring(0, ind1);
                allLeds.remove(0, ind1 + 1);
                delay(10);
                Serial.println(ledNo);
                if (ledNo != ""){

                  colHa = colH;
                  delay(0);
                  colBa = colB;
                  delay(0);
                  colFa = colF;
                  delay(0);
                  //Serial.println("colH "+colH);
                  Serial.println("colHa "+colHa+" "+colBa+" "+colFa);
                  delay(10);

                  
                  ind1 = allLeds.indexOf('$');  
                  String whichH = allLeds.substring(0, ind1);   
                  allLeds.remove(0, ind1 + 1);
                  delay(0);
                  
                  if(whichH=="h"){
                    //Serial.println(whichH+" - "+colHa)  ;
                     ind1 = colHa.indexOf(',');
                     Red1=colHa.substring(0, ind1);
                     colHa.remove(0, ind1 + 1);
                     ind1 = colHa.indexOf(',');
                     Green1=colHa.substring(0, ind1);
                     colHa.remove(0, ind1 + 1);
                     ind1 = colHa.indexOf(',');
                     Blue1=colHa.substring(0, ind1);
                     colHa.remove(0, ind1 + 1);
                  }
                  else if(whichH=="b"){
                    //Serial.println(whichH+" - "+colBa)  ;
                     ind1 = colBa.indexOf(',');
                     Red1=colBa.substring(0, ind1);
                     colBa.remove(0, ind1 + 1);
                     ind1 = colBa.indexOf(',');
                     Green1=colBa.substring(0, ind1);
                     colBa.remove(0, ind1 + 1);
                     ind1 = colBa.indexOf(',');
                     Blue1=colBa.substring(0, ind1);
                     colBa.remove(0, ind1 + 1);
                  }
                  else if(whichH=="f"){
                   //Serial.println(whichH+" - "+colFa)  ;
                     ind1 = colFa.indexOf(',');
                     Red1=colFa.substring(0, ind1);
                     colFa.remove(0, ind1 + 1);
                     ind1 = colFa.indexOf(',');
                     Green1=colFa.substring(0, ind1);
                     colFa.remove(0, ind1 + 1);
                     ind1 = colFa.indexOf(',');
                     Blue1=colFa.substring(0, ind1);
                     colFa.remove(0, ind1 + 1);
                  }  
                   Serial.println("conq "+ledNo+" "+Red1+" "+Blue1+" "+Green1);
                   delay(20);
                   colHa="";
                   colBa="";
                   colFa="";
             
                   leds[ledNo.toInt() - 1] = CRGB(Red1.toInt(), Blue1.toInt(), Green1.toInt()); //writes info to leds
                   FastLED.show();
                   delay(20);






               
            

           }
                  
                  allLeds="\0";
                  stringComplete = true;

}


and here is a sample of the string data

21,h$10,h$1,h$3,h$4,h$20,h$19,h$18,h$25,h$24,h$23,h$22,h$41,h$40,h$39,h$45,h$44,h$43,h$86,h$82,h$83,h$65,h$66,h$102,h$108,h$107,h$106,h$87,h$111,h$100,h$99,h$90,h$110,h$

and the com monitor return

serial delimit test 28-4-21
21,h$after star 21,h$
21
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 21 255  0  0
10,h$after star 10,h$
10
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 10 255  0  0
1,h$after star 1,h$
1
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 1 255  0  0
3,h$after star 3,h$
3
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 3 255  0  0
4,h$after star 4,h$
4
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 4 255  0  0
20,h$after star 20,h$
20
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 20 255  0  0
19,h$after star 19,h$
19
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 19 255  0  0
18,h$after star 18,h$
18
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 18 255  0  0
25,h$after star 25,h$
25
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 25 255  0  0
24,h$after star 24,h$
24
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 24 255  0  0
23,h$after star 23,h$
23
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 23 255  0  0
22,h$after star 22,h$
22
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 22 255  0  0
41,h$after star 41,h$
41
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 41 255  0  0
40,h$after star 40,h$
40
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 40 255  0  0
36,h$after star 36,h$
36
colHa 255, 0, 0 0, 255, 0 0, 0, 255
conq 36 255  0  0
1

as you can see the string after $40,h is corrupt. Also I am unsure what is necessary for a blank string in my instance.

inputString = ""; or  inputString = "\0"; 
inputString = ""; 

Actually this is a situation in which a blocking reception of Serial is more appropriate, but if you can create a bit more time between transmission, even by putting a few dummy characters in, you will probably be ok.

21,h$...10,h$...1,h$...3,h$...4,h  etc

and then

(---
    Serial.write(inChar);    
    if (inchar != '.') inputString += inChar;  // discard the dummy character   
    if (inChar == '$') {
---) etc

The more leds, the more dummy characters you may need, the higher the baud-rate the more dummy characters. If you can just make the sender wait a little after sending the '$' that works as well of course, just enough time to make sure the show() has been completed and interrupts are enabled again.

thank you !!! :grinning: I would never of thought of this and I have learnt a little more about the peculiarities of coding the arduino. In the end I got rid of as many of the delays as possible and I had to add a ridiculous number of fullstops but it works (maybe I could lose a few I'll have to experiment). Here is the finished code. and a sample of the serial string.

#include <Wire.h>

#include <FastLED.h>

// How many leds in your strip?
#define NUM_LEDS 250
//1602  outside wire SCL to A5  SDA to A4
#define DATA_PIN 13

#define BRIGHTNESS  255;

CRGB leds[NUM_LEDS];

String inputString = "";         // a String to hold incoming data
bool stringComplete = false;  // whether the string is complete


String colHa="";
String colBa="";
String colFa="";
String ledNo="";

String Red1="";
String Green1="";
String Blue1="";
String allLeds="";

String colH ="255, 0, 0";
String colB ="0, 255, 0";
String colF ="0, 0, 255";
int ind1;


void setup() {
  // initialize serial:
  Serial.begin(9600);
  
  Serial.println("serial delimit test 28-4-21"); // so I can keep track of what is loaded
  FastLED.addLeds<WS2811, DATA_PIN, GBR>(leds, NUM_LEDS);  // GRB ordering is typical
  
}

void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
    inputString = "\0";
    stringComplete = false;
   }
}


void serialEvent()
{
  // sterretje: changed while to if
  if (Serial.available()) {
    
    char inChar = (char)Serial.read();

    // sterretje: echo received character
    //Serial.write(inChar);

    
    if (inChar != '.') inputString += inChar;
       
    if (inChar == '$') {
         //inChar='\0';
         getLEDS2();     
      }
    
  }
}      
      
void getLEDS2(){
        
        allLeds=inputString;
        Serial.println("after star "+allLeds);
        delay(40);
         
        
        //Serial.println(inputString);
        //delay(100);
        
        
          
        
                ind1 = allLeds.indexOf(',');  //finds led no
                ledNo = allLeds.substring(0, ind1);
                allLeds.remove(0, ind1 + 1);
                //delay(10);
                //Serial.println(ledNo);
                if (ledNo != ""){

                  colHa = colH;
                  delay(0);
                  colBa = colB;
                  delay(0);
                  colFa = colF;
                  delay(0);
                  //Serial.println("colH "+colH);
                  //Serial.println("colHa "+colHa+" "+colBa+" "+colFa);
                  delay(0);

                  
                  ind1 = allLeds.indexOf('$');  
                  String whichH = allLeds.substring(0, ind1);   
                  allLeds.remove(0, ind1 + 1);
                  delay(0);
                  
                  if(whichH=="h"){
                    //Serial.println(whichH+" - "+colHa)  ;
                     ind1 = colHa.indexOf(',');
                     Red1=colHa.substring(0, ind1);
                     colHa.remove(0, ind1 + 1);
                     ind1 = colHa.indexOf(',');
                     Green1=colHa.substring(0, ind1);
                     colHa.remove(0, ind1 + 1);
                     ind1 = colHa.indexOf(',');
                     Blue1=colHa.substring(0, ind1);
                     colHa.remove(0, ind1 + 1);
                  }
                  else if(whichH=="b"){
                    //Serial.println(whichH+" - "+colBa)  ;
                     ind1 = colBa.indexOf(',');
                     Red1=colBa.substring(0, ind1);
                     colBa.remove(0, ind1 + 1);
                     ind1 = colBa.indexOf(',');
                     Green1=colBa.substring(0, ind1);
                     colBa.remove(0, ind1 + 1);
                     ind1 = colBa.indexOf(',');
                     Blue1=colBa.substring(0, ind1);
                     colBa.remove(0, ind1 + 1);
                  }
                  else if(whichH=="f"){
                   //Serial.println(whichH+" - "+colFa)  ;
                     ind1 = colFa.indexOf(',');
                     Red1=colFa.substring(0, ind1);
                     colFa.remove(0, ind1 + 1);
                     ind1 = colFa.indexOf(',');
                     Green1=colFa.substring(0, ind1);
                     colFa.remove(0, ind1 + 1);
                     ind1 = colFa.indexOf(',');
                     Blue1=colFa.substring(0, ind1);
                     colFa.remove(0, ind1 + 1);
                  }  
                   
             
                   leds[ledNo.toInt() - 1] = CRGB(Red1.toInt(), Blue1.toInt(), Green1.toInt()); //writes info to leds
                   FastLED.show();
                   delay(20);
Serial.println("conq "+ledNo+" "+Red1+" "+Blue1+" "+Green1);
                   delay(0);
                   colHa="\0";
                   colBa="\0";
                   colFa="\0";





               
            

           }
                  
                  allLeds="\0";
                  stringComplete = true;

}

the input

21,h$................................................................10,f$................................................................1,h$................................................................3,h$................................................................4,h$................................................................20,h$................................................................19,h$................................................................18,h$................................................................25,b$................................................................24,h$................................................................23,h$................................................................22,h$................................................................41,h$................................................................40,f$................................................................39,h$................................................................45,h$................................................................44,h$................................................................43,b$................................................................86,h$................................................................82,h$................................................................83,h$................................................................65,h$................................................................66,h$................................................................102,h$................................................................108,h$................................................................107,h$................................................................106,h$................................................................87,h$................................................................111,h$................................................................100,h$................................................................99,h$................................................................90,h$................................................................110,h$................................................................109,h$................................................................122,h$................................................................121,h$................................................................120,h$................................................................130,h$................................................................123,h$................................................................71,h$................................................................72,h$................................................................76,h$................................................................92,h$................................................................77,h$................................................................78,h$................................................................70,h$................................................................97,h$................................................................93,h$................................................................98,h$................................................................91,h$................................................................75,h$................................................................74,h$................................................................96,h$................................................................13,b$................................................................14,h$................................................................12,h$................................................................30,h$................................................................29,h$................................................................35,h$................................................................34,h$................................................................33,h$................................................................32,h$................................................................52,h$................................................................46,h$................................................................38,h$................................................................166,h$................................................................165,h$................................................................172,h$................................................................170,h$................................................................149,h$................................................................150,h$................................................................187,h$................................................................188,h$................................................................169,h$................................................................148,h$................................................................146,h$................................................................145,h$................................................................144,h$................................................................151,h$................................................................164,h$................................................................161,h$................................................................160,h$................................................................155,h$................................................................156,h$................................................................139,h$................................................................177,h$................................................................175,h$................................................................141,h$................................................................154,h$................................................................140,h$................................................................158,h$................................................................157,h$................................................................138,h$................................................................137,h$  etc etc etc

I tested it with 624 items and it did not break. Thanks again.

void getLEDS2(){
        
        allLeds=inputString;
        Serial.println("after star "+allLeds);
        delay(40);

If you remove that last one, you should be able to remove nearly 40 full stops.

If you optimize the part that actually assigns the color to the led, you can save more time.
The String class is rather slow, and totally redundant for this purpose.

CRGB newColor;

There is absolutely no need to parse colH, colB & colF or to store that information in a String.
In fact for the basic colors there are definitions already within the FastLED library

else if(whichH=="f"){
                   newColor = CRGB::Green;
                   //Serial.println(whichH+" - "+colFa)  ;
                   /*  ind1 = colFa.indexOf(',');
                     Red1=colFa.substring(0, ind1);
                     colFa.remove(0, ind1 + 1);
                     ind1 = colFa.indexOf(',');
                     Green1=colFa.substring(0, ind1);
                     colFa.remove(0, ind1 + 1);
                     ind1 = colFa.indexOf(',');
                     Blue1=colFa.substring(0, ind1);
                     colFa.remove(0, ind1 + 1);*/
                  }           

even to first assign it to newColor is a bit of a detour, but nothing compared to what you are doing.

leds[ledNo.toInt() - 1] = newColor;

You could even revert back to you original setup, although i suggest that for colors you switch to hexadecimal representation, (#00FF00 for green or just leave ity as it is, you will need to create a parser for the HEXdata) , parse the led info as it comes in (so you don't double up on the buffer) And use a separate 'endmarker' for when the message is complete. **Only then **do you call .show() Remember it is the calling of show() that disturbs the Serial reception now. As before it was the doubling up on the buffer.

I can try, but when I was experimenting before the allLeds var did not seem to accept the whole value of the inputString parts were missing, so I added a delay to allow it to become the same as the input. The main change was after removing the Serial.write I read this blocks the serial if the buffer is full. Do you know how to clear the buffer after processing the code?

the colours are only for this sample sketch the actual colours will be sent from the app I just wanted to simplify it as much as possible to get it to work. I could try to send hexcolours from the app , but wouldn't they be in the form of a string which would need converting to hex? there'll probably be a string to hex function like .toint()

I didn't realise that I could call the .show() function just at the end I thought it was necessary to call it after every statement I'll have at look at that as well.

I have been programming for a long time but never with such a lack of memory, I am self taught so even though stuff works for me I'm sure it can be coded much more efficiently. Thanks again.

In theory you you could even send them as raw bytes, but then you have no characters to tell you where to start.
Sending a HEX value is smaller and more efficient to parse than numeric values (i was going to say easier, but there isn't a ready made function) the size is always the same. And i have a function for it already made, let me look that up.

uint32_t HexColor(String colorcode) {
  if ((colorcode.length() != 7) || (colorcode.charAt(0) != '#')) return 0xFFFFFFFF;
  uint32_t color = 0;
  for (uint8_t i = 1; i < 7; i++) {
    color = color << 4;
    char c = colorcode.charAt(i);
    if ((c >= '0') && (c <= '9')) {
      color = color + (c - '0');
    }
    else if ((c >= 'A') && (c <= 'F')) {
      color = color + (c - 'A') + 10;
    }
    else if ((c >= 'a') && (c <= 'f')) {
      color = color + (c - 'a') + 10;
    }
    else {
      return 0xFFFFFFFF;
    }
  }
  return color;
}

The function takes '#rrbbgg' as HEX as an argument and returns the 24-bit color code as a uint32_t , which i think you can just cast to a CRGB.
You can a;lso modify the function to just return a CRGB, but then you will not get an error-code if the String doesn't meet the requirements.

1 Like

Well it's the show() function that is causing the trouble,
My suggestion is simply parse as the data is coming in.
Don't double up on the buffer.
Call show() in a moment that you are not expecting to receive relevant information.
There has always been the discussion on the forum that 'non-blocking code' is preferred over 'blocking-code' , and i've always maintained that there are situation in which 'blocking code' is more appropriate.

I added an end of line delimiter which when caught resets my colour variables and forces the show. It works just fine, I have also vastly reduced the number of full stops, it is very stable and I seem to be able to light unlimited leds. For testing I want to light everything for a a couple of seconds followed by a rgb sequence from the start to the end. My test board only has 60 leds and later on in the week I want to test all 200. Thank you very much for your assitance, I will look at the colour options to further speed it up. :slightly_smiling_face:

This function works fine Deva_Rishi :grinning: I now send hex colours from the app and using your function convert them to the uint32_t long int which goes straight into the fastleds CRGB. Now it is much more stable and quicker

Great !

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.