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

Hi,

I’m having trouble with PROGMEM and strcpy_P. ( It seems I’m not the only), I’ve checked the forum, and from what I can tell this code ought to work. It compiles ok, but churns out garbage when it attempts to print out the data I’ve copied from EEPROM into ‘normal’ memory.

What am I doing wrong?


Code:


#include <avr/pgmspace.h>  // Needed for PROGMEM stuff

void setup()
{
  Serial.begin(115200);//Communication speed for the display
  Serial.println("######################################################");
  Serial.println("Starting......");
  Serial.println("######################################################");
}

void loop()
{
  for (int x=300; x<302 ;x++)
  {
    dispCmsErrorMess(x);
    delay(100);
  }
}


// Given a +CMS error, find the appropriate error message (data taken from http://www.dreamfabric.com/sms/cms_error.html)
// returns 'true' only if a match for the error number is found
bool dispCmsErrorMess(int err_num)
{
  char errMessage[35];        // Array to hold the error message
  errMessage[0]=0;

  // Note 'PSTR' forces the enclosed string to be stored in program memory (PROGMEM)
  // rather than data memory

  prog_char ERR_300[] PROGMEM = "Phone failure";
  prog_char ERR_301[] PROGMEM = "SMS service of phone reserved";

  switch (err_num)
  {
    case 300:
      strcpy_P(errMessage,ERR_300);
      break;
    case 301:
      strcpy_P(errMessage,ERR_301);
      break;
  }
 
  // force a null terminator to stop the print spiraling out of control
  errMessage[35]=0;

  Serial.print("Err#=<");Serial.print(err_num);Serial.print("> Err mess=<");Serial.print(errMessage);Serial.println(">");
}
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 551
Posts: 46240
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
  char errMessage[35];        // Array to hold the error message
  errMessage[35]=0;
You are allocating space for 35 characters, and stuffing a NULL in the 36th spot in the array.

Do you see the same garbage if ERR_300 and ERR_301 are global variables?
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 551
Posts: 46240
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I actually copied your code, and tried it. My Arduino keeps resetting, and printing garbage. I move the for loop from the loop() function to setup(), and it still resets.

Then, I moved the ERR_300 and ERR_301 variables to global scope, and the Arduino sent valid data to the serial monitor, and stopped resetting.

Quote
######################################################
Starting......
######################################################
Err#=<300> Err mess=<Phone failure>
Err#=<301> Err mess=<SMS service of phone reserved>
Logged

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

Thanks for the solution Paul
Quote
I moved the ERR_300 and ERR_301 variables to global scope

That seems to have cured it. Any idea why?

The code snipet I posted is part of a larger function for handling any one of about 25 errors, I've noticed some threads for doing similar stuff involving using tables, but I'm not really sure if this would offer any advantage. Any suggestions on the best approach for this?

Regards
Logged

New Hampshire
Offline Offline
God Member
*****
Karma: 13
Posts: 779
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This is not documented anywhere that I've ever seen, and not well known either, but the PROGMEM attribute does not work properly with automatic local variables. Because these variables are automatically cleaned up when they go out of scope, that conflicts with the 'immutable' natural of PROGMEM variables in flash.

It may work by declaring them static, but I've never tried that.  It certainly works by keeping them global.
Logged


Ontario
Offline Offline
God Member
*****
Karma: 20
Posts: 835
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Automatic variable are in the stack and cannot be in PROGMEM.  You would have to declare them static.

For this sort of thing you are better to go directly to the AVR GCC information.  There is much more useful technical information on the AVR boards.  Have a look at this thread; this is quite a good writeup on PROGMEM: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=38003

Logged

Pages: [1]   Go Up
Jump to: