I would use something like this:
#include <FastLED.h>
// POD RGB color struct
struct ColorRGB {
uint8_t r, g, b;
};
// Wrapper to easily read pixels from a PROGMEM bitmap.
struct PGMBitmap {
template <size_t Rows, size_t Cols>
PGMBitmap(const ColorRGB (&colors)[Rows][Cols])
: colors(&colors[0][0]), rows(Rows), cols(Cols) {}
struct PGMBitmapRow {
PGMBitmapRow(const ColorRGB *colors, size_t cols)
: colors(colors), cols(cols) {}
CRGB operator[](size_t col) const {
if (col >= cols) // bounds check
return CRGB::Black;
return CRGB{
pgm_read_byte(&colors[col].r),
pgm_read_byte(&colors[col].g),
pgm_read_byte(&colors[col].b),
};
}
const ColorRGB * const colors;
const size_t cols;
};
PGMBitmapRow operator[](size_t row) {
if (row >= rows) // bounds check
return {nullptr, 0};
return {colors + row * cols, cols};
}
const ColorRGB * const colors;
const size_t rows, cols;
};
// RGB bitmap stored in program memory. [rows][columns]
static const ColorRGB pgm_bitmap[][8] PROGMEM = {
{{255, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 255}, {0, 0, 0}},
{{255, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 255}, {0, 0, 0}},
{{255, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 255}, {0, 0, 0}},
{{255, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 255}, {0, 0, 0}},
{{255, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 255}, {0, 0, 0}},
{{255, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 255}, {0, 0, 0}},
{{255, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 255}, {0, 0, 0}},
{{255, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 255}, {0, 0, 0}},
};
// 2D Array-like object to easily read colors
PGMBitmap bitmap = pgm_bitmap;
constexpr uint8_t LED_PIN = 3;
constexpr auto COLOR_ORDER = GRB;
#define CHIPSET WS2811
constexpr uint8_t NUM_COLS = 32;
constexpr uint8_t NUM_ROWS = 8;
constexpr size_t NUM_LEDS = NUM_COLS * NUM_ROWS;
CRGB leds[NUM_LEDS] = {};
uint16_t XY( uint8_t x, uint8_t y) {
// TODO: Fix this function!
// See https://github.com/FastLED/FastLED/blob/master/examples/XYMatrix/XYMatrix.ino
return x + NUM_COLS * y;
}
void setup() {
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
}
void loop() {
// Load the bitmap in the frame buffer
for (uint8_t row = 0; row < bitmap.rows; ++row) {
for (uint8_t col = 0; col < bitmap.cols; ++col) {
leds[XY(col, row)] = bitmap[row][col];
}
}
FastLED.show();
}
The ColorRGB datatype is used to efficiently save RGB values in a single variable, and can be used for PROGMEM arrays (unlike the FastLED::CRGB type).
The large PGMBitmap class handles reading a 2D array of ColorRGB from PROGMEM, and provides a simple interface so you can write bitmap[row][col]
, like you would with a normal 2D array.
The XY(x, y) function maps a point to the LED index, see the XYMatrix example of FastLED for more info, you’ll have to use their implementation, but I didn’t want to waste space posting it here.
I don’t have the hardware to test it, but if it doesn’t work, it should be very close.