How fast is flash reading compared to SRAM? I'm working on a project that will eventually scale to 864 LEDs on WS2815 LED strips (three rows of 288 LEDs). I'm currently running it on an Arduino Uno with a single test strip of 144 LEDs.

FastLED stores its data in 3-byte structs, so I obviously cannot simply hold all of the data in SRAM and work with it directly (at least not without upgrading to a controller with more memory). I'm going to use a Raspberry Pi to send the Arduino data, one section at a time. To further save memory, I want to implement an RGB color lookup table in flash, then instead of

CRGB pixels[PIXEL_COUNT];


taking up over 2KiB of memory 800+ values, or

CRGB pixels[PIXEL_BUFFER_COUNT];


with a buffer of 288 RGB values consuming most of my working memory (864 bytes), I would have

CRGB *pixels[PIXEL_BUFFER_COUNT];


Where each pointer would reference a location in a PROGMEM 256-entry table of CRGB values. This is a more manageable 576 bytes in SRAM.

I realize FastLED does not work this way. There's a  lot of work ahead of me if I do this, but before I get started, my question:



Will I run into issues with reading the actual data from flash memory while sending to the LED strips? As currently implemented in FastLED, RGB data is in SRAM, but each pointer dereference will require reading from flash. Is the subsequent delay enough that it will cause an issue with sending data to the strips?
On an Arduino Uno, or other AVR-based Arduino, reading a byte from RAM
takes 2 CPU cycles. Reading it from flash takes 3 cycles. So flash vs.
RAM is not such a high overhead. However, if you store a LUT in flash,
and the color indexes in RAM, then each pixel would require:


2 cycles for reading the color index from RAM
3 × 3 cycles for reading the RGB values from flash.


That's a total of 11 cycles, vs. 6 cycles it would take to read the RGB
values from RAM, as is done in the stock FastLED library.

It sounds bad, but it could be that the precise timing is not such a big
issue. I don't know the WS2815, but if they are similar to the WS2812,
then you don't need to be anywhere as precise with the timings as the
datasheet suggests. C.f. the blog post NeoPixels Revealed: How to (not
need to) generate precisely timed signals.

Edit: there will be a few more cycles needed for the pointer
arithmetic. I estimate something around 7 cycles. At low level, the code
for getting a color should look roughly like this:

uint8_t *pixel = ...;
uint8_t index = *pixel;            // read from RAM: 2 cycles
uint8_t pgm_p;                     // pointer to flash
pgm_p = &amp;pgm_lut + 3 * index;      // pointer arithmetic: ≥ 7 cycles
struct CRGB color;
color.r = pgm_read_byte(pgm_p++);  // read from flash: 3 cycles
color.g = pgm_read_byte(pgm_p++);  // read from flash: 3 cycles
color.b = pgm_read_byte(pgm_p);    // read from flash: 3 cycles