Passing PGM_P into functions

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Passing PGM_P into functions

Postby morrijr » Tue Aug 26, 2008 7:17 am

I'm having problems using progmem, I'm correctly getting "Test working?" when directly calling strcpy_P in the loop but not for the other cases. I need to pass the string into another function where, as below, I do the conversion to buffer there. As far as I can tell (with limited embedded knowledge) these should be all the same...

Can anyone help?

Thanks.

Code: Select all
#include <avr/pgmspace.h>

const prog_char PROGMEM stringTest[] = "Test working?";

PGM_P PROGMEM stringTestTable[] = { stringTest };

char buffer[17];

void setup() {
   Serial.begin(9600);
}

void loop() {
   strcpy_P(buffer, (char*)pgm_read_word(&(stringTestTable[0])));
   Serial.print(buffer);
   Serial.print(" : ");
   
   strcpy_P(buffer, (char*)pgm_read_word(&(stringTest)));
   Serial.print(buffer);
   Serial.print(" : ");
   
   Print(stringTestTable[0]);
   Serial.print(" : ");
   
   Print(stringTest);
}

void Print(PGM_P str) {
   strcpy_P(buffer, (char*)pgm_read_word(&(str)));
   Serial.println(buffer);
}
morrijr
 
Posts: 3
Joined: Tue Aug 26, 2008 7:11 am

Re: Passing PGM_P into functions

Postby mtbf0 » Tue Aug 26, 2008 8:08 am

don't have time to research it properly, but something like this ought to be a start.

Code: Select all
   Print(&stringTestTable[0]);
   Serial.print(" : ");

...

void Print(PGM_P *str) {
   strcpy_P(buffer, (char*)pgm_read_word(str));
   Serial.println(buffer);
}


maybe
"i want to lead a dissipate existence, play scratchy records and enjoy my decline" - iggy pop, i need more
User avatar
mtbf0
 
Posts: 1642
Joined: Fri Nov 09, 2007 11:59 pm
Location: oakland ca

Postby morrijr » Tue Aug 26, 2008 10:20 am

That gives me

error: cannot convert ‘const prog_char*’ to ‘const prog_char**’ for argument ‘1’ to ‘void Print(const prog_char**)’

PGM_P is typedef'd to const prog_char*

thanks for the response, I've been asking on several boards/irc for a few days now and this is the first time somebodies actually suggested something!

J.
morrijr
 
Posts: 3
Joined: Tue Aug 26, 2008 7:11 am

Postby mtbf0 » Tue Aug 26, 2008 7:33 pm

PGM_P is typedef'd to const prog_char*


see, that's what i didn't have time to look up.

i'd suggest changing the function definition back to what it was, i.e. lose the asterisk, and either keep the other change i suggested or use

Code: Select all
   Print(stringTestTable);


your original code passes the character 'T' to the function. either of my versions pass its address.

sorry to have answered before i was fully awake and while i was trying to get out the door.
"i want to lead a dissipate existence, play scratchy records and enjoy my decline" - iggy pop, i need more
User avatar
mtbf0
 
Posts: 1642
Joined: Fri Nov 09, 2007 11:59 pm
Location: oakland ca

Postby morrijr » Wed Aug 27, 2008 3:41 am

Hi mtbf0,

westfw on the Arduino Forum pointed me in the right direction. BTW, I didn't typedef PGM_P, it's a standard one in avr/pgmspace.h

Anyway, for anyone wanting to know what the answer is;

Code: Select all
#include <avr/pgmspace.h>

const prog_char PROGMEM stringTest[] = "Test working?";

PGM_P PROGMEM stringTestTable[] = { stringTest };

char buffer[17];

void setup() {
   Serial.begin(9600);
}

void loop() {
   // the pgm_read_word here is to get the correct pointer from the PROGMEM array
   strcpy_P(buffer, (char*)pgm_read_word(&(stringTestTable[0])));
   Serial.print(buffer);
   Serial.print(" : ");

   // pgm_read_word is not required here because it is handled within strcpy_P
   strcpy_P(buffer, stringTest);
   Serial.print(buffer);
   Serial.print(" : ");

   // I don't understand why pgm_read_word isn't required for
   // this one but is for the first?
   Print(stringTestTable[0]);
   Serial.print(" : ");
   
   // pgm_read_word is not required here because it is handled within strcpy_P
   // within the called function (Print)
   Print(stringTest);

   Serial.println("");
}

void Print(PGM_P str) {
   strcpy_P(buffer, str);
   Serial.print(buffer);
}


As you can see, I still don't understand why the third test works, but *shrug* :)

But, as I said; thank you very much for at least attempting to help.

J.
morrijr
 
Posts: 3
Joined: Tue Aug 26, 2008 7:11 am

Postby mtbf0 » Wed Aug 27, 2008 6:57 am

i'm so ashamed.

but maybe i can help you uncerstand what's going on...

this declares a zero terminated array of characters, i.e. a string, in program memory.
Code: Select all
const prog_char PROGMEM stringTest[] = "Test working?";


this declares an array, (a very short array), of addresses of strings in program memory. note that these addresses are 16 bit values.

Code: Select all
PGM_P PROGMEM stringTestTable[] = { stringTest };


this will read the address of stringTest from program memory.

Code: Select all
(char*)pgm_read_word(&(stringTestTable[0]))


an array reference without a subscript gives the address of the array, thus "stringTest" resolves to the address of stringTest.

stringTestTable is an array of string addresses, so "stringTestTable[0]" resolves to the address of stringTest.

the difference between the first and third examples is that in the first example the address resolves at run time and in the third it is resolved at compile time. this doesn't really seem right until you consider that data stored in program memory are implicitly const and so will not be altered at run time.

this means that the third example will run faster than the first and in this case would be the one you want to use. you would want to use the first example in the case where your stringTestTable is longer than one entry and you are using a variable index, because that reference would not be resolvable at compile time.

so...

Code: Select all
  int i = 0;
  Print(stringTestTable[i]);


... should not work.

but i've been wrong before. at least twice that we know of.
"i want to lead a dissipate existence, play scratchy records and enjoy my decline" - iggy pop, i need more
User avatar
mtbf0
 
Posts: 1642
Joined: Fri Nov 09, 2007 11:59 pm
Location: oakland ca


Return to Arduino

Who is online

Users browsing this forum: No registered users and 8 guests

Stuff to buy from the Adafruit store and links to product documentation!


New Products [105]

Raspberry Pi[80]
 
FLORA[23]
 
Bunnie Studios[9]
 
FPGA[1]
 
mbed[11]
Arduino[60]
 
NETduino[14]
 
BeagleBone[24]
 
Android[6]
 
XBee[10]
More Dev Boards[30]


 
BoArduino[8]
 
SpokePOV[4]
 
TV-B-Gone[4]
 
MiniPOV[3]
 
SIM reader[3]
 
Microtouch[5]
 
Clocks & Watches[18]
 
Drawdio[4]
 
Brain Machine[1]
 
Game of Life[2]
 
MintyBoost[2]
More DIY Kits[16]


 
MaKey MaKey[3]
 
Tweet-a-Watt[5]
 
Young Engineers[33]
 
Discover Electronics[2]
 
Snap Circuits[4]
 
littleBits[3]
 
Project packs[8]


 
Breakout Boards[33]
LCDs & Displays[48]
Components & Parts[69]
Batteries & Power[49]
EL Wire/Tape/Panel[52]
LEDs[108]
 
Wireless[14]
Cables[60]
 
Lasers[6]
Sensors/Parts[145]
 
Enclosures/Cases[11]
 
Solar[11]
 
RFID / NFC[13]
Prototyping[69]
 
iDevices[13]
Tools[71]
 
Wearables[39]
 
CNC[37]
 
Robotics[29]
 
3D printing[1]
 
Materials[24]


 
Stickers[41]
 
Skill badges[55]
 
Books[25]
 
Circuit Playground[7]
 
Gift Certificates[4]