Go Down

Topic: Speeding up sending Neopixel color data over serial  (Read 112 times) previous topic - next topic

PixelDeath

The end goal of my project is to use python to send serial information to a Arduino uno that runs a strip of neopixels spanning my room. The plan is to make some music visualizers/redshifts night light/wake up alarm lights/that cool lights behind your monitor that show the average screen color.

to meet this flexibility was hoping I could do all of the pixel color processing on my computer and have the arduino act as a dumb input to display. but if I can't speed things up I'll switch to just sending animation info and writing all producing all of the animations on the arduino.

So, my current issues is I'm not getting as high a refresh as id like so I wanted to know if there were any things I could do to speed things up

my arduino code 
Code: [Select]
#include <Adafruit_NeoPixel.h>

 
const byte PIN = 7;
const int PIX_NUM = 150;
uint32_t color;
int idx = 0;
int red;
int green;
int blue;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIX_NUM, PIN, NEO_GRB + NEO_KHZ800);
 
void setup() {
  strip.begin();
  strip.show();
  Serial.begin(500000);
  Serial.print("#");
}
 
void loop() {
  nextPixel();
}
 
void nextPixel() {
  if(Serial.available() >= 63)  {//wait for buffer to have 21 pixels or 63 bytes
    for(int i=0; i < 21 ; i++)  {
      red = Serial.read();
      green = Serial.read();
      blue = Serial.read();
      color = strip.Color(red,green,blue); //converts  rgb to a single uint32_t
      showNewData();
  }
    Serial.print("#"); //tells program buffer is empty again
  } }
 
void showNewData() {
  strip.setPixelColor(idx,color);
  idx++; //keeps track of pixel index
    if(idx == 150){
      strip.show(); //only updates strip when full new img is there because this function is slow
      idx = 0;
  } }


my python code that displays a simple animation for testing:
Code: [Select]
import serial,random,time,struct
ser = serial.Serial('COM3', 500000)

#wait until a '#' is sent
def ArdWait():
    while True:
        x = ser.read()
        if x == b'#':
            break
        
#wait for ard to be ready
ArdWait()

#setting some variables up
idx = 0
t = time.time()
flip = False
count = 1
bpsCounter = 0
bpsUpdateSec = 2 # how many sec to wait to display bps, python is slow af at printing

brightness = 0
pixelIndex = 0

#main loop
while True:
    
    #sends brightness three times then sends 0 three times to turn on every other pixel
    #having every other pixel off helps me to tell if there is any desyncing caused by high BUAD
    if flip == False:
        value = struct.pack('>B', brightness)
    if flip == True:
        value = struct.pack('>B', 0)
    if count == 3:
        flip = not flip
        count = 0
        pixelIndex = pixelIndex + 1
    
        
    ser.write(value)
    count = count + 1

    

    if pixelIndex == 149:
        pixelIndex = 0
        if brightness < 255:
            brightness = brightness + 1
        else:
            brightness = 0
    
    #wait for buffer to empty before repopulating, this also fixes any desync caused by high BAUD rates
    #63 is used instead of 64(size of arduino buffer) because it is divisable by 3, 3 bytes per pixel
    if idx == 63:
        ArdWait()
        idx= 0
    idx = idx+1
    
    #for displaying 'bps'
    bpsCounter+=1
    if (time.time() - t) > bpsUpdateSec :
        print("bytes sent per sec: ", bpsCounter / (time.time() - t))
        bpsCounter = 0
        t = time.time()



python output:

Code: [Select]
bytes sent per sec:  7169.44018428738
bytes sent per sec:  7465.607360341261
bytes sent per sec:  7147.383546265492
bytes sent per sec:  7415.0659037044825
bytes sent per sec:  7618.0125068798325
bytes sent per sec:  7385.654689745196
bytes sent per sec:  8677.095821100802
bytes sent per sec:  7380.6209164907705
bytes sent per sec:  8299.705158217294
bytes sent per sec:  7174.294169611728
bytes sent per sec:  7438.116854144725
bytes sent per sec:  9978.895260607414
bytes sent per sec:  9183.865011077163


So 150 pixels * 3 bytes per pixel = 450 bytes per refresh.
advantage bytes per sec is about 7700, so 7700 / 450 = about 17 refreshes per sec. Id like this to be 30+.
Is there anything I can do or is this just too much info for serial?

PaulRB

Try using an Arduino Pro Micro. The chip on this type of Arduino connects directly to the USB, not via a separate USB to serial chip. This means it can connect at, in theory, the maximum speed of USB. That is only USB 1.1, not USB 2.0 or 3.0, but even so, that's 12MB/s, so faster than any standard serial speed.

PixelDeath

Thank you for the answer, do you know if it would be feasible to get a usb to gpio for my computer and have multiple pins all sent to the arduino at once. I don't know what the BAUD is on those pins, and they wouldn't have a buffer. But I could wire 9 pins(8 for byte and 1 for clock) and be able to send a byte per cycle

Paul__B

PaulRB's recommendation is much more correct/ accurate/ sensible.

Even so, it will take some serious coding to achieve any significant speed.

PaulRB

8-bit parallel interfaces can be fast over very short distances between chips on the same PCB. But for longer connections, serial interfaces are faster because parallel interfaces get synchronisation problems. When you have to synchronise 8 signals with a clock signal over longer distances, you have to really slow down the clock, so serial ends up being faster.

12Mb/s should be much faster than you need. If you still have problems then, perhaps there is some problem with your code, so post that.

Go Up