PROGMEM and using array with pgm_read_byte_near

I am designing some code to light up some LED’s with an ATTINY, and because of limited RAM, I am using the FLASH to store the patterns. I am currently testing this on a regular Arduino UNO:

#include <MsTimer2.h>
#include <avr/pgmspace.h>

uint8_t const sineWave[] PROGMEM = { 16,16,17,17,18,18,18,19,19,20,20,20,21,21,21,22,22,22,23,23,24,24,24,25,25,25,26,26,26,26,27,27,27,28,28,28,28,29,29,29,29,30,30,30,30,30,30,31,31,31,31,31,31,31,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,31,31,31,31,31,31,31,30,30,30,30,30,30,29,29,29,29,28,28,28,28,27,27,27,26,26,26,26,25,25,25,24,24,24,23,23,22,22,22,21,21,21,20,20,20,19,19,18,18,18,17,17,16,16,16,15,15,14,14,14,13,13,12,12,12,11,11,11,10,10,10, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9,10,10,10,11,11,11,12,12,12,13,13,14,14,14,15,15,16  };
uint8_t const spinWave[] PROGMEM = { 31,31,31,31,31,31, 0,25,24,23,22,20,11,12,13,14,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 0, 4, 8,16,20,24,28,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 0, 4, 8,16,20,24,28,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 0, 4, 8,16,20,24,28,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 0, 4, 8,16,20,24,28,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 0, 4, 8,16,20,24,28,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 0, 4, 8,16,20,24,28,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 0, 4, 8,16,20,24,28,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32  };
uint8_t const blnkWave[] PROGMEM = { 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 0,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32  };

const uint8_t* const waveTable[] PROGMEM = {sineWave, spinWave, blnkWave};
static int currentWave = 0;


void setup()
{
  Serial.begin(115200);
  MsTimer2::set(2000, nextPattern);
  MsTimer2::start();
}


void loop()
{
  Serial.print(currentWave);
  Serial.print(": ");
  Serial.println(pgm_read_byte_near(waveTable[currentWave]));
  delay(100);
}

#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))

void nextPattern()
{
  // add one to the current pattern number, and wrap around at the end
  currentWave = (currentWave + 1) % ARRAY_SIZE( waveTable);
}

The output is as follows:

0: 33
1: 255
2: 255

I can read the actual expected byte by replacing

Serial.println(pgm_read_byte_near(waveTable[currentWave]));

with

Serial.println(pgm_read_byte_near(waveTable[0]));

or

Serial.println(pgm_read_byte_near(waveTable[1]));

or

Serial.println(pgm_read_byte_near(waveTable[2]));

results with:
0: 16
1: 31
2: 32

Any idea why using the currentWave doesn’t work, and where does it pull the data from?

svdbor:
I can read the actual expected byte by replacing

Serial.println(pgm_read_byte_near(waveTable[currentWave]));

with

Serial.println(pgm_read_byte_near(waveTable[0]));

or

Serial.println(pgm_read_byte_near(waveTable[1]));

or

Serial.println(pgm_read_byte_near(waveTable[2]));

Yes you can because waveTable is defined as an array yet, in your code, you do not reference it as such (no [index]) so the value being used is simply the calculated address of the beginning of the first array and who knows what that is.

Also, as your arrays are all 256 bytes, what’s with the #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))?

You can also eliminate the modulo by just allowing integer math to rollover.

Forget those last comments. Upon a closer look, this is even more screwed up than that.

Okay, you still there? First, you can use pgm_read_byte_near or simply pgm_read_byte.

The pgm_read functions want an address. When you issued your statements that ‘worked’ (i.e. Serial.println(pgm_read_byte_near(waveTable[1])); ), you were passing the base address of waveTable[1], ignoring the fact that waveTable is a two-dimensional array. What you saw as ‘correct’ output was merely index zero of each array. This (unfortunately) will not generate an error or even a warning as it is valid syntax, if that’s what you want. By definition, the name of an array is a pointer to the base address of that array. To cycle through the addresses of the array, you either add the length of the array member (in this case uint8 which is 1) or reference the array member.

In code-speak this is base_address + offset or &base_address@.

In your case, with a two-dimensional array, you want waveTable[currentWave] + offset or &waveTable[currentWave]@.

For test, put this loop in setup(),

for (byte i = 0; i < 255; i ++)
{
    Serial.print(pgm_read_byte(&sineWave[i]));
    Serial.print("\t");
    Serial.print(pgm_read_byte(sineWave + i));
    Serial.print("\t");
    Serial.print(pgm_read_byte(&spinWave[i]));
    Serial.print("\t");
    Serial.print(pgm_read_byte(spinWave + i));
    Serial.print("\t");
    Serial.print(pgm_read_byte(waveTable[1] + i));
    Serial.print("\t");
    Serial.println(pgm_read_byte(&waveTable[1][i]));
}

Thank you for your reply. I added your code to the setup to get an overview of the memory, but I am still confused by the results. I added "i" to the table to get an index where I can reference to:

0: 	16	16	31	31	12	12
1: 	16	16	31	31	148	148
2: 	17	17	31	31	184	184
3: 	17	17	31	31	1	1
4: 	18	18	31	31	12	12
5: 	18	18	31	31	148	148
6: 	18	18	0	0	224	224
7: 	19	19	25	25	1	1
8: 	19	19	24	24	12	12
9: 	20	20	23	23	148	148
10: 	20	20	22	22	224	224
11: 	20	20	20	20	1	1
12: 	21	21	11	11	12	12
13: 	21	21	12	12	148	148
14: 	21	21	13	13	224	224
15: 	22	22	14	14	1	1
16: 	22	22	32	32	12	12
17: 	22	22	32	32	148	148
18: 	23	23	32	32	224	224
19: 	23	23	32	32	1	1
20: 	24	24	32	32	12	12
21: 	24	24	32	32	148	148
22: 	24	24	32	32	224	224
23: 	25	25	32	32	1	1
24: 	25	25	32	32	12	12
25: 	25	25	32	32	148	148
26: 	26	26	32	32	224	224
27: 	26	26	32	32	1	1
28: 	26	26	32	32	12	12
29: 	26	26	32	32	148	148
30: 	27	27	32	32	224	224
31: 	27	27	32	32	1	1
32: 	27	27	0	0	12	12
33: 	28	28	4	4	148	148
34: 	28	28	8	8	224	224
35: 	28	28	16	16	1	1
36: 	28	28	20	20	12	12
37: 	29	29	24	24	148	148
38: 	29	29	28	28	22	22
39: 	29	29	32	32	4	4
40: 	29	29	32	32	12	12
41: 	30	30	32	32	148	148
42: 	30	30	32	32	224	224
43: 	30	30	32	32	1	1
44: 	30	30	32	32	12	12
45: 	30	30	32	32	148	148
46: 	30	30	32	32	224	224
47: 	31	31	32	32	1	1
48: 	31	31	32	32	12	12
49: 	31	31	32	32	148	148
50: 	31	31	32	32	224	224
51: 	31	31	32	32	1	1
52: 	31	31	32	32	12	12
53: 	31	31	32	32	148	148
54: 	32	32	32	32	224	224
55: 	32	32	32	32	1	1
56: 	32	32	32	32	12	12
57: 	32	32	32	32	148	148
58: 	32	32	32	32	224	224
59: 	32	32	32	32	1	1
60: 	32	32	32	32	12	12
61: 	32	32	32	32	148	148
62: 	32	32	32	32	224	224
63: 	32	32	32	32	1	1
64: 	32	32	0	0	12	12
65: 	32	32	4	4	148	148
66: 	32	32	8	8	204	204
67: 	32	32	16	16	3	3
68: 	32	32	20	20	12	12
69: 	32	32	24	24	148	148
70: 	32	32	28	28	224	224
71: 	32	32	32	32	1	1
72: 	32	32	32	32	12	12
73: 	32	32	32	32	148	148
74: 	32	32	32	32	154	154
75: 	31	31	32	32	3	3
76: 	31	31	32	32	12	12
77: 	31	31	32	32	148	148
78: 	31	31	32	32	116	116
79: 	31	31	32	32	3	3
80: 	31	31	32	32	12	12
81: 	31	31	32	32	148	148
82: 	30	30	32	32	224	224
83: 	30	30	32	32	1	1
84: 	30	30	32	32	12	12
85: 	30	30	32	32	148	148
86: 	30	30	32	32	224	224
87: 	30	30	32	32	1	1
88: 	29	29	32	32	12	12
89: 	29	29	32	32	148	148
90: 	29	29	32	32	224	224
91: 	29	29	32	32	1	1
92: 	28	28	32	32	12	12
93: 	28	28	32	32	148	148
94: 	28	28	32	32	224	224
95: 	28	28	32	32	1	1
96: 	27	27	0	0	12	12
97: 	27	27	4	4	148	148
98: 	27	27	8	8	224	224
99: 	26	26	16	16	1	1
100: 	26	26	20	20	12	12
101: 	26	26	24	24	148	148
102: 	26	26	28	28	224	224
103: 	25	25	32	32	1	1
104: 	25	25	32	32	32	32
105: 	25	25	32	32	32	32
106: 	24	24	32	32	32	32
107: 	24	24	32	32	32	32
108: 	24	24	32	32	32	32
109: 	23	23	32	32	32	32
110: 	23	23	32	32	32	32
111: 	22	22	32	32	32	32
112: 	22	22	32	32	32	32
113: 	22	22	32	32	32	32
114: 	21	21	32	32	32	32
115: 	21	21	32	32	32	32
116: 	21	21	32	32	32	32
117: 	20	20	32	32	32	32
118: 	20	20	32	32	32	32
119: 	20	20	32	32	32	32
120: 	19	19	32	32	32	32
121: 	19	19	32	32	32	32
122: 	18	18	32	32	32	32
123: 	18	18	32	32	32	32
124: 	18	18	32	32	32	32
125: 	17	17	32	32	32	32
126: 	17	17	32	32	32	32
127: 	16	16	32	32	32	32
128: 	16	16	0	0	32	32
129: 	16	16	4	4	32	32
130: 	15	15	8	8	32	32
131: 	15	15	16	16	32	32
132: 	14	14	20	20	32	32
133: 	14	14	24	24	32	32
134: 	14	14	28	28	32	32
135: 	13	13	32	32	32	32
136: 	13	13	32	32	32	32
137: 	12	12	32	32	32	32
138: 	12	12	32	32	32	32
139: 	12	12	32	32	32	32
140: 	11	11	32	32	32	32
141: 	11	11	32	32	32	32
142: 	11	11	32	32	32	32
143: 	10	10	32	32	32	32
144: 	10	10	32	32	32	32
145: 	10	10	32	32	32	32
146: 	9	9	32	32	32	32
147: 	9	9	32	32	32	32
148: 	8	8	32	32	32	32
149: 	8	8	32	32	32	32
150: 	8	8	32	32	32	32
151: 	7	7	32	32	32	32
152: 	7	7	32	32	32	32
153: 	7	7	32	32	32	32
154: 	6	6	32	32	32	32
155: 	6	6	32	32	32	32
156: 	6	6	32	32	32	32
157: 	6	6	32	32	32	32
158: 	5	5	32	32	32	32
159: 	5	5	32	32	32	32
160: 	5	5	0	0	32	32
161: 	4	4	4	4	32	32
162: 	4	4	8	8	32	32
163: 	4	4	16	16	32	32
164: 	4	4	20	20	32	32
165: 	3	3	24	24	32	32
166: 	3	3	28	28	32	32
167: 	3	3	32	32	32	32
168: 	3	3	32	32	32	32
169: 	2	2	32	32	32	32
170: 	2	2	32	32	32	32
171: 	2	2	32	32	32	32
172: 	2	2	32	32	32	32
173: 	2	2	32	32	32	32
174: 	2	2	32	32	32	32
175: 	1	1	32	32	32	32
176: 	1	1	32	32	32	32
177: 	1	1	32	32	32	32
178: 	1	1	32	32	32	32
179: 	1	1	32	32	32	32
180: 	1	1	32	32	32	32
181: 	1	1	32	32	32	32
182: 	0	0	32	32	32	32
183: 	0	0	32	32	32	32
184: 	0	0	32	32	32	32
185: 	0	0	32	32	32	32
186: 	0	0	32	32	32	32
187: 	0	0	32	32	32	32
188: 	0	0	32	32	32	32
189: 	0	0	32	32	32	32
190: 	0	0	32	32	32	32
191: 	0	0	32	32	32	32
192: 	0	0	0	0	32	32
193: 	0	0	4	4	32	32
194: 	0	0	8	8	32	32
195: 	0	0	16	16	32	32
196: 	0	0	20	20	32	32
197: 	0	0	24	24	32	32
198: 	0	0	28	28	32	32
199: 	0	0	32	32	32	32
200: 	0	0	32	32	32	32
201: 	0	0	32	32	32	32
202: 	0	0	32	32	32	32
203: 	1	1	32	32	32	32
204: 	1	1	32	32	32	32
205: 	1	1	32	32	32	32
206: 	1	1	32	32	32	32
207: 	1	1	32	32	32	32
208: 	1	1	32	32	32	32
209: 	1	1	32	32	32	32
210: 	2	2	32	32	32	32
211: 	2	2	32	32	32	32
212: 	2	2	32	32	32	32
213: 	2	2	32	32	32	32
214: 	2	2	32	32	32	32
215: 	2	2	32	32	32	32
216: 	3	3	32	32	32	32
217: 	3	3	32	32	32	32
218: 	3	3	32	32	0	0
219: 	3	3	32	32	32	32
220: 	4	4	32	32	32	32
221: 	4	4	32	32	32	32
222: 	4	4	32	32	32	32
223: 	4	4	32	32	32	32
224: 	5	5	0	0	32	32
225: 	5	5	4	4	32	32
226: 	5	5	8	8	32	32
227: 	6	6	16	16	32	32
228: 	6	6	20	20	32	32
229: 	6	6	24	24	32	32
230: 	6	6	28	28	32	32
231: 	7	7	32	32	32	32
232: 	7	7	32	32	32	32
233: 	7	7	32	32	32	32
234: 	8	8	32	32	32	32
235: 	8	8	32	32	32	32
236: 	8	8	32	32	32	32
237: 	9	9	32	32	32	32
238: 	9	9	32	32	32	32
239: 	10	10	32	32	32	32
240: 	10	10	32	32	32	32
241: 	10	10	32	32	32	32
242: 	11	11	32	32	32	32
243: 	11	11	32	32	32	32
244: 	11	11	32	32	32	32
245: 	12	12	32	32	32	32
246: 	12	12	32	32	32	32
247: 	12	12	32	32	32	32
248: 	13	13	32	32	32	32
249: 	13	13	32	32	32	32
250: 	14	14	32	32	32	32
251: 	14	14	32	32	32	32
252: 	14	14	32	32	32	32
253: 	15	15	32	32	32	32
254: 	15	15	32	32	32	32

Looks like the blnkWave is starting at index# 104 of the waveTable?

Eyes open mate, blnkWave isn't being printed!

I got it! I should have used

static uint8_t currentWave = 0;

instead of:

static int currentWave = 0;

It is all working fine now. I ended up listing all the addresses for the PROGMEM to determine where the data was located. So sineWave[0] started at 0x26E, spinWave[0] at 0x16E and blnkWave[0] at 0x6E. The initial currentWave array started reading at 0x00, so it got to spinWave first at 0x6E. Thank so much for your support.

  Serial.println(pgm_read_byte_near(waveTable[currentWave]));

You put (I can NOT imagine why) waveTable in PROGMEM, but are accessing it like it is in SRAM. That is an epic fail.