Losing part of serial input when using FastLED.addLeds

Hi, I am new to arduino and have come across a problem which I am unable to solve at the moment . I am using the standard SerialEvent example to receive bluetooth input fron an android app to a hc-06.
Instead of “\n” I have used a “*” as the last character.
Everything works and the serial monitor returns all of the input including the end star.
So building on this I added extra code line by line and when I add the FastLED.addLeds… line then the return to the Serial Monitor becomes truncated, what can I do to keep the integrity of the input.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#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 200;

CRGB leds[NUM_LEDS];

String inputString = “”; // a String to hold incoming data
bool stringComplete = false;

void setup() {
Serial.begin(9600);

Serial.println(“serial delimit test 11-12-13”); // so I can keep track of what is loaded
FastLED.addLeds<WS2811, DATA_PIN, GBR>(leds, NUM_LEDS); // GRB ordering is typical
// for (int i = 0; i <= NUM_LEDS; i++) {
// leds[i] = CRGB(0,0,0);
// FastLED.show();

//}
lcd.begin();
lcd.clear();
inputString.reserve(2000);
//CheckDisplays();
}

void loop() {
// print the string when a newline arrives:
if (stringComplete) {
Serial.println(inputString);
// clear the string:
inputString = “”;
stringComplete = false;
}
}

/*
SerialEvent occurs whenever a new data comes in the hardware serial RX. This
routine is run between each time loop() runs, so using delay inside loop can
delay response. Multiple bytes of data may be available.
/
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag so the main loop can
// do something about it:
if (inChar == '
’) {
stringComplete = true;
}
}
}

truncated it becomes 104%Derek Brookes%modified:%28.4.2021%5C%cenph%21,0,255,0$10,0,255,0$1,0,255,0$3,0,255,0$4,0,255,0$20,0,255,0$19,0,255,0$18,0,255,0$25,0,255,0$24,0,255,0$23,0,255,0$22,0,255,0$41,0,255,0$40,0,255,0$39,0,255,0$45,0,255,0$44,0,255,0$43,0,255,0$86,0,255,0$82,0,255,0$83,0,255,0$65,0,255,0$66,0,255,0$102,0,255,0$108,0,255,0$107,0,255,0$106,0,255,0$87,0,255,0$111,0,255,0$100,0,255,0$99,0,255,0$90,0,255,0$110,0,255,0$109,0,255,0$122,0,255,0$121,0,255,0$120,0,255,0$130,0,255,0$123,0,255,0$71,0,255,0$72,0,255,0$76,0,255,0$92,0,255,0$77,0,255,0$78,0,255,0$70,0,255,0$97,0,255,0

it should be
104%Derek Brookes%modified:%28.4.2021%5C%cenph%21,0,255,0$10,0,255,0$1,0,255,0$3,0,255,0$4,0,255,0$20,0,255,0$19,0,255,0$18,0,255,0$25,0,255,0$24,0,255,0$23,0,255,0$22,0,255,0$41,0,255,0$40,0,255,0$39,0,255,0$45,0,255,0$44,0,255,0$43,0,255,0$86,0,255,0$82,0,255,0$83,0,255,0$65,0,255,0$66,0,255,0$102,0,255,0$108,0,255,0$107,0,255,0$106,0,255,0$87,0,255,0$111,0,255,0$100,0,255,0$99,0,255,0$90,0,255,0$110,0,255,0$109,0,255,0$122,0,255,0$121,0,255,0$120,0,255,0$130,0,255,0$123,0,255,0$71,0,255,0$72,0,255,0$76,0,255,0$92,0,255,0$77,0,255,0$78,0,255,0$70,0,255,0$97,0,255,0$93,0,255,0$98,0,255,0$91,0,255,0$75,0,255,0$74,0,255,0$96,0,255,0$13,0,255,0$14,0,255,0$12,0,255,0$30,0,255,0$29,0,255,0$35,0,255,0$34,0,255,0$33,0,255,0$32,0,255,0$52,0,255,0$46,0,255,0$38,0,255,0$166,0,255,0$165,0,255,0$172,0,255,0$170,0,255,0$149,0,255,0$150,0,255,0$187,0,255,0$188,0,255,0$169,0,255,0$148,0,255,0$146,0,255,0$145,0,255,0$144,0,255,0$151,0,255,0$164,0,255,0$161,0,255,0$160,0,255,0$155,0,255,0$156,0,255,0$139,0,255,0$177,0,255,0$175,0,255,0$141,0,255,0$154,0,255,0$140,0,255,0$158,0,255,0$157,0,255,0$138,0,255,0$137,0,255,0$178,0,255,0$181,0,255,0$182,0,255,0$176,0,255,0$159,0,255,0$2,255,0,0$112,255,0,0$8,255,0,0$51,0,0,255$37,0,0,255$*

Welcome,

This line for (int i = 0; i <= NUM_LEDS; i++) should be for (int i = 0; i < NUM_LEDS; i++) else it will write outside the leds array.

thank you when I get there I will change this, but this line is not used at this time

What type of Arduino? Many do not have sufficient memory for

inputString.reserve(2000);

Also please correct your original post and add code tags.

Yes I suspect you ran out of memory, some arduino boards only have 2kB of SRAM. It does not warn you when you compile because inputString.reserve(2000); is doing dynamic memory allocation.

One solution is to not store such long string, instead process it as it comes

it is a chinese nano, but it works ok I’m sorry what are code tags?

NeoPixels have critical timing when you update the strip; for that reason interrupts are disabled during the update.

Serial input on the Arduino makes use of interrupts to store received data in the background and that will fail. My solution is to use a protocol with a handshake between Arduino and sender; the basics are

  1. Sender sends one byte / character to Arduino
  2. Arduino echoes (sends) it back to sender when it reads the character.
  3. Only when sender receives the echo, it will send the next byte / character.
  4. Back to (2).
2 Likes

ok thanks it sounds rather complicated, I only send out a string from the android app it doesn’t receive anything back from the android, is there a way to receive the whole string before parsing it and sending it to the fastled. If you notice from my code this is barebones, nothing is being sent as yet to the fastled all it is doing is adding the leds in setup. What was interesting was when I sent the initial string it was received whole, I eas able to parse it and all of the leds lit correctly (I haven’t includes this code yet) only subsequent sends were truncated

… process it as it comes, I was waiting for the eol * o start to parse the result, how can I start to process it without the eol marker , I apologise if I sound naive I have little experience with arduino and serial coms

You have another marker to delimit “commands”, the $ character. You could store until this character, process the “command”, reset and repeat until *.

Also it seems the data between two $ are always 4 values between 0 and 255, but you send them as characters. This could be improved by sending 4 bytes instead of up to 15 characters “255,255,255,255”

code-tags can be initiated by hitting the </> in the composer window.
A nano has 2048kb of RAM

inputString.reserve(2000);

You can reserve all you want, but what isn’t there isn’t there.
When you compile only memory declared on the stack is counted and what you have left is not counting anything that is declared on the heap (the ‘String’ you are using) and any variables declared locally.

thanks, I have also thought that I am repeating myself too much with the string the first number is the number of the LED and the next three r,g,b colours, as these never change I will define them at the beginning of the string and then give them a number1-3 thus reducing the string vastly ie 104%Derek Brookes%modified:%28.4.2021%5C%cenph%255,0,0%0,255,0%0,0,255%21,2$10,1$ …

So you are saying that this :

21,0,255,0

are actually 4 individual bytes ? now they are represented by 10 bytes + separator = 11 bytes.
I suggest you first decide how much information you send, then send out that part of the info, then send the info in the most packet form, being just the bytes as bytes.
But regardless of that, unless you can control specifically when you transmit this information, and you do so while your program is sending a ws2811 signal, you data is going to be corrupted.
So if you fix this now, a new problem will arise once you do start calling show();

Nano has 2K ram memory. The data for your LEDs take nearly half of that. You don’t have enough memory to reserve 2K for a String variable. Using String variables is not recommended on Arduino, especially those with limited memory. As @guix said, there is no need to read all the data into memory and then process it. You can read it in smaller chunks and process each chunk before reading the next. A “chunk” could be a single character, a number, or part of the data up to a marker character such as a ‘$’.

All new forum members should read the guide posts before posting, so they understand the need for things like code tags and how to use them. Unfortunately, it is much easier to not read the guide and then apologise for breaking the rules after, using the excuse of being new to the forum.

Code tags put your code into a window with a scroll bar, and prevents the forum software from corrupting the code you post by removing indentation, or incorrectly interpreting certain character sequences as formatting changes. You may have noticed the code in your post no longer exactly matches how it looks in the IDE?

thank you, about the code tags, the inputString.resrve was initially set at 200 it didn’t do anything when I set it higher. I am reducing the string but will have to learn how to send and receive bytes (and what to do with them when I’ve got them)

Actually thinking about it, it doesn’t really matter what you do with the format so much, as long as you do not wait with executing the orders until the complete message has come in.

104%Derek Brookes%modified:%28.4.2021%5C%cenph%

This section as it comes in can either be discarded or stored depending on it having any information that you want to use, but also then you should extract that as soon as it has come in.
Every time you have a complete section of this :

21,0,255,0$

you should simply transfer that information to the led output buffer straight away:

leds[21] = CRGB (0, 255, 0);

after which you can clear that part of the buffer. Now your input buffer only needs to be a fraction of what it was before.

I did not even notice that you were not controlling the leds yet :frowning: Probably too early in the morning :slight_smile:

Anyway, this is the change for your current code in the serialEvent

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

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

    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

I don’t know anything about cell phone apps but you have to send one character, wait for the echo etc.

You should check the result of inputString.reserve(). It returns 0 if it fails and 1 if it succeeds; unfortunately the reference does not mention that (it was reported long ago) but the source code shows it

unsigned char String::reserve(unsigned int size)
{
	if (buffer && capacity >= size) return 1;
	if (changeBuffer(size)) {
		if (len == 0) buffer[0] = 0;
		return 1;
	}
	return 0;
}

thanks Devak_Rishi I will look at that next at the moment I am trying to get the three colours into separate variables which can be passed to the leds crgb function instead of sending them over and over

thank you there is so much help here I will look into it

Nothing wrong with Strings even for limited memory. On uno/mega they are essentially bullet proof even after you run out of memory.

See my tutorial on Taming Arduino Strings
Check the return value from reserve( ) (in setup() ) as noted in #17 to see if you have enough memory
e.g.

  if (!string3.reserve(930)) { // do largest last and check its return
      Serial.println(F("Strings out-of-memory"));
  }

Even if the reserve() fails, the String will still work but just not to that length. When it runs out of memory it just stops adding text, but the rest of the program keeps running on Uno and Mega2560 due to the way the malloc is coded.