Neopixel Show() interrupting serial communication

darnegar:
This is the pi running with 2 arduinos hooked up in a ...

I don't see any evidence that you are reading the Replies that people are taking time to give you. Certainly you are not responding to them.

...R

Sorry, forgot to mention the changes that I made.

  1. moved changecolours() to loop, added 50ms timer to it.
  2. tried Serial.flush(), same outcome.
  3. removed noInterrupts() and interrupts() from changecolours, since the strip.show() handles that.
  4. removed commented out noInterrupts() and interrupts() from recv function.

Did I miss anything else?

Current code:

//#include <LiquidCrystal.h>
#include <stdio.h>
#include <stdlib.h>
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include <VL53L0X.h>
VL53L0X sensor;
#include <elapsedMillis.h>
elapsedMillis timeElapsed; //declare global if you don't want it reset every time loop runs
#define PIN 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(18, PIN, NEO_GRB + NEO_KHZ800);
#define LONG_RANGE
//LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
char tmp[2] = "";
const int numChars = 500;
char receivedChars[numChars];
int init_index = 0;
int permanent_rgb[3] = {0, 0, 0};
int signal_rgb[3] = {0, 0, 0};
int sensor_location = 0;
bool chk = false;
boolean newData = false;
int strLength = 0;
int counter = 0;
bool mutex = true;
void setup() {
  timeElapsed = 0;
  strip.begin();

  //strip.show() causes I/O problems with serial -> interrupts
  strip.show(); // Initialize all pixels to 'off'
  Serial.begin(115200);
  Wire.begin();
  sensor.init();

  sensor.setTimeout(500);
  sensor.setMeasurementTimingBudget(33000);
  sensor.setSignalRateLimit(0.1 * 65536);
  sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
  sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);

  sensor.startContinuous();
}
void changecolours() {

  byte count = 0;
  int diff_rgb = 0;
  for (int i = 0; i < 3; i++) {
    diff_rgb = signal_rgb[i] - permanent_rgb[i];

    if (diff_rgb > 0) {
      permanent_rgb[i] += 2;

    }
    else if (diff_rgb < 0) {
      permanent_rgb[i] -= 2;
    }
    else count++;

  }
  if (count == 3)return;
  for (int j = 0; j < 18; j++) {
    strip.setPixelColor(j, permanent_rgb[0], permanent_rgb[1], permanent_rgb[2]);

  }

  strip.show();  //this is breaking my signal sent back

}
void loop() {
  recvWithStartEndMarkers(); //parse signal

  if (newData == true) {
    signalBuild();  //send new signal
    newData = false;
  }

  if (timeElapsed > 50) {
    changecolours();  //this is breaking my signal sent back
    timeElapsed = 0;
  }





}

void parseSign() {  //parse the sign into a string

  //bool chk = false;

  sensor_location = init_index;

}


void buildIndex() { //building of index into new sign

  char tmp[3];

  tmp[0] = receivedChars[0];
  tmp[1] = receivedChars[1];

  init_index = atoi(tmp);

  itoa(init_index + 1, tmp, 10);

  if ((init_index + 1) < 10) {
    receivedChars[0] = '0';
    receivedChars[1] = tmp[0];
  } else {
    receivedChars[0] = tmp[0];
    receivedChars[1] = tmp[1];
  }
  //Serial.print(sign);
}


void buildSensor() { //building of sensor values into new sign
  char sens;
  int newValue;
  int range = sensor.readRangeContinuousMillimeters();

  //newValue = range;
  newValue = range / 26 + 97;
  //bring newValue to ASCII/Alphabet character
  sens = newValue;
  receivedChars[sensor_location] = sens;
}

void readRGB() {
  while (receivedChars[sensor_location] != '%') {
    sensor_location++;
  }
  sensor_location += 3 * init_index + 1;

  for (int i = 0; i < 3; i++) {
    if ((int)receivedChars[sensor_location + i] * 2 >= 0 && (int)receivedChars[sensor_location + i] * 2 < 255)
      signal_rgb[i] = ((int)receivedChars[sensor_location + i] * 2) % 255;
    //Serial.print((int)receivedChars[sensor_location + i] * 2);
  }
  //rgb_values[sensor_location]='\0';
}


void signalBuild() {
  if (strLength <= 3) {
    buildIndex();
    Serial.print("<");
    Serial.print(receivedChars);
    Serial.print(">");
    Serial.flush();
  }
  else {
    parseSign(); //parse signal string
    //buildIndex(); //build new index
    buildSensor();  //read and build new sensor
    Serial.print("<");
    Serial.print(receivedChars);
    Serial.print(">");    
    Serial.flush();

    readRGB(); //read RGB values

  }
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static int ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        strLength = ndx;
        ndx = 0;
        newData = true;

      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

void showNewData() {
  if (newData == true) {
    Serial.print("<");
    Serial.print(receivedChars);
    Serial.print(">");
    newData = false;
  }
}

darnegar:
This code works seamlessly without freezing if I comment out the strip.show(), which means it's the source of this problem.

certainly.

you need a timing sequence to allow a period of no serial activity during updates to the LEDs.

Have you tired echoing the received chars down the daisy chain one by one (immediately as received instead of rebuilding a new packet and sending it)?

darnegar:
Did I miss anything else?

To make use of the Forum effectively requires more than simply updating your program. I see several things in Replies #13 and #15 that you have not responded to.

What you think about the suggestions is as important as changes to the code because it helps us to know if you understand what we are saying or if we have got things wrong.

And I specifically asked for examples of the data being sent to the Arduino but I don't see any.

...R

BulldogLowell:
Have you tired echoing the received chars down the daisy chain one by one (immediately as received instead of rebuilding a new packet and sending it)?

You mean immediately sending receivedChars as soon as the Arduino meets an end character? But then I will not be able to supply the pi with sensor information (needed for rgb generation).

Robin2:
And I specifically asked for examples of the data being sent to the Arduino but I don't see any.

I sent 2 images with data being sent from the Pi to the Arduino, isn't that what you told me to? I even explained the Pi- Arduino communication for you to understand. If you meant something else please let me know and I will upload accordingly.

Regarding replies #13 and #15, they mention the fact that I used changecolours() in the recv function, which I mentioned in the changes. The data format that is suggested in #15 is already tackled as the string being sent is as small as possible, where even the rgb values are shortened to 3 bytes in order to save length from string at the expense of half the colours, which are not needed. The part where you said about extracting data in multiple places, I cannot understand what you are referring to. The serial communication is done in recv function and SignalBuild() function, for receiving and sending repectively. What do you suggest I do then?

Just as a sidenote, I am very new to electronics and Arduino in general, so I am a bit green on conventions regarding wire communications. I will gladly do any changes and report back, but I am more concerned about the actual problem, that being the LED lights freezing the connection of the arduinos, until the arduinos reset the LED's back to initial state (either via arduino reset or by LED reset), and this can take up to 10 seconds frozen until it happens.

darnegar:
You mean immediately sending receivedChars as soon as the Arduino meets an end character? But then I will not be able to supply the pi with sensor information (needed for rgb generation).

so, there are two arduinos daisy chained over Serial. All the messages are returned to the Pi through the last in the chain?

BulldogLowell:
so, there are two arduinos daisy chained over Serial. All the messages are returned to the Pi through the last in the chain?

Exactly. The pi then reads the string with modified string that contains the sensor values (ascii byte).

darnegar:
Exactly. The pi then reads the string with modified string that contains the sensor values (ascii byte).

OK, so show us exactly what the Pi sends... it looks something like this:

<_%___>

how is that encoded?

And what the Pi expects to receive... A (or one from each node in the chain?) packet that contains what exactly?

what you want to do is easily done, but your code (relying on so many global variables used in so many places) is not easy to understand. It will need to be significantly refactored.

If you want this to work, explain what you are trying to do... with precision.

The string is encoded as following:

Ping:

1 arduino:
From pi: <00>
To pi: <01>
2 arduinos:
From pi: <00>
To pi: <02>

String:

<+ a*[arduinos]+%+ rgb*[arduinos]+>

In simple English: Starting char+ sensor values for each arduinos (initialized at 'a' from pi) + % (placeholder for arduino to start looking for RGB values) + rgb values (3 for each arduino, 0-127 each char)+ end char.

1 arduino:

from pi: <a%aaa>
to pi: <g%aaa>
from pi: <a%dkd>
to pi: <s%dkd>

3 arduinos:

from pi: <aaa%aaaaaaaaa>
to pi: <jad%aaaaaaaaa>
from pi: <aaa%idhiskeud>
to pi: <uda%idhiskeud>

I think I get it:

you send from Pi two types of messages:

Ping:

Ping is sent as a zero in between two <>

<0>

each Arduino increments the value and remembers which value it was, that is its identifier.

Pi sees there are (in your case) two arduinos.

yes?

Second message contains a target Arduino and target RGB values:

<1%rgb>

yes?

Nearly there. The second string is not "a target Arduino and target RGB values" but rather "sensor values for each arduino and target RGB values"

for example, 1 arduino: a%aaa
2 arduinos: aa%aaaaaa
the first a's get replaced by each arduino with the sensor value.

The system is mostly functional except for the NeoPixel's strip.show() which sometimes interferes with the signals being received, which results in the system having to wait until the Arduinos restart, which in itself is a bit strange.

Also, I have noticed that when the arduinos hang, the L light begins to flicker like crazy. I do not know if this is related to the problem.

Also, if I unhook the power from the LED strip while it is hanging, it will work again.

darnegar:
Nearly there. The second string is not "a target Arduino and target RGB values" but rather "sensor values for each arduino and target RGB values"

for example, 1 arduino: a%aaa
2 arduinos: aa%aaaaaa
the first a's get replaced by each arduino with the sensor value.

not there yet... perhaps it is your use of the letter a.

Can you describe what exactly is sent from Pi. (using real example) and how arduino handles it and alters it?

darnegar:
The system is mostly functional except for the NeoPixel's strip.show() which sometimes interferes with the signals being received, which results in the system having to wait until the Arduinos restart, which in itself is a bit strange.

yes, because all your Serial com is being disrupted by NeoPixel writes, we got that.

I already did in reply #19. Is this what you want?

darnegar:
I already did in reply #19. Is this what you want?

I think I understand.

The pi sends

<a%aaa>

the first arduino replaces the first a with its sensor value. Each following appends it"

the first arduino updates its LEDs to the values following the % char and/or feeds back to Pi its RGB values?

that part I cannot get, yet

:slight_smile: sorry for being dim.

Exactly, but the arduino always feeds back the RGB values for the other connected arduinos to read theirs.

For example,

3 arduinos: <aaa%[hdg][oej][fye]>
123 1 2 3

I put the square brackets as a visual aid and are not included in the communication itself. Somehow the numbering below is getting skewed because of different font between edit post.

darnegar:
Exactly, but the arduino always feeds back the RGB values for the other connected arduinos to read theirs.

For example,

3 arduinos: <aaa%[hdg][oej][fye]>
123 1 2 3

I put the square brackets as a visual aid and are not included in the communication itself.

understood now...

the subsequent arduino will be instructed to light up as the previous, I guess.

Now let me look at the code and see if I can help you do this and update the LEDs.

Finally, how fast a refresh rate are you looking to achieve... I'm guessing as fast as possible...

Right now, we are updating every 50ms, and it seems to dim at an ideal speed. I think as it is would be fine.

darnegar:
Exactly, but the arduino always feeds back the RGB values for the other connected arduinos to read theirs.

I hope you are beginning to understand why I asked the question in Reply #15

Please post some examples of the data that is being sent to the Arduino - they may help to make things clearer.

And I can't say that I understand it yet.

Do you mean that if there are two Arduinos the message to the PI is
<12%aaabbb> where nnn is the value from ArduinoA and bbb is the value from ArduinoB
and if there are 3 Arduinos the message will be<123%aaabbbccc>

Is there an upper limit to the number of Arduinos?

if so it would seem simpler to send a fixed length message even if many of the slots have a value of 0. Something like

<aaa,bbb,000,ddd,000,000,000,000,000>

Then the RPI and all the Arduinos can figure out which is which by the position in the message.

...R

I have found the solution by myself. The LED dimming is done before the arduino sends back to the pi, allowing the LED to lock up the arduino without ruining serial connection.

Here is the updated code.

#include <LiquidCrystal.h>
#include <stdio.h>
#include <stdlib.h>
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include <VL53L0X.h>
VL53L0X sensor;
#include <elapsedMillis.h>
elapsedMillis timeElapsed; //declare global if you don't want it reset every time loop runs
#define PIN 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(18, PIN, NEO_GRB + NEO_KHZ800);
#define LONG_RANGE
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
char tmp[2] = "";
const int numChars = 500;
char receivedChars[numChars];
int init_index = 0;
int permanent_rgb[3] = {0,0,0};
int signal_rgb[3] = {0, 0, 0};
int sensor_location = 0;
bool chk = false;
boolean newData = false;
int strLength = 0;
int counter = 0;
bool mutex = true;
void setup() {
  timeElapsed = 0;
  strip.begin();

  //strip.show() causes I/O problems with serial -> interrupts
  strip.show(); // Initialize all pixels to 'off'
  Serial.begin(115200);
  Wire.begin();
  sensor.init();

  sensor.setTimeout(500);
  sensor.setMeasurementTimingBudget(33000);
  sensor.setSignalRateLimit(0.1 * 65536);
  sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
  sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);

  sensor.startContinuous();
}

void changeatonce(){
  int count = 0;
  int diff_rgb = 0;
  for (int i = 0; i < 3; i++) {

    diff_rgb = signal_rgb[i] - permanent_rgb[i];
    if (diff_rgb !=0 ) {
       permanent_rgb[i]=signal_rgb[i];
    }
    else count++;
    }
  
  if (count >= 3)return;
  else{
  for (int j = 0; j < 18; j++) {
    strip.setPixelColor(j, permanent_rgb[0], permanent_rgb[1], permanent_rgb[2]);

  }
  if(!Serial.available())   strip.show();  //this is breaking my signal sent back

  }

}


void changecolours() {

  byte count = 0;
  int diff_rgb = 0;
  for (int i = 0; i < 3; i++) {

    diff_rgb = signal_rgb[i] - permanent_rgb[i];
    if (diff_rgb >= 150) {
      if (permanent_rgb[i] < 254){
      permanent_rgb[i] += 8;
      }
      else count++;
    }
    else if(diff_rgb >= 75) {
      if(permanent_rgb[i] < 254){
        permanent_rgb[i] += 4;
      }
      else count++;
    }
    else if(diff_rgb > 0) {
      if(permanent_rgb[i] < 254) {
        permanent_rgb[i] += 2;
      }
      else count++;
    }
    else if (diff_rgb <= -150) {
      if (permanent_rgb[i]>=0){
      permanent_rgb[i] -= 8;
      }
      else count++;
    }
    else if(diff_rgb <= -75) {
      if(permanent_rgb[i] >= 0){
        permanent_rgb[i] -= 8;
      }
      else count++;
    }
    else if(diff_rgb < 0) {
      if(permanent_rgb[i] >= 0){
        permanent_rgb[i] -= 4;
      }
      else count++;
    }
    else count++;
  }
  if (count >= 3)return;
  else{
  for (int j = 0; j < 18; j++) {
    strip.setPixelColor(j, permanent_rgb[0], permanent_rgb[1], permanent_rgb[2]);

  }
   lcd.clear();
    
    lcd.print(permanent_rgb[0]);
        lcd.print(":");
    lcd.print(permanent_rgb[1]);
    lcd.print(":");
    lcd.print(permanent_rgb[2]);
   strip.show();  //this is breaking my signal sent back

  }
}
void loop() {
  recvWithStartEndMarkers(); //parse signal

  if (newData == true) {
    signalBuild();  //send new signal
    changecolours();
    sendSignal();
    newData = false;
  }

 /*

  if (timeElapsed > 5) {
    //this is breaking my signal sent back
    //changecolours();
    timeElapsed = 0;

  }
*/
  





}

void parseSign() {  //parse the sign into a string

  //bool chk = false;

  sensor_location = init_index;

}


void buildIndex() { //building of index into new sign

  char tmp[3];

  tmp[0] = receivedChars[0];
  tmp[1] = receivedChars[1];

  init_index = atoi(tmp);

  itoa(init_index + 1, tmp, 10);

  if ((init_index + 1) < 10) {
    receivedChars[0] = '0';
    receivedChars[1] = tmp[0];
  } else {
    receivedChars[0] = tmp[0];
    receivedChars[1] = tmp[1];
  }
  //Serial.print(sign);
}


void buildSensor() { //building of sensor values into new sign
  char sens;
  int newValue;
  int range = sensor.readRangeContinuousMillimeters();

  //newValue = range;
  newValue = range / 26 + 97;
  //bring newValue to ASCII/Alphabet character
  sens = newValue;
  receivedChars[sensor_location] = sens;
}

void readRGB() {
  while (receivedChars[sensor_location] != '%') {
    sensor_location++;
  }
  sensor_location += 3 * init_index + 1;

  for (int i = 0; i < 3; i++) {
    if ((int)receivedChars[sensor_location + i] * 2 >= 0 && (int)receivedChars[sensor_location + i] * 2 < 255)
      signal_rgb[i] = ((int)receivedChars[sensor_location + i] * 2) % 255;
    //Serial.print((int)receivedChars[sensor_location + i] * 2);
  }
  //rgb_values[sensor_location]='\0';
     

}

void sendSignal(){

    Serial.print("<");
    Serial.print(receivedChars);
    Serial.print(">");    
    Serial.flush();
}

void signalBuild() {
  if (strLength <= 3) {
    buildIndex();
  }
  else {
    parseSign(); //parse signal string
    buildSensor();  //read and build new sensor
    readRGB(); //read RGB values

  }
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static int ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        strLength = ndx;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

Thank you all for your time. You may all rest now.