Pages: [1]   Go Down
Author Topic: Hardcoded strings and PSTR  (Read 7805 times)
0 Members and 1 Guest are viewing this topic.
UK
Offline Offline
Jr. Member
**
Karma: 2
Posts: 90
It was like it when I found it
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Is there a simple solution to the PSTR issue?

I recently got all excited when I discovered I could use.....
#include <avr/pgmspace.h> and PSTR()
To write all my hardcoded strings to program memory rather than data memory. I duly changed lots of hardcoded stuff

Serial.println(“Hello world”) became  Serial.println(PSTR(“Hello world”))
And
strcpy(errMessage,("not plugged in")) became strcpy(errMessage,(PSTR("not plugged in")))

Throughout my code, only to discover it didn’t work and I had to undo everything!

I checked the forum, and it’s obviously a known issue (wish I’d checked before I’d made the changes). Is there a fix to this issue, or maybe a better way of doing this? I did discover a couple of posts about this, but they seemed to only work for Serial.println, and not for all inline strings.
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 207
Posts: 12917
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Try this...
http://arduiniana.org/libraries/flash/
Logged

Essex, UK
Offline Offline
Full Member
***
Karma: 4
Posts: 150
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Why did you undo everything? Most of the std library functions have _P equivalents that work with strings in flash. strcpy_P for example...
Logged

Home of the Nokia QVGA TFT LCD hacks: http://andybrown.me.uk

UK
Offline Offline
Jr. Member
**
Karma: 2
Posts: 90
It was like it when I found it
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The problem isn't with the _P equivalents, it with the interpretation of hardcoded string literals. This command....
Serial.println(PSTR(“Hello world”))
Ought to work but doesn't (not in arduino world anyway). This forum hosts threads about this, but the most recent one I could find was over a year old and I was hoping for some fresh developments since then.

I'll try the flash library.
Logged

Essex, UK
Offline Offline
Full Member
***
Karma: 4
Posts: 150
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
This command.... Serial.println(PSTR(“Hello world”)) Ought to work

No it ought not to work! Serial.println expects a pointer into SRAM and you are trying to pass it a pointer into flash. The Harvard architecture of the AVR MCU means that address N could be in flash or it could be in SRAM and so a function (e.g. println) that receives a memory address must know in which memory bank it lies. The convention is that ordinarily named functions expect SRAM addresses and those with an _P suffix expect flash addresses in at least one of their parameters.

If you want println to accept a flash address then you could subclass it and add _P methods or you will need to temporarily copy your string out of flash like this:

Code:
char *buffer;
buffer=(char *)malloc(strlen_P(progmemstring)+1);
strcpy_P(buffer,progmemstring);
Serial.println(buffer);
free(buffer);
Logged

Home of the Nokia QVGA TFT LCD hacks: http://andybrown.me.uk

Offline Offline
Edison Member
*
Karma: 3
Posts: 1001
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ought to work but doesn't (not in arduino world anyway).
It is not so much the Arduino or the C compiler, but the fact that the AVR microcontroller is based on Harvard architecture (as opposed to von Neumann). Anything in flash memory requires different low level access code on an AVR. That is, a function needs to know whether it should fetch data from flash or from RAM. The address of the data is not sufficient by itself.  This is why you see duplication of functions with a _P suffix.

I’ve used PSTR quite a lot and find it useful. The only thing you need is to write your own “print_P” function as it is not available in the standard core library. An implementation could be as follows:

Code:
// print a character string from program memory
void print_P(const char *str)
{
  uint8_t val;
  while (true) {
    val=pgm_read_byte(str);
    if (!val) break;
    Serial.write(val);
    str++;
  }
}
Logged

Essex, UK
Offline Offline
Full Member
***
Karma: 4
Posts: 150
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I **think** the problem is not with Arduino, but with the GCC C++ compiler.
I had similar problems in doing this in a very small project using C++, and make files  etc - and worked through the examples discussed in the winavr documentation - to find the I could not make PSTR() work at all.

Apparently the PSTR() macro uses extensions to the C language, that happen to work sometimes and in some versions of the C++ compiler, but that there are issues with these extensions in C++, so they are not supported.

There is absolutely nothing wrong or unsupported about PSTR in either the latest version of g++ or the somewhat dated version shipped with the Arduino IDE. Please post any problematic code that you have and I'll be happy to correct it for you.
Logged

Home of the Nokia QVGA TFT LCD hacks: http://andybrown.me.uk

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

The "problem" seems to be that C++ does not recognize PSTR as a different data type compared to char*, so functions like Serial.print() don't know which ones they've been passed.  the "flash" library does some clever things to get around this, but I usually just define a new function:
Code:

void flashprint (const char p[])
{
    byte c;
    while (0 != (c = pgm_read_byte(p++))) {
Serial.write(c);
    }
}

#define fp(string) flashprint(PSTR(string));
Logged

UK
Offline Offline
Full Member
***
Karma: 2
Posts: 110
Kittens eat Arduinos
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Andy,

I had issues with PSTR() and the release winavr (20100110) over christmas new-year break.

I kept getting errors from the compiler - like the ones reported in this thread..
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=57011

I did not find any comments about how it had could be resolved..

As far as I could see there was no way to convince the GCC C++ compiler that the string was initialised and hence legal to put in PROGMEM.

I did find (but will need to look for it again) some statements like I reported above, saying that issues in PROGMEM could relate to parsing the more complex C++ grammar.

I will post some sample code and and errors in a bit
Logged

Essex, UK
Offline Offline
Full Member
***
Karma: 4
Posts: 150
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ah yes, the "warning: only initialized variables can be placed into program memory area" warning. It's completely bogus and can be ignored - the compiler does the correct thing anyway. This one got on my nerves so much that I went into the gcc source and removed the warning message so I could use the -Werror and -Wall flags without this annoyance breaking the build.
Logged

Home of the Nokia QVGA TFT LCD hacks: http://andybrown.me.uk

UK
Offline Offline
Full Member
***
Karma: 2
Posts: 110
Kittens eat Arduinos
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Andy,

I went back and tried to replicate my problems from end of dec. What I found lines up with your statement that the warning does not mean anything.

I am cranky with myself because i spent more than 2 days looking at this warning, and reading messages on the web, but did not think to check the avr-size of the result.

It is still agravating. Do you know of a fix that might arrive in avr-c++ anytime soon?

I am going to delete my earlier comment - I see it coming up in Google now smiley-sad - and it is wrong.

Dave



Logged

Pages: [1]   Go Up
Jump to: