PROGMEM array of structs

I have the following to store mapping of positions of leds for certain words in a wordclock:

#ifndef MAPS_H
#define MAPS_H

#include <avr/pgmspace.h>

typedef struct WordMap 
{
	char* name; // identifier
	uint8_t row; // the row number (0-7)
	uint16_t rowPos; // two bytes of positions that should be on or off (16 positions available)
} mapWords[];
typedef struct HourMap 
{
	uint8_t name;
	uint8_t row;
	uint16_t rowPos;
} mapHours[];
typedef struct MinuteMap 
{
	uint8_t name;
	uint8_t row; 
	uint16_t rowPos; 
} mapMinutes[];

static const PROGMEM mapWords words = {
	{"het",		0,	0xe000}, // 1110000000000000 
};
static const PROGMEM mapHours hours = {
	{1, 3, 0xe000}  // 1110000000000000 
};
static const PROGMEM mapMinutes minutes = {
/*	etc. */
};

#endif

To show the word “het” the first 3 leds (B1110000000000000) of the first row (0) should be on and for the hour 1 the same on row 3…

Is this a smart way of storing it or is there a more economic way?
And how can I read this from the memory using pgm_read_* or something else?
I searched it on Google, etc, but could not find a good example or explanation, so a little help is much appreciated :slight_smile:

String literals need to be placed into memory separate, otherwise you still have it in RAM, but you can use an additional struct to combine the three, then you only need one array. Here is an example using a single element ( not an array ). but expanding to an array is simple:

struct WordMap{
  char* name; // identifier
  uint8_t row; // the row number (0-7)
  uint16_t rowPos; // two bytes of positions that should be on or off (16 positions available)
};

struct HourMap{
  uint8_t name;
  uint8_t row;
  uint16_t rowPos;
};

struct MinuteMap{
  uint8_t name;
  uint8_t row; 
  uint16_t rowPos; 
};

struct Maps{
  WordMap Words;
  HourMap Hours;
  MinuteMap Minutes;
};

char het[] PROGMEM = "het";
Maps maps PROGMEM = { {het,    0,  0xe000}, {1, 3, 0xe000}, { 1,2,3 } };

To use in pgm_read_xxx, find the element you need then take its address. Say I want the row value from the WordMap:

x = pgm_read_byte( &maps.Words.row );

Thanks!

I ditched the strings in the array and probably I’m going to get rid of the 'id’s also because it’s probably just as easy to select them through the array pointers (and keep some map in my comments for readability).

This what I have now:

#ifndef MAPS_H
#define MAPS_H

#include <avr/pgmspace.h>

struct WordMap 
{
	uint8_t id;
	uint8_t row;
	uint16_t rowPos;
}; 
struct HourMap 
{
	uint8_t id;
	uint8_t row;
	uint16_t rowPos;
}; 
struct MinuteMap 
{
	uint8_t id;
	uint8_t row;
	uint16_t rowPos;
}; 
struct Maps
{
	WordMap words[11];
	HourMap hours[12];
	MinuteMap minutes[5];
};
Maps clockMaps PROGMEM = {
	// words
	{ 
		{0 /* het */,	0,	0xe000}, // 1110000000000000
		{1 /* is */,	0,	0x0c00}, // 0000110000000000
		{2 /* bijna */,	0,	0x00f8}, // 0000000011111000
		{3 /* voor */, 	2,	0xf000}, // 1111000000000000
		{4 /* over */,	2, 	0x0f00}, // 0000111100000000
		{5 /* uur */,	6, 	0x01c0}, // 0000000111000000
		{6 /* vm */,	6,	0x0018}, // 0000000000011000
		{7 /* nm */,	6,	0x0006}, // 0000000000000110
		{8 /* geweest */,7, 0x7f00}, // 0111111100000000
		{9 /* tik */,	7,	0x0070}, // 0000000001110000
		{10 /* tak */,	7,	0x000e}  // 0000000000001110
	},
	// hours
	{ 
		{0, 	6, 0xfc00}, // 1111110000000000 // twaalf
		{1, 	3, 0xe000}, // 1110000000000000
		{2, 	3, 0x1e00}, // 0001111000000000
		{3, 	3, 0x01e0}, // 0000000111100000
		{4, 	3, 0x001e}, // 0000000000011110
		{5, 	4, 0xf000}, // 1111000000000000
		{6, 	4, 0x0e00}, // 0000111000000000
		{7, 	4, 0x01f0}, // 0000000111110000
		{8, 	4, 0x000f}, // 0000000000001111
		{9, 	5, 0xf800}, // 1111100000000000
		{10, 	5, 0x03c0}, // 0000001111000000
		{11, 	5, 0x001c}  // 0000000000011100
	},
	// minutes
	{ 
		{0, 	0, 0x0000}, // 
		{5, 	1, 0xf000}, // 1111000000000000
		{10, 	1, 0x0f00}, // 0000111100000000
		{15, 	1, 0x0f80}, // 0000000011111000
		{30, 	2, 0x0078}  // 0000000001111000
	}
};

#endif

And accessed like this:

uint8_t x = 3; // selecting 'bijna'
uint8_t row = pgm_read_byte(&clockMaps.words[x].row);
uint16_t pos = pgm_read_word(&clockMaps.words[x].rowPos);

Thanks for the help!