Im building myself an 'Ambilight'-type system based on a Processing host app running on

Im building myself an ‘Ambilight’-type system based on a Processing host app running on my Mac Mini HTPC and a string of ‘Christmas Light’ WS2811-enabled LEDs. I managed to get the serial comms working between Processing on the Mac and the Nano, but my LED results were less than stellar.

The original code it was based on used Neopixel library, but I found it was really slow, giving me less than 30 frames a second and lagging a bit on playback, so I wanted to try converting it to FastLED, but… as usual, my programming skillz aren’t up to the task. I’ve got it mostly done, but there’s a line of code that I can’t work out the FastLED equivalent to and I wondered if some of our resident experts could give me a nudge in the right direction.

the command is strip.setPixelColor.

Here is the original, I can’t work out what it is doing with so many led_colour[led_index] components.

// update LEDs
for(int i=0; i<NUM_LED; i++){
int led_index = i*3 + 2;
strip.setPixelColor(i, strip.Color(led_color[led_index], led_color[led_index+1], led_color[led_index+2]));

Any help gratefully received.

This may not be the direction you want, but I recently got Adalight working with OctoWS2811. It’s now an example with version 1.2. So far, no real benchmarking has been done, but it should be very fast. Code is here.

No, that’s great, @PaulStoffregen Thanks very much.

EDIT: oh, no - don’t get Teensy’s over here. Way too expensive to import.

I would imagine the serial data is being read into an 8bit array called ‘led_color’. The first 2 array values are probably the number of leds and as such have not been used in the above segment.
So you first led’s color is at index 2 (Red) index 3 (Green) index 4 (Blue), this pattern repeats for as many leds as you have specified in the MAC mini’s config.
I have a OpenElec PC based media PC which uses boblight.
I use a Teensy to do the led control and in the code I read the serial data straight into the FastLED led array with this command:-
Serial.readBytes((char *)&leds[0].r, NumLeds * 3);
Of course before this line I read and check for the correct preamble sequence.
I too had speed issues to start with until I realised I could set the baud rate upto 460800 as it was going over the usb cable anyway. I have 128 leds around my tv.

On Teensy, USB Serial is always 12 MBit/sec (minus USB protocol overhead). The baud number you use with Serial.begin(baud) is ignored.

The maximum speed without other USB devices active on the same bus is approx 1.1 to 1.2 MByte/sec. The remaining 0.4 to 0.3 MByte/sec is USB protocol overhead.

However, USB protocol provides true end-to-end flow control, similar to Serial when used with RTS+CTS signals. You can easily end up with less than the maximum speed if either side runs slowly. On the Teensy side, Serial.readBytes() is fastest. On the PC side, sending in larger blocks helps, especially on Windows.

Here are some benchmarks I did a couple years ago. All the benchmark code is provided, in case you wish to run the test on your computer and Arduino compatible hardware.

http://www.pjrc.com/teensy/benchmark_usb_serial_receive.html

I think that in our world, instead of this:
strip.setPixelColor(i, strip.Color(led_color[led_index], led_color[led_index+1], led_color[led_index+2]));
you’d write this:
leds[i] = CRGB( led_color[led_index+0], led_color[led_index+1], led_color[led_index+2]);

Or if you’re feeling like a ‘real C programmer’:

CRGB* input_rgbs = (CRGB*)(leds_color + 2);
for( int i=0; i<NUM_LED; i++){
leds[i] = input_rgbs[i];
}

Or now that I think about it, I bet that it’d be even faster to just:

memcpy8( leds, leds_color + 2, NUM_LEDS * 3); // bam.

I think. Totally untested, of course, but it looks right to me. And probably much than the original code. What’s going on here is that we’re taking advantage of the fact that FastLED makes the internals of the “CRGB” pixel structure public, and in particular: publicly writable as raw memory. So the input is two bytes plus a stream of R G B, and you want to copy it into the led buffer of R G B’s, and you can do it with in one fell swoop.

Now that I think about it even more (I should stop this), there may not even be a need to copy the data AT ALL.

Just define “leds” to be inside the led_colors array:
CRGB* leds = (CRGB*)(led_colors + 2);

and now you don’t even have to copy the data. Just read data from USB into led_colors, and call FastLED.show(). Bang.

With WS2812 LEDs, the require waveform timing (30 microseconds per pixel) dominates. Memory to memory copy, even in AVR, is only a tiny fraction of the total time.

Worss yet, if you use a library that generates that timing with a CPU busy loop with interrupts disabled, then you data can’t be flowing in while the slow timing is generated.

My OctoWS2811 library solves these problems by using DMA & a timer to transfer the data automatically, while the CPU is free to receive the next frame or do whatever else needs to happen. The memory copying isn’t the thing you really need from the CPU… it’s responding to USB interrupts (or polling if AVR USB) or serial interrupts, so the data keeps arriving for the next frame during the slow update time. Together with sending 8 channels in parallel (8X faster update), you get pretty incredible speed while using the cheap WS2812 LEDs.

Of course, if you use LPD8806 or WS2801, they can accept data very fast, so timing issues aren’t as much of an issue.

@Mark_Kriegsman thanks so much - that’s perfect!