I'm using memcpy_P to copy a row from a PROGMEM 2d array of structs into a buffer. The number of columns is specified by COLS_PER_FRAME.
memcpy_P(buf, FRAMES[i], COLS_PER_FRAME) works as expected.
If I instead specify the source array as (FRAMES + (buffer_offset++)) that works the same, and the code compiles into less space. This is surprising to me because I expected that it should be FRAMES + (buffer_offset++ * COLS_PER_FRAME).
Shouldn't it end up getting the array offset by 1 byte, not one whole row? Any why is the compiled code smaller?
#include <avr/pgmspace.h>
typedef struct {
const uint8_t anode : 3;
const uint8_t cathode : 3;
} Led;
const uint8_t NUM_FRAMES = 11;
const uint8_t COLS_PER_FRAME = 6;
const Led FRAMES[NUM_FRAMES][COLS_PER_FRAME] PROGMEM = {
{ {.anode = 0, .cathode = 1}, {.anode = 1, .cathode = 0}, {.anode = 0, .cathode = 0}, {.anode = 0, .cathode = 0}, {.anode = 0, .cathode = 0}, {.anode = 5, .cathode = 6} },
{ {.anode = 0, .cathode = 2}, {.anode = 2, .cathode = 1}, {.anode = 2, .cathode = 0}, {.anode = 0, .cathode = 0}, {.anode = 0, .cathode = 0}, {.anode = 0, .cathode = 0} },
{ {.anode = 0, .cathode = 3}, {.anode = 1, .cathode = 2}, {.anode = 3, .cathode = 1}, {.anode = 3, .cathode = 0}, {.anode = 0, .cathode = 0}, {.anode = 0, .cathode = 0} },
{ {.anode = 1, .cathode = 3}, {.anode = 3, .cathode = 2}, {.anode = 4, .cathode = 1}, {.anode = 0, .cathode = 0}, {.anode = 0, .cathode = 0}, {.anode = 0, .cathode = 0} },
{ {.anode = 0, .cathode = 4}, {.anode = 2, .cathode = 3}, {.anode = 4, .cathode = 2}, {.anode = 5, .cathode = 1}, {.anode = 5, .cathode = 0}, {.anode = 0, .cathode = 0} },
{ {.anode = 1, .cathode = 4}, {.anode = 4, .cathode = 3}, {.anode = 5, .cathode = 2}, {.anode = 6, .cathode = 1}, {.anode = 6, .cathode = 0}, {.anode = 0, .cathode = 0} },
{ {.anode = 0, .cathode = 5}, {.anode = 2, .cathode = 4}, {.anode = 5, .cathode = 3}, {.anode = 6, .cathode = 2}, {.anode = 7, .cathode = 1}, {.anode = 7, .cathode = 0} },
{ {.anode = 1, .cathode = 5}, {.anode = 3, .cathode = 4}, {.anode = 6, .cathode = 3}, {.anode = 7, .cathode = 2}, {.anode = 0, .cathode = 7}, {.anode = 0, .cathode = 0} },
{ {.anode = 0, .cathode = 6}, {.anode = 2, .cathode = 5}, {.anode = 5, .cathode = 4}, {.anode = 7, .cathode = 3}, {.anode = 2, .cathode = 7}, {.anode = 1, .cathode = 7} },
{ {.anode = 1, .cathode = 6}, {.anode = 3, .cathode = 5}, {.anode = 6, .cathode = 4}, {.anode = 3, .cathode = 7}, {.anode = 4, .cathode = 0}, {.anode = 0, .cathode = 0} },
{ {.anode = 3, .cathode = 6}, {.anode = 2, .cathode = 6}, {.anode = 4, .cathode = 5}, {.anode = 7, .cathode = 4}, {.anode = 4, .cathode = 7}, {.anode = 0, .cathode = 0} },
};
void setup() {
Serial.begin(9600);
Serial.println("hello");
}
void loop() {
uint8_t buffer_offset = 0;
static Led buf[COLS_PER_FRAME] = {0};
for (int8_t i = 0; i < NUM_FRAMES; ++i) {
// 2076 bytes compiled with pointer offset (FRAMES + buffer_offset)
memcpy_P(buf, FRAMES + buffer_offset, COLS_PER_FRAME);
buffer_offset += 1;
// 2082 bytes compiled with array index (FRAMES[i])
// memcpy_P(buf, FRAMES[i], COLS_PER_FRAME);
for (uint8_t j = 0; j < COLS_PER_FRAME; ++j) {
Serial.print('a');
Serial.print(buf[j].anode);
Serial.print(" c");
Serial.print(buf[j].cathode);
Serial.print(", ");
}
Serial.println();
}
Serial.println();
delay(1000);
}
Output (correctly reproduces the input):
a0 c1, a1 c0, a0 c0, a0 c0, a0 c0, a5 c6,
a0 c2, a2 c1, a2 c0, a0 c0, a0 c0, a0 c0,
a0 c3, a1 c2, a3 c1, a3 c0, a0 c0, a0 c0,
a1 c3, a3 c2, a4 c1, a0 c0, a0 c0, a0 c0,
a0 c4, a2 c3, a4 c2, a5 c1, a5 c0, a0 c0,
a1 c4, a4 c3, a5 c2, a6 c1, a6 c0, a0 c0,
a0 c5, a2 c4, a5 c3, a6 c2, a7 c1, a7 c0,
a1 c5, a3 c4, a6 c3, a7 c2, a0 c7, a0 c0,
a0 c6, a2 c5, a5 c4, a7 c3, a2 c7, a1 c7,
a1 c6, a3 c5, a6 c4, a3 c7, a4 c0, a0 c0,
a3 c6, a2 c6, a4 c5, a7 c4, a4 c7, a0 c0,
+adds sizeof type