Really weird issue while using a linked list on Arduino Nano/Uno

Hi all,

Sort of a weird issue here as I’m trying to use an Arduino Uno (also tested on a Nano) to create 5 linked lists with ~50 nodes each to produce a theatre chase animation on some neopixels. Right now, the neopixels aren’t even causing any issues.

The code is decently well commented to give an idea of how everything is working but basically I am filling in these 5 linked lists with a predetermined message that’s stored in a 2d array. I have marked one commented out println where the data comes back fine from the linked list but there is a second serial print that causes some super bizarre results (see below). I even tried adding in a serial print to just output the strip name before the data from posting here and it’s almost like the i index was overflowing.

I can provide any further details that might be needed but I’m mostly at a loss here. I commented out the loop as that code isn’t used currently (until this can get fixed!).

Here is the code:

#include "LPD8806.h"

int nLEDs = 18; // number of leds on light strip
int dataPin[5]  = {3, 9, 7, 5, 11}; // First number is the top light strip, last is the bottom
int clockPin[5] = {2, 6, 8, 4, 10}; // same

int msgWidth = 51; // needs to be the same as the below definition as well
byte msg[][51] = {
  // write the letters out on a whiteboard and convert them to binary and then type it out here
  // the padding at the front and back are important for when the message wraps around, otherwise it doesn't scroll and just flicks back to the first frame
  // consider using a singly circular linked list to make the scrolling animation better (ie. start and end of message can be on the belt at the same time)
  // also if the message length is less than the number of pixels, this code WILL NOT work - was really tired and didn't feel like making your life easier

  //              D              A              I              R              Y              F              A              R              M
  {0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0},
  {0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0},
  {0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0},
  {0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0},
  {0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0}
};

// array of five light strips
LPD8806 strips[5] = {
  LPD8806(nLEDs, dataPin[0], clockPin[0]),
  LPD8806(nLEDs, dataPin[1], clockPin[1]),
  LPD8806(nLEDs, dataPin[2], clockPin[2]),
  LPD8806(nLEDs, dataPin[3], clockPin[3]),
  LPD8806(nLEDs, dataPin[4], clockPin[4])
};

// node of a linked list
struct Node {
  byte data;
  struct Node *next;
};

Node *firsts[] = {NULL, NULL, NULL, NULL, NULL};   // ref to "head" of linked list (aka start of message)
Node *currents[] = {NULL, NULL, NULL, NULL, NULL}; // ref to current node


void setup() {
  Serial.begin(115200);
  while(!Serial);
  
  for (int i = 0; i < 5; i++) {
    // create the first nodes and store them for later reference
    firsts[i] = new Node;
    firsts[i]->data = msg[i][0];

    // starting at the first node...
    currents[i] = firsts[i];
    for (int j = 0; j < msgWidth; j++) {
      // for each element in the msg array...
      Node *temp = new Node;            // create a node
      temp->data = msg[i][j];           // set the data
      currents[i]->next = temp;         // link the previous node
      // Serial.print(currents[i]->data);  // *******Have tried printing the data and it works fine here (see below)*******
      currents[i] = currents[i]->next;  // iterate to the next node (the one that was just created)
    }
    currents[i]->next = firsts[i];      // link the last node to the first node (circularly linked)
  }

  // set the current indexes back to our references to the first nodes
  for (int i = 0; i < 5; i++) currents[i] = firsts[i];

  // test printing the data values of the nodes
  for (int i = 0; i < 5; i++) {
//    Serial.print("Strip"); Serial.print(i); Serial.print(": ");
    for (int j = 0; j < msgWidth; j++) {
      Serial.print(currents[i]->data); // *******THIS IS WHERE THE ISSUE IS*******
      currents[i] = currents[i]->next;
    }
    Serial.println();
    }

  for (int s = 0; s < 5; s++) {
    strips[s].begin();
    strips[s].show();
  }
}


void loop() {
//  for (int s = 0; s < 5; s++) {
//    currents[s] = firsts[s];
//
//    for (int i = 0; i < msgWidth; i++) {
//      if (currents[s] -> data == 1) {
//        // one strip was not the same length as the other four so we had to do this hack job, buy better lights dummy
//        if (s == 0) strips[s].setPixelColor(i - 2, strips[s].Color(173, 2, 252));
//        else strips[s].setPixelColor(i, strips[s].Color(173, 2, 252));
//      }
//      else {
//        if (s == 0) strips[s].setPixelColor(i - 2, strips[s].Color(0, 0, 0));
//        else strips[s].setPixelColor(i, strips[s].Color(0, 0, 0));
//      }
//      currents[s] = currents[s] -> next;
//    }
//    strips[s].show();
//  }
//  // seems like a reasonable timing for a theatre chase animation
//  delay(150);
}

Which produces the following on two separately tested boards (Uno and Nano):

000001100011100111001110010100111001110011100101000
000001010010100010001010010100100001010010100111000
000001010011100010001100011100110001110011000101000
000001010010100010001010001000100001010010100101000
163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163163

leds.ino (4.45 KB)

The attached code is small enough to post inline in your post, using code tags. It is the preferred way to post code in this forum.

Good lord. You are not programming on a PC. Why use a linked list to each byte of data? Why declare an array of 8 bits width to store 0 or 1? You are way over complicating things

Hi,

Please read the post at the start of any forum , entitled "How to use this Forum".
OR
http://forum.arduino.cc/index.php/topic,148850.0.html.
Then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Thanks.. Tom... :slight_smile:

blh64:
Good lord. You are not programming on a PC. Why use a linked list to each byte of data? Why declare an array of 8 bits width to store 0 or 1? You are way over complicating things

This is definitely way over-complicating a simple message scroll. Generally you copy the pattern into the LED buffer, then shift the buffer contents to the left or right (depending on scroll direction) to achieve the scroll. If the scroll needs to be circular, you save the pixel data for the LED that gets shifted out first, then write it to the other end of the buffer after the shift. It is also a bit unusual to manually create the pattern from text, much more versatile to define the bit patterns for the ASCII characters in the code then do the conversion when loading the LED buffer, that way you can easily change the text dynamically in the code.

TomGeorge:
Hi,

Please read the post at the start of any forum , entitled "How to use this Forum".
OR
http://forum.arduino.cc/index.php/topic,148850.0.html.
Then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Thanks.. Tom... :slight_smile:

Apologies on that! Should have checked over the rules more throughly. I have updated the original post.

david_2018:
This is definitely way over-complicating a simple message scroll. Generally you copy the pattern into the LED buffer, then shift the buffer contents to the left or right (depending on scroll direction) to achieve the scroll. If the scroll needs to be circular, you save the pixel data for the LED that gets shifted out first, then write it to the other end of the buffer after the shift. It is also a bit unusual to manually create the pattern from text, much more versatile to define the bit patterns for the ASCII characters in the code then do the conversion when loading the LED buffer, that way you can easily change the text dynamically in the code.

Should have mentioned in the original post: I know there are simpler ways to achieve the same effect and I have some code that does exactly what you mention (aside from the ASCII to buffer conversion!). The main reason I started a new version was just to see if I could accomplish it using a linked list. It's more an exercise in programming than a viable solution to the problem.

The program then started producing weird results and it intrigued me to figure out why.

Without the LPD8806 library, the sketch 'works' but you have only 268 bytes of memory left after creating those linked lists. I suspect the library and five strings of LEDs use more than 268 bytes. That would cause you to run out of memory while building the linked lists.

Figured as much but wasn’t sure how to check for totally memory used.

I compiled and had it come out to 3970 bytes (out of 32256) of flash and 548 bytes (out of 2048) of ram. Adding in the linked lists would be 510 (5 arrays * 51 modes * 2 bytes per node) for a total of ~1110 (rounded up for some buffer). Isn’t that only about 50% of memory?

Wouldn't a node be 3 bytes? A pointer is 16 bits on AVR architecture.

When constructing the linked lists the available memory goes down by 260 bytes per row of 51 elements. That comes to a little over 5 bytes per element. I don't know why. Perhaps there is overhead in 'malloc()' which is called by 'new'.