Pages: [1]   Go Down
Author Topic: PROGMEM usage  (Read 6528 times)
0 Members and 1 Guest are viewing this topic.
Vancouver, Canada
Offline Offline
Newbie
*
Karma: 1
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey folks - I've got hopefully a simple one here.

I'm playing around with using PROGMEM based on the samples in the docs, and it doesn't appear to be working as expected for me. I'm unsure of what I'm doing wrong. Here's the test code, and it outputs nothing.

Code:
#include <avr/pgmspace.h>
prog_char cmd_hello[] PROGMEM = "Hello!";
char flashStringBuffer[32];

setup() {
  Serial.print(GS(cmd_hello));
}

char* GS(const prog_char str[]){
strcpy_P(flashStringBuffer, (char*)pgm_read_word(&(str)));
return flashStringBuffer;
}

Output: (nothing)

However, when I print the char const directly it outputs fine. Is the PROGMEM not storing the data in the flash? I shouldn't be able to access the char array directly should I?

Code:
#include <avr/pgmspace.h>
prog_char cmd_hello[] PROGMEM = "Hello!";
char flashStringBuffer[32];

setup() {
  Serial.print(GS(cmd_hello));
}

char* GS(const prog_char str[]){
strcpy_P(flashStringBuffer, (char*)str);
return flashStringBuffer;
}

Output: Hello!
Logged

Beginner Enthusiast

SE USA
Offline Offline
Faraday Member
**
Karma: 41
Posts: 3783
@ssh0le
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

not that it awnsers your question, but you could do

Serial.print(F(“Hello World”))

which is a function that puts its string into progmem

Logged


Vancouver, Canada
Offline Offline
Newbie
*
Karma: 1
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

No I'm aware of the F() macro - I'm trying to optimize re-usage of very large numbers of string literals and the F() macro while useful, isn't quite what I need.
Logged

Beginner Enthusiast

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 64
Posts: 2101
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

strcpy_P is the PROGMEM version of strcpy.

If you pass it cmd_hello, it does the  'pgm_read_XX' handling for you.

cmd_hello is a pointer stored in ram pointing to its data stored in flash, you only need special functions to access the data, not the pointer.

Logged


SE USA
Offline Offline
Faraday Member
**
Karma: 41
Posts: 3783
@ssh0le
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

what happens if you toss it in a loop and read back one char at a time without pcopy
Logged


Vancouver, Canada
Offline Offline
Newbie
*
Karma: 1
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

pYro - that makes a world of sense to me now. I noticed this is how the docs on PROGMEM were accessing the data, however the difference is that they use a table of strings and the address to that table must be stored in flash ram, hence the call to pgm_read_word.

Would someone be able to give me a quick pointer on how to determine if the string data is in fact being stored in flash vs. sram? I noticed the compile sketch size is identical for PROGMEM vs. string literal declaration (using Visual Micro on VS 2012).

Thanks a ton!
Logged

Beginner Enthusiast

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 64
Posts: 2101
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Just try printing the array as normal, it should do some undefined bahaviour/nothing/everything.

Code:
char inRam[] = "String in SRAM";

char inProgmem[] PROGMEM = "String in FLASH";

void setup() {

 char buff[ 20 ];
 
 Serial.begin(9600);
 
 Serial.print( "Read inRam from ram: " );
 Serial.println( inRam );
 
 strcpy_P( buff, inProgmem );
 
 Serial.print( "Read inProgmem from flash: " );
 Serial.println( buff );
 
 Serial.print( "Read inProgmem from ram: " );
 Serial.println( inProgmem );
}

void loop() {}
Logged


Australia
Offline Offline
Sr. Member
****
Karma: 13
Posts: 444
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I thought that any PROGMEM strings had to be set as constant before being placed in flash.

e.g. const char inProgmem[] PROGMEM = "String in FLASH";

I've often had compile errors reminding me to set them as const.

What is the rule regarding this?
« Last Edit: April 06, 2013, 11:31:53 pm by lemming » Logged

Vancouver, Canada
Offline Offline
Newbie
*
Karma: 1
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Pyro - thanks that was enlightening!

I do believe the constant requirement is merely recommended practice. You don't want the pointer to the flash ram to change mid-program through accidental assignment or resource corruption do you?
Logged

Beginner Enthusiast

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 64
Posts: 2101
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yeah, moving the pointer could be bad, however using the pointer value is fine:

Code:
strcpy_P( buff, inProgmem + 5 );
 Serial.print( "Read inProgmem[ 5 ] from flash: " );
 Serial.println( buff );

it uses the same principle involved in using struct members to offset a pointer:

Code:
struct RGB{
  int red;
  int green;
  int blue;
};

RGB Colours[] PROGMEM = {
     { 0, 0, 0 },
     { 255, 0, 0 },
     { 2, 255, 0 },
     { 0, 0, 255 },
     { 255, 0, 255 },
     { 255, 255, 255 },     
  };

void GetColour( RGB &r_Out, int i_Index )
  {
    const RGB &r_Colour = *(Colours + i_Index);
   
    r_Out.red = pgm_read_word( &r_Colour.red );
    r_Out.green = pgm_read_word( &r_Colour.green );
    r_Out.blue = pgm_read_word( &r_Colour.blue );
    return;
  }
Logged


SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 124
Posts: 6636
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
give me a quick pointer on how to determine if the string data is in fact being stored in flash vs. sram? I noticed the compile sketch size is identical for PROGMEM vs. string literal declaration (using Visual Micro on VS 2012).

Run "avr-size" on the resulting .elf file, and look at the size in the "data" column.
Code:
void setup()
{
  Serial.begin(115200);
  Serial.print(F("This is a test of stuff"));
}
void loop() {}
Without the F(), and with the F():
BillW-MacOSX-2<10619> avr-size *.elf
   text    data     bss     dec     hex filename
   1810      40     179    2029     7ed sketch_apr07a.cpp.elf
BillW-MacOSX-2<10620> avr-size *.elf
   text    data     bss     dec     hex filename
   1842      16     179    2037     7f5 sketch_apr07a.cpp.elf
Logged

Offline Offline
Full Member
***
Karma: 2
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

May not be relevant to you but I had much more success using the Flash library http://arduiniana.org/libraries/flash/
It was easy to implement and took me just 1 day to stuff all my strings into flash memory rather than Ram. Works like a charm.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Pyro - thanks that was enlightening!

I do believe the constant requirement is merely recommended practice. You don't want the pointer to the flash ram to change mid-program through accidental assignment or resource corruption do you?

Making it const won't stop corruption.
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 124
Posts: 6636
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Newer versions of the compiler REQUIRE the "const" on flash things.
BillW-MacOSX-2<10630> /usr/local/CrossPack-AVR-20100115/bin/avr-gcc -mmcu=atmega328p -c foo.c
   (compile was OK)

BillW-MacOSX-2<10631> /usr/local/CrossPack-AVR-20121207/bin/avr-gcc -mmcu=atmega328p -c foo.c
foo.c:4:6: error: variable 'foo' must be const in order to be put into read-only section by means of '__attribute__((progmem))'

Logged

Pages: [1]   Go Up
Jump to: