0

Arduino Mega Serial Port problems with Adafruit_NeoPixel
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Arduino Mega Serial Port problems with Adafruit_NeoPixel

by bishop0114 on Sat May 24, 2014 8:32 am

I am using Adafruit_NeoPixel to control programmable light strands from a Serial port. I need to send a signal to the Serial port to light the first light on a strand and then that light will move down the strand until it reaches the end.

The problem I am having is that when I run the code to move the lights, I start losing data on the Serial port. If I comment out the code for Adafruit, the Serial port works fine.

Here is an example of what I am sending to the Serial Port (USB) from the PC.

L;1;20;0;0

After sending the code a few times, here are the responses.

L;1;20;0;0
L;1;20;0;0
L;1;20;0;0
L;1;20;0;0
L;20;
L;1;20;0;0
L;1;20;0;0

Here is my code.
Code: Select all | TOGGLE FULL SIZE
//  // Serial Input
//  // L;1;20;0;0    (Lane;red;green;blue)
//  // D;100    (Delay time)
//  // C;600  (Total number of lights per lane)

#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel lane1 = Adafruit_NeoPixel(600, 2, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel lane2 = Adafruit_NeoPixel(600, 3, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel lane3 = Adafruit_NeoPixel(600, 4, NEO_GRB + NEO_KHZ800);


int lightcount = 300;  //initialize maximum number of lights.
int lightdelay = 300;  //initialize delay for light movement.

void setup() {
  Serial.begin(9600);
  Serial.println("Serial Light Sequencer 9.2");

  lane1.begin();
  lane1.show();  //Set all lights to off
  lane2.begin();
  lane2.show();  //Set all lights to off
  lane3.begin();
  lane3.show();  //Set all lights to off
}

void loop() {

  for (int i = lightcount; i >= 2 ; i--) {
    lane1.setPixelColor(i, lane1.getPixelColor(i - 1));
    lane1.setPixelColor(i - 1, 0);
    lane2.setPixelColor(i, lane2.getPixelColor(i - 1));
    lane2.setPixelColor(i - 1, 0);
    lane3.setPixelColor(i, lane3.getPixelColor(i - 1));
    lane3.setPixelColor(i - 1, 0);
  }
  lane1.show();
  lane2.show();
  lane3.show();
  delay(lightdelay);
}

void serialEvent() {
  GetSerial();
}

//Read Serial Data
void GetSerial () {
  if (Serial.available()) {
    char *list[6];
    char buf[20] ;
    byte i;
    i = Serial.readBytesUntil('\n', buf, 20);
    buf[i] = '\0';  //terminate string with null
    //Serial.flush();
    Serial.println(buf);
    return;
    char *token = strtok(buf, ";");
    i = 0;
    list[i] = token;
    i++;
    while (token)
    {
      token =  strtok(NULL, ";"); // Use NULL as the 1st argument to keep parsing the same string
      list[i] = token;
      //Serial.println(token);
      i++;
    }
    char tmpproc;
    strncpy (&tmpproc, (list[0]), 1); //Copy Char* to Char * convert to INT for Switch comparison
    switch (tmpproc) {  //Check process
      case 'L':  //Set light
        switch (atoi(list[1])) {
          case 1:
            lane1.setPixelColor(1, byte(atoi(list[2])), byte(atoi(list[3])), byte(atoi(list[4])));  //(light1,r,g,b)
            break;
          case 2:
            lane2.setPixelColor(1, byte(atoi(list[2])), byte(atoi(list[3])), byte(atoi(list[4])));  //(light1,r,g,b)
            break;
          case 3:
            lane3.setPixelColor(1, byte(atoi(list[2])), byte(atoi(list[3])), byte(atoi(list[4])));  //(light1,r,g,b)
            break;
        }
        Serial.println ("LightSet");
        break;

      case 'D':  //Set Delay
        lightdelay = atoi(list[2]);
        Serial.println ("Delay Set");
        break;

      case 'C':  //Set Light Count
        lightcount = atoi(list[2]);
        Serial.println ("LightCountSet");
        break;
    }
    Serial.println(atoi(list[2]));
    Serial.println(atoi(list[3]));
    Serial.println(atoi(list[4]));
  }
}


bishop0114
 
Posts: 5
Joined: Sat May 24, 2014 8:21 am

Re: Arduino Mega Serial Port problems with Adafruit_NeoPixel

by adafruit_support_bill on Sat May 24, 2014 9:55 am

With 3 600 pixel strips, the processor will be spending a lot of time updating the neopixels. Since interrupts are disabled during neopixel updates (necessary to maintain timing tolerances) you are probably losing some serial port interrupts.

adafruit_support_bill
 
Posts: 84355
Joined: Sat Feb 07, 2009 10:11 am

Re: Arduino Mega Serial Port problems with Adafruit_NeoPixel

by bishop0114 on Sun May 25, 2014 11:28 am

Is there a way to resolve it? I am using the Mega, is there another board that would work better?
bishop0114
 
Posts: 5
Joined: Sat May 24, 2014 8:21 am

Re: Arduino Mega Serial Port problems with Adafruit_NeoPixel

by adafruit_support_bill on Sun May 25, 2014 11:35 am

You could implement a 'handshake' between the Mega and the computer that is sending the commands. Have it synchronized so that the Mega requests the next command to be transmitted during the delay, so that there is no interference with the Neopixel updates.

adafruit_support_bill
 
Posts: 84355
Joined: Sat Feb 07, 2009 10:11 am

Re: Arduino Mega Serial Port problems with Adafruit_NeoPixel

by bishop0114 on Sun May 25, 2014 11:51 am

Thanks so much for the help! Do you know if there is an example somewhere on how to do that?
bishop0114
 
Posts: 5
Joined: Sat May 24, 2014 8:21 am

Re: Arduino Mega Serial Port problems with Adafruit_NeoPixel

by adafruit_support_bill on Sun May 25, 2014 11:57 am

There is the SerialCallResponseASCII example in File->Examles->Communication.

That works in reverse of what you are looking for - the Arduino waits for the program on the host computer to send a character, then it responds with data. But code for both sides is there (Processing on the host side), it should not be hard to reverse the roles.

adafruit_support_bill
 
Posts: 84355
Joined: Sat Feb 07, 2009 10:11 am

Re: Arduino Mega Serial Port problems with Adafruit_NeoPixel

by bishop0114 on Wed May 28, 2014 4:34 pm

Is there a way to tell Adafruit_NeoPixel not to turn off the interrupt for the Serial port only? I am still having issues with communication, even when I do handshaking. As soon as I do .show() on the NeoPixel, I start having dropped data.
bishop0114
 
Posts: 5
Joined: Sat May 24, 2014 8:21 am

Re: Arduino Mega Serial Port problems with Adafruit_NeoPixel

by adafruit_support_bill on Wed May 28, 2014 5:16 pm

Post the code you are using (both sides) and we'll take a look.

adafruit_support_bill
 
Posts: 84355
Joined: Sat Feb 07, 2009 10:11 am

Re: Arduino Mega Serial Port problems with Adafruit_NeoPixel

by bishop0114 on Mon Jun 02, 2014 2:06 pm

Here is the code I am working with. I am having 2 problems.

First, the faster I cycle through the loop (reducing the delay), the more likely it is that the communication on the serial port receives garbage.

Second, I need to scroll the light strand at up to 85 feet per minute. The fastest I seem to be able to scroll is about 40 feet per minute. Is there anything I can do to make this code more efficient? The basic concept is that I want to have 3 strands of up to 600 lights. I need to scroll each strand where whatever is on light 1, moves to light 2, etc... until it reaches the end. The Serial inputs a light strand and a color that turns on light 1.

If it helps improve speed, I don't need to scroll past every light, I could scroll every other light (1 moves to 3, to 5, etc.).

Arduino Mega code:
Code: Select all | TOGGLE FULL SIZE
#include <Adafruit_NeoPixel.h>

//  // Serial Input
//  // L;1;20;0;0    (Lane;red;green;blue)
//  // D;100    (Delay time)
//  // C;600  (Total number of lights per lane)

#include <Adafruit_NeoPixel.h>Ard
Adafruit_NeoPixel lane1 = Adafruit_NeoPixel(600, 2, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel lane2 = Adafruit_NeoPixel(600, 3, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel lane3 = Adafruit_NeoPixel(600, 4, NEO_GRB + NEO_KHZ800);


int lightcount = 100;  //initialize maximum number of lights.
int lightdelay = 1000;  //initialize delay for light movement.

void setup() {
  Serial.begin(9600);
  Serial.println("Serial Light Sequencer 9.3");

  lane1.begin();
  lane1.show();  //Set all lights to off
  lane2.begin();
  lane2.show();  //Set all lights to off
  lane3.begin();
  lane3.show();  //Set all lights to off
}

void loop() {
  static unsigned long nextUpdate = millis();
  if (millis() > nextUpdate) {

    for (int i = lightcount; i >= 2 ; i--) {
      lane1.setPixelColor(i, lane1.getPixelColor(i - 1));
      lane1.setPixelColor(i - 1, 0);
      lane2.setPixelColor(i, lane2.getPixelColor(i - 1));
      lane2.setPixelColor(i - 1, 0);
      lane3.setPixelColor(i, lane3.getPixelColor(i - 1));
      lane3.setPixelColor(i - 1, 0);
    }
    lane1.show();
    lane2.show();
    lane3.show();
    Serial.println("A");
    //delay (lightdelay);
    nextUpdate += lightdelay;
  }
  GetSerial();
}

void serialEvent() {
 //GetSerial();
}

//Read Serial Data
void GetSerial () {
  Serial.flush();

  if (Serial.available()) {
    char *list[6];
    char buf[20] ;
    byte i;

    i = Serial.readBytesUntil('\n', buf, 20);
    buf[i] = '\0';  //terminate string with null
    //Serial.flush();
    //    Serial.println(buf);
    //    return;
    char *token = strtok(buf, ";");
    i = 0;
    list[i] = token;
    i++;
    while (token)
    {
      token =  strtok(NULL, ";"); // Use NULL as the 1st argument to keep parsing the same string
      list[i] = token;
      //Serial.println(token);
      i++;
    }
    char tmpproc;
    strncpy (&tmpproc, (list[0]), 1); //Copy Char* to Char * convert to INT for Switch comparison
    switch (tmpproc) {  //Check process
      case 'L':  //Set light
        switch (atoi(list[1])) {
          case 1:
            lane1.setPixelColor(1, byte(atoi(list[2])), byte(atoi(list[3])), byte(atoi(list[4])));  //(light1,r,g,b)
            break;
          case 2:
            lane2.setPixelColor(1, byte(atoi(list[2])), byte(atoi(list[3])), byte(atoi(list[4])));  //(light1,r,g,b)
            break;
          case 3:
            lane3.setPixelColor(1, byte(atoi(list[2])), byte(atoi(list[3])), byte(atoi(list[4])));  //(light1,r,g,b)
            break;
        }
        Serial.print ("L: ");
        Serial.print((list[1]));
        Serial.print("; ");
        Serial.print((list[2]));
        Serial.print (", ");
        Serial.print((list[3]));
        Serial.print (", ");
        Serial.println((list[4]));
        break;

      case 'D':  //Set Delay
        lightdelay = atoi(list[1]);
        Serial.print ("D: ");
        Serial.println((list[1]));
        break;

      case 'C':  //Set Light Count
        lightcount = atoi(list[1]);
        Serial.print ("C: ");
        Serial.println((list[1]));
        break;
    }
  }
}


VB.NET code:
Code: Select all | TOGGLE FULL SIZE
Imports System.IO.Ports
Imports System.Timers

Module Module1
   Dim aTimer As New Timer()
   Dim WithEvents Port As New SerialPort
   Delegate Sub myMethodDelegate(ByVal [text] As String)
   Dim myDelegate As New myMethodDelegate(AddressOf ShowString)
   Sub Main()

      Try
         With Port
            .BaudRate = CInt("9600")
            .PortName = "COM22"
            .Open()
            If .IsOpen Then
               Console.WriteLine("Listening to Port")
               Port.WriteLine("D;50")
               Port.WriteLine("C;300")
            Else
               Console.WriteLine("Unable to open Port")
            End If
         End With

      Catch
         Port.Close()
      End Try

      Console.ReadKey()
      If Port.IsOpen Then
         Port.Close()
      End If
      Console.WriteLine("Port Closed")
   End Sub

   Private Sub SerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles Port.DataReceived
      Dim str As String = Port.ReadExisting()
      Static i As Integer = 1
      Console.Write(str)
      If Mid(str, 1, 1) = "A" And Port.IsOpen Then
         Select i

            Case 1
               Port.WriteLine("L;1;200;0;0") 'Red
               i = i + 1
            Case 2
               Port.WriteLine("L;1;0;5;0") 'Green
               i = i + 1
            Case 3
               Port.WriteLine("L;1;0;0;5") 'Blue
               i = 1

         End Select


      End If
   End Sub

   Sub ShowString(ByVal myString As String)
      Console.WriteLine(myString)
   End Sub

End Module

bishop0114
 
Posts: 5
Joined: Sat May 24, 2014 8:21 am

Re: Arduino Mega Serial Port problems with Adafruit_NeoPixel

by adafruit_support_bill on Mon Jun 02, 2014 2:22 pm

First, the faster I cycle through the loop (reducing the delay), the more likely it is that the communication on the serial port receives garbage.

That makes sense. You are giving the serial communication less time to complete.
Second, I need to scroll the light strand at up to 85 feet per minute. The fastest I seem to be able to scroll is about 40 feet per minute. Is there anything I can do to make this code more efficient?

The update time for the strip depends on the number of pixels in the strip. If you were to break up your strip into several smaller strip sections, you would only have to update the sections that changed. To do that would require:
    * an extra pin per extra section
    * a bit more logic to handle the transition from section to section
    * some buffering of the signal line to the more distant sections

With a Mega, you have plenty of digital pins to work with. The total number of pixels would not change, so the memory requirements would be similar to what you have now. The speed-up should be roughly proportional to the reduction in pixel count for the individual sections.

adafruit_support_bill
 
Posts: 84355
Joined: Sat Feb 07, 2009 10:11 am

Re: Arduino Mega Serial Port problems with Adafruit_NeoPixel

by gregspata on Thu Jun 13, 2019 2:01 pm

Thank you soooo much for this post. I've been tearing my hair out for the past few days trying to figure out what's going on. I've attempted to slow the baud rate down to 1200 and I do see some improvement, but not enough. Ultimately, I'm going to have to revisit my project requirements, but at least I now know the root cause of the issue.

gregspata
 
Posts: 8
Joined: Wed Sep 18, 2013 10:20 pm

Please be positive and constructive with your questions and comments.