#include <Adafruit_NeoPixel.h>
#include <inttypes.h>
-#define LED_PIN 12
#define ROWS 8
#define COLS 32
#define NUM_PIXELS (ROWS * COLS)
#define BIG_IMAGE_FILE_SIZE 780
#define DIMM 4
+/*
+ ATMEGA328P has only 2KiB RAM. The three copies of the color data (const ppm image file,
+ working buffer and NeoPixel library buffer) alone require slightly more than that.
+ When loop() is called, the stack collides with the heap and overrides the library buffer.
+ The resulting visual effect is interesting but in order to actually display the image
+ we must do so directly without allocating a working buffer.
+ Uncomment this to indicate that display_rgb_direct() must be used.
+*/
#define NEOPIXEL_ATE_MY_RAM
+#ifdef NEOPIXEL_ATE_MY_RAM
+#define LED_PIN 12
+#else
+#define LED_PIN PA2
+#endif
+
int render_image(uint8_t buff[ROWS][COLS][3], const uint8_t image[]);
int display_rgb(uint8_t buff[ROWS][COLS][3]);
int display_rgb_direct(const uint8_t image[]);
void loop()
{
+ #ifndef NEOPIXEL_ATE_MY_RAM
uint8_t frame_buffer[ROWS][COLS][3] = {{{0}}};
- #ifdef NEOPIXEL_ATE_MY_RAM
render_image(frame_buffer, big_image_data);
display_rgb(frame_buffer);
#else
display_rgb_direct(big_image_data);
#endif
+
}
int render_image(uint8_t buff[ROWS][COLS][3], const uint8_t image[])
{
+ size_t row_offset, col_offset;
+
if (buff == NULL || image == NULL)
return -1;
for (uint8_t row = 0; row < ROWS; row++)
{
+ row_offset = row * COLS * 3;
for (uint8_t col = 0; col < COLS; col++)
{
+ col_offset = col * 3;
for (uint8_t i = 0; i < 3; i++)
{
- buff[row][col][i] = image[PPM_HEADER_LENGHT + row * COLS * 3 + col * 3 + i];
+ buff[row][col][i] = image[PPM_HEADER_LENGHT + row_offset + col_offset + i];
}
}
}
{
for (uint8_t row = 0; row < ROWS; row++)
{
- led_matrix.setPixelColor(col * ROWS + row, led_matrix.Color(buff[row][col][0] / DIMM,
- buff[row][col][1] / DIMM,
- buff[row][col][2] / DIMM));
+ led_matrix.setPixelColor(col * ROWS + row,
+ led_matrix.Color(buff[row][col][0] / DIMM,
+ buff[row][col][1] / DIMM,
+ buff[row][col][2] / DIMM));
}
}
for (uint8_t col = 1; col < COLS; col += 2)
{
for (uint8_t row = 0; row < ROWS; row++)
{
- led_matrix.setPixelColor((col + 1) * ROWS - row - 1, led_matrix.Color(buff[row][col][0] / DIMM,
- buff[row][col][1] / DIMM,
- buff[row][col][2] / DIMM));
+ led_matrix.setPixelColor((col + 1) * ROWS - row - 1,
+ led_matrix.Color(buff[row][col][0] / DIMM,
+ buff[row][col][1] / DIMM,
+ buff[row][col][2] / DIMM));
}
}
led_matrix.show();
int display_rgb_direct(const uint8_t image[])
{
+ size_t row_offset, col_offset;
+
if (image == NULL)
return -1;
for (uint8_t col = 0; col < COLS; col += 2)
{
+ col_offset = col * 3;
for (uint8_t row = 0; row < ROWS; row++)
{
- led_matrix.setPixelColor(col * ROWS + row, led_matrix.Color(image[PPM_HEADER_LENGHT + row * COLS * 3 + col * 3] / DIMM,
- image[PPM_HEADER_LENGHT + row * COLS * 3 + col * 3 + 1] / DIMM,
- image[PPM_HEADER_LENGHT + row * COLS * 3 + col * 3 + 2] / DIMM));
+ row_offset = row * COLS * 3;
+ led_matrix.setPixelColor(col * ROWS + row,
+ led_matrix.Color(image[PPM_HEADER_LENGHT + row_offset + col_offset] / DIMM,
+ image[PPM_HEADER_LENGHT + row_offset + col_offset + 1] / DIMM,
+ image[PPM_HEADER_LENGHT + row_offset + col_offset + 2] / DIMM));
}
}
for (uint8_t col = 1; col < COLS; col += 2)
{
+ col_offset = col * 3;
for (uint8_t row = 0; row < ROWS; row++)
{
- led_matrix.setPixelColor((col + 1) * ROWS - row - 1, led_matrix.Color(image[PPM_HEADER_LENGHT + row * COLS * 3 + col * 3] / DIMM,
- image[PPM_HEADER_LENGHT + row * COLS * 3 + col * 3 + 1] / DIMM,
- image[PPM_HEADER_LENGHT + row * COLS * 3 + col * 3 + 2] / DIMM));
+ row_offset = row * COLS * 3;
+ led_matrix.setPixelColor((col + 1) * ROWS - row - 1,
+ led_matrix.Color(image[PPM_HEADER_LENGHT + row_offset + col_offset] / DIMM,
+ image[PPM_HEADER_LENGHT + row_offset + col_offset + 1] / DIMM,
+ image[PPM_HEADER_LENGHT + row_offset + col_offset + 2] / DIMM));
}
}
led_matrix.show();