Go Down

Topic: Arduino Due 2100 LEDs working but slow (Read 492 times) previous topic - next topic

Aug 05, 2019, 02:53 pm Last Edit: Aug 05, 2019, 02:56 pm by eeyore124
I've build a matrix 14x150  total of 2100 LEDs, it's 8ft 2in for each LED strip..  I am using FASTLED and NeoPixel library.  Everything is working.  The problem is the text displays slowly.  I have the text coming in from the right side and scrolling across.  The speed was fine on 14x20 proto type board, but when scaled to
full size, the speed is way too slow.  I am providing 5v power at each strip of 150 LEDs, I have two 5v 60a power supplies, this is all working fine.  Total power white 416W at full birghtness, I also have 120v fans to keep everything cool, it will be located out side.

 I've read that Due should only control 1000 LED for each controller.  Is there a controller that I can buy to manage sending the data line out and sync it to different parts of the matrix ?

I have this mounted in a public location, County Fair, with the letters being so slow it will not work the way I intended.


The theoretical frame speed is 0.063sec or 16 frames each second for a single string of 2100 leds. To reach that the processor must use 100% of cpu time to update the leds.


Grumpy_Mike

#2
Aug 05, 2019, 03:36 pm Last Edit: Aug 05, 2019, 03:40 pm by Grumpy_Mike
Many beginners make the mistake of calling the show method after each led has been changed. This significantly slows things down when you have a lot of LEDs .

Given you have not posted any code we don't know if you are falling for that mistake.
Quote
Is there a controller that I can buy to manage sending the data line out and sync it to different parts of the matrix ?
It is not a function of the controller but a function of the led strips. There are no addressable strips where you can just change one value. You have to send all the LEDs all the data every time.

Grumpy_mike you nailed it, I'm using the strip.show().  I'm attaching the code.

Grumpy_Mike

Sorry can't read a .ino file on an iPad, but only use the show method once all the LEDs have been changed for each full frame of the scrolling.

Here's the code.  Note I removed most of the letter fonts to fit into the size limit.  I have a switch statement that check for what letter is being processed.  then call this function.  strip.show(); is called at the end of the switch.

Code: [Select]
int getIndex(int r, int c) {
  if (r >= ROWS || c >= COLS || r < 0 || c < 0) {return -1;}
  //c = COLS-c-1;
  //r = ROWS-r-1;
  return (2*COLS)-2+r+(2*(COLS-1)*floor((r-1)/2.0))+(c*(1-2*(r%2)));
 
}
void letter(const boolean arr[HEIGHT][WIDTH], int org) {
  int eeyore = 0;
  if (-org > WIDTH*2) return;
  if (org > COLS) return;
 
  for (int x=0; x<HEIGHT; x++) {
    for (int y=0; y<WIDTH; y++) {
      //Serial.print("result getIndex = ");
     
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x, 2*y+org), (255, 255, 255));
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x+1, 2*y+org), (255, 255, 255));
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x+1, 2*y+1+org), (255, 255, 255));
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x, 2*y+1+org), (255, 255, 255));
   
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x, 2*y+org), pgm_read_dword((arr[x][y]?color:strip.Color(0, 0, 0))));
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x+1, 2*y+org), pgm_read_dword((arr[x][y]?color:strip.Color(0, 0, 0))));
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x+1, 2*y+1+org), pgm_read_dword((arr[x][y]?color:strip.Color(0, 0, 0))));
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x, 2*y+1+org), pgm_read_dword((arr[x][y]?color:strip.Color(0, 0, 0))));
      strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x, 2*y+org), (arr[x][y]?color:strip.Color(0, 0, 0)));
      strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x+1, 2*y+org), (arr[x][y]?color:strip.Color(0, 0, 0)));
      strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x+1, 2*y+1+org), (arr[x][y]?color:strip.Color(0, 0, 0)));
      strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x, 2*y+1+org), (arr[x][y]?color:strip.Color(0, 0, 0)));
    }
  }
}

strip.show();
  delay(SPEED);
  clear();
  index1++;
  if (index1 == maximum) {index1=0; phrase=(phrase+1==phrases?0:phrase+1);}


This is the code that calls "strip,show()"  it only gets called once after all the letters are processed.
Trying to find way to speed up the text scrolling.  It looks very very slow on a 8ft display.


Code: [Select]
for (int x=0; x<len[phrase]; x++) {
    //Serial.print(x); Serial.print(" "); Serial.println(x*WIDTH*2+x*2);
    switch (string[phrase][x]) {
      case 'a':
        letter(A, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'b':
        letter(B, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'c':
        letter(C, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'd':
        letter(D, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'e':
        letter(E, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'f':
        letter(F, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'g':
        letter(G, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'h':
        letter(H, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'i':
        letter(I, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'j':
        letter(J, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'k':
        letter(K, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'l':
        letter(L, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'm':
        letter(M, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'n':
        letter(N, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'o':
        letter(O, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'p':
        letter(P, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'q':
        letter(Q, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'r':
        letter(R, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 's':
        letter(S, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 't':
        letter(T, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'u':
        letter(U, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'v':
        letter(V, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'w':
        letter(W, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'x':
        letter(X, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'y':
        letter(Y, x*WIDTH*2+x*2-index1+COLS);
        break;
      case 'z':
        letter(Z, x*WIDTH*2+x*2-index1+COLS);
        break;
      case ' ':
        letter(space, x*WIDTH*2+x*2-index1+COLS);
        break;
      case '0':
        letter(zero, x*WIDTH*2+x*2-index1+COLS);
        break;
      case '1':
        letter(one, x*WIDTH*2+x*2-index1+COLS);
        break;
      case '2':
        letter(two, x*WIDTH*2+x*2-index1+COLS);
        break;
      case '3':
        letter(three, x*WIDTH*2+x*2-index1+COLS);
        break;
      case '4':
        letter(four, x*WIDTH*2+x*2-index1+COLS);
        break;
      case '5':
        letter(five, x*WIDTH*2+x*2-index1+COLS);
        break;
      case '6':
        letter(six, x*WIDTH*2+x*2-index1+COLS);
        break;
      case '7':
        letter(seven, x*WIDTH*2+x*2-index1+COLS);
        break;
      case '8':
        letter(eight, x*WIDTH*2+x*2-index1+COLS);
        break;
      case '9':
        letter(nine, x*WIDTH*2+x*2-index1+COLS);
        break; 
    }
  }
  strip.show();
  delay(SPEED);
  clear();

Grumpy_Mike

#7
Aug 05, 2019, 07:04 pm Last Edit: Aug 05, 2019, 07:07 pm by Grumpy_Mike
Code: [Select]
strip.show();
  delay(SPEED);
  clear();

Remove the delay and the clear. Removing the clear will double the speed in itself.


Quote
Here's the code.
Well no its only a bit of the code. No need to see all the font definitions but need to see the rest. It is possible you could speed up something else.

I have the delay set to zero.  Was wondering about removing the "clear()" was going to test what happened if I commented it out.

Code: [Select]
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
//#include <WireUpdate.h>
//#include <OneWire.h>
//#include <DallasTemperature.h>
//#include <RTClib.h>

#include <math.h>

#define PIN 5
#define TEMPSENSOR 4
#define NOSETCLOCK
#define BUZZER 12

#define ROWS 14
#define COLS 150
#define WIDTH 5
#define HEIGHT 7
#define SPEED 0

int index1 = 0;

const int LENGTH = COLS*ROWS;


//CONVERT MATRIX TO INDEX
//prog[r_,c_,cc_]:=2cc-2+r+2(cc-1)Floor[(r-1)/2]+c*(1-2Mod[r,2])


//RTC_DS3231 rtc;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(LENGTH, PIN, NEO_RGB+NEO_KHZ800);

//OneWire oneWire(TEMPSENSOR);
//DallasTemperature sensors(&oneWire);


// BEGIN QLOCK SETTINGS ###############################



const uint32_t color = strip.Color(0, 0, 255);
const uint32_t white = strip.Color(255, 255, 255);
//   jump in code
#define MAXLEN 18
#define MAXPHRASES 5
int phrases = 1;
int phrase;
//char string[MAXPHRASES][MAXLEN] = {"rabbits for sale"};
char string[MAXPHRASES][MAXLEN] = {"abba abba baab"};
byte len[MAXPHRASES] = {16};

// END QLOCK SETTINGS #################################


long lastMinSet=millis();
boolean colorStatus=false;

const int adc_address=41;   // I2C Address
char keyboard_data[80];   // Array to store keyboard values   


int getIndex(int r, int c) {
  if (r >= ROWS || c >= COLS || r < 0 || c < 0) {return -1;}
  //c = COLS-c-1;
  //r = ROWS-r-1;
  return (2*COLS)-2+r+(2*(COLS-1)*floor((r-1)/2.0))+(c*(1-2*(r%2)));
 
}



keep running into size limit.  below is the code that is called by the switch in main loop

Code: [Select]
void letter(const boolean arr[HEIGHT][WIDTH], int org) {
  int eeyore = 0;
  if (-org > WIDTH*2) return;
  if (org > COLS) return;
 
  for (int x=0; x<HEIGHT; x++) {
    for (int y=0; y<WIDTH; y++) {
      //Serial.print("result getIndex = ");
     
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x, 2*y+org), (255, 255, 255));
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x+1, 2*y+org), (255, 255, 255));
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x+1, 2*y+1+org), (255, 255, 255));
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x, 2*y+1+org), (255, 255, 255));
   
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x, 2*y+org), pgm_read_dword((arr[x][y]?color:strip.Color(0, 0, 0))));
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x+1, 2*y+org), pgm_read_dword((arr[x][y]?color:strip.Color(0, 0, 0))));
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x+1, 2*y+1+org), pgm_read_dword((arr[x][y]?color:strip.Color(0, 0, 0))));
      //strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x, 2*y+1+org), pgm_read_dword((arr[x][y]?color:strip.Color(0, 0, 0))));
      strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x, 2*y+org), (arr[x][y]?color:strip.Color(0, 0, 0)));
      strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x+1, 2*y+org), (arr[x][y]?color:strip.Color(0, 0, 0)));
      strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x+1, 2*y+1+org), (arr[x][y]?color:strip.Color(0, 0, 0)));
      strip.setPixelColor(getIndex(ROWS-2*HEIGHT+2*x, 2*y+1+org), (arr[x][y]?color:strip.Color(0, 0, 0)));
    }
  }
}

Grumpy_Mike

Quote
Was wondering about removing the "clear()"
What this function does is to set all the LEDs in the buffer array to zero and then write them all out to the LEDs.

If you code for setting up the next screen to display only sets the LEDs it needs to set and doesn't clear the bits that need to be off, they you will have to write a routine to put all the LEDs in the buffer to zero but not write them out.

However you keep insisting on showing only part of the code. I have no idea how you are writing letter nor how your matrix is wired up.

I post the ino file.  Here is all the code, minus the letter arrays, I will have to post it in parts to get under the size limits.  I have the LED matrix configured in Z pattern.   I have a blog on the build on Hackaday.io  https://hackaday.io/project/164444-very-large-led-display    I'm doing this with 4H youth group I'm leader for.  You can see all the technical details, including pictures.

I attached the entire program file as a txt file. 


david_2018

What this function does is to set all the LEDs in the buffer array to zero and then write them all out to the LEDs.

Are you sure about that? The code from Adafruit.NeoPixel.cpp is as follows:

Code: [Select]

/*!
  @brief   Fill the whole NeoPixel strip with 0 / black / off.
*/
void Adafruit_NeoPixel::clear(void) {
  memset(pixels, 0, numBytes);
}


The actual clear() in the OP's code is a function in the sketch using a loop to set each pixel individually, but a bit of testing shows that strip.clear() is almost seven times faster.

david_2018

Since you are using an Arudino Duo and should have plenty of SRAM, it would probably be faster to create an array to hold an image of the text that will be displayed on the LEDs, then copy that over to the actual pixel array with an appropriate offset to generate the scrolling.  That way you only have to generate the image once, and the rest can be done with memcpy.

Grumpy_Mike

#13
Aug 06, 2019, 07:09 am Last Edit: Aug 06, 2019, 07:29 am by Grumpy_Mike
Quote
Are you sure about that? The code from Adafruit.NeoPixel.cpp is as follows
Sorry you are quite right, I was thinking about the fastLED library.

Wow that code is massive and it is full of commented out stuff which makes it even more confusing to read.. I have never seen a loop function that big.

You should break it up into functions so you can see more easily what is going on. It seems like you are engaging in an I2C exchange every time round the loop function, that is going to massively slow things down.

And I agree with David about the shifting, you should only need to write to the left hand column of the display after shifting what you already have to the left by one column.

Thanks for the suggestions.  I have the LED matrix installed at the 4H Fair now. I'm going to go over there this evening (Fair starts this coming weekend), and test out your suggestions.  I had one of the kids in the club write the letter code, I put the print commands in so I could check/debug.   I hope commenting out the I2C section will be a nice boost in speed.  I am not using the USB Keyboard now, it worked on the Mega, having problems getting it working on the Due.  Going to table that for now, and work on it after the Fair is over.  The idea was you could enter new phrases via keyboard.  I'm also going to test increasing the "step" now its moving one column at a time, will try moving two than three.  See how much faster that is and how it looks. 

Go Up