PROGMEM on a transform array?

Status
Not open for further replies.

wolfv

Well-known member
I want to use PROGMEM with a transform array.
PROGMEM and TRANSFORM array work as expected when implemented individually.
But PROGMEM with TRANSFORM array implemented together does not have the expected output.
The following example sketch was compiled 4 ways, here are the 4 outputs:

#define WITH_PROGMEM, output is as expected.
Code:
output: ab

#define WITH_TRANSFORM, output is as expected.
Code:
output: ba

#define WITH_PROGMEM_TRANSFORM1, output is blank, was expecting "ba".
Code:
output:

#define WITH_PROGMEM_TRANSFORM2, output is blank, was expecting "ba".
Code:
output:

Example sketch:
Code:
//uncomment exactly one #define and compile
//#define WITH_PROGMEM
//#define WITH_TRANSFORM
#define WITH_PROGMEM_TRANSFORM1
//#define WITH_PROGMEM_TRANSFORM2

const char A = 'a';
const char B = 'b';

#ifdef WITH_PROGMEM                    //output: ab
const PROGMEM char * const layout[] = {&A, &B};

const char* getPtrChar(uint8_t i)
{
    return (char*) pgm_read_ptr(&layout[i]);
}
#endif

#ifdef WITH_TRANSFORM                  //output: ba
const char * const layout[] = {&A, &B};
const char * const transform[] = { layout[1], layout[0] };

const char* getPtrChar(uint8_t i)
{
    return transform[i];
}
#endif

#ifdef WITH_PROGMEM_TRANSFORM1         //output: 
const char * const layout[] = {&A, &B};
const PROGMEM char * const transform[] = { layout[1], layout[0] };

const char* getPtrChar(uint8_t i)
{
    return (char*) pgm_read_ptr(&transform[i]);
}
#endif

#ifdef WITH_PROGMEM_TRANSFORM2          //output: 
const PROGMEM char * const layout[] = {&A, &B};
const char * const transform[] = { layout[1], layout[0] };

const char* getPtrChar(uint8_t i)
{
    return (char*) pgm_read_ptr(&(transform[i]));
}
#endif

void setup()
{
    Keyboard.begin();
    delay(1000);
    Keyboard.print(F("output: "));

    const char* ptrChar;

    ptrChar = getPtrChar(0);
    Keyboard.print(*ptrChar);

    ptrChar = getPtrChar(1);
    Keyboard.print(*ptrChar);
}
void loop() {}
How to use PROGMEM with a transform array?:confused:

I am running Teensy2 on Arduino IDE 1.6.5 with C++11 and Teensyduino 1.25 on Linux.

Thank you.
 
Last edited:
Is there a reason you're storing pointers to the address of A and B?

Have you tried:
Code:
const char layout[] = {A, B};
const PROGMEM ptrsChars[] = { layout[1], layout[0] };

I believe this post has a greater explanation but it's early on a Monday so ;)
 
Oh, so many things wrong here. Maybe later today I'll write more, if I can even figure out what you're really trying to do here... but in the meantime, here's how to make the code "work".

Code:
PROGMEM const char A = 'a';
PROGMEM const char B = 'b';

const char * const layout[] = {&A, &B};
const char * const ptrsChars[] = { layout[1], layout[0] };

const char * getPtrChar(uint8_t i)
{
    return ptrsChars[i];
}

void setup()
{
    Serial.begin(9600);
    delay(1000);
    Serial.print(F("output: "));

    const char * ptrChar;

    ptrChar = getPtrChar(0);
    Serial.print((char)pgm_read_byte(ptrChar));

    ptrChar = getPtrChar(1);
    Serial.print((char)pgm_read_byte(ptrChar));
}
void loop() {}

One important point here is the only 2 variables actually stored in PROGMEM are A and B. Both arrays are in RAM. Maybe that's not what you wanted. And maybe you wanted getPtrChar() to return something that doesn't require pgm_read_byte() in the main program. Maybe? What you really wanted isn't clear at all. You only asked "How to use PROGMEM with a transform array". So I showed how to use PROGRAM with these arrays....

If you want something other than this, maybe you could explain your goals?
 
Last edited:
Ooops... I thought PROGMEM was EEPROM for some reason.
That's why I was questioning why pointers were being used :L
 
Hi Paul,
I apologize for not explaining better. Here is a better explanation:

In the actual application, A and B are class objects.
As I understand it, moving class objects into PROGMEM doesn't save RAM.
I moved arrays of pointers into PROGMEM and that saved 474 RAM.
My goal is to add transform arrays without consuming additional RAM.

In my example #ifdef WITH_PROGMEM, layout[] is an array of pointers in PROGMEM
In my example #ifdef WITH_TRANSFORM, the transform[] array transforms the layout[] array.
But it only works without PROGMEM.
How to add a transform array in example #ifdef WITH_PROGMEM, without consuming additional RAM?

Thank you.
 
I still don't understand what you mean by "transform arrays". Obviously this means something specific to you, but I simply do not know this term, so I don't understand what you're saying.
 
So this transform array is located in RAM, and it points to data in PROGMEM?

I see 2 arrays in your program: ptrsChars[] and layout []. Which one is the transform array? Why are there two?
 
The following example sketch has two arrays, layout[] and transform[].
Both arrays are const, so I would like to put both of them in PROGMEM.

The application I am working on is a keyboard.
layout[] is a row-column grid of keys on a keyboard as they appear to the user while typing on the keyboard.
transform[] is a row-column matrix of switches the controller is connected to.
When a key on the keyboard is pressed, the firmware uses the transform[] array to send the corresponding key specified in layout[].
The layout[] array is already in PROGMEM, now I want to add the transform[] array to PROGMEM.

Thanks for asking the right questions. I will try to include more information.

Code:
const char A = 'a';
const char B = 'b';

const char * const layout[] = {&A, &B};
const char * const transform[] = { layout[1], layout[0] };

const char* getPtrChar(uint8_t i)
{
    return transform[i];
}

void setup()
{
    Keyboard.begin();
    delay(1000);
    Keyboard.print(F("output: "));

    const char* ptrChar;

    ptrChar = getPtrChar(0);
    Keyboard.print(*ptrChar);

    ptrChar = getPtrChar(1);
    Keyboard.print(*ptrChar);
}
void loop() {}
 
Well, if you want *everything* in PROGMEM, as far as I know, you can't have "layout[number]" as an initializer. Maybe there's a way, but I don't know of any. As far as I can tell, the compiler is only able to resolve addresses of PROGMEM stuff, not the data itself.

So you'll need to change transform[] to be a pointer to a pointer. Like this:

Code:
PROGMEM const char A = 'a';
PROGMEM const char B = 'b';

PROGMEM const char * const layout[] = {&A, &B};
PROGMEM const char * const * const transform[] = { &layout[1], &layout[0] };

const char* getPtrChar(uint8_t i)
{
  return (const char *)pgm_read_ptr(pgm_read_ptr(&transform[i]));
}

void setup()
{
    Serial.begin(9600);
    delay(1000);
    Serial.print(F("output: "));

    const char* ptrChar;

    ptrChar = getPtrChar(0);
    Serial.print((char)pgm_read_byte(ptrChar));

    ptrChar = getPtrChar(1);
    Serial.print((char)pgm_read_byte(ptrChar));
}
void loop() {}

That's some messy syntax... so perhaps you might consider switching to the less expensive Teensy-LC board, which avoids all this PROGMEM ugliness. But if you really want it, this is how you can make it work.
 
Status
Not open for further replies.
Back
Top