PROGMEM Issue I read all other PROGMEM posts

Hi,,

I read all other progmem related topics but none of these works for me

I have a pretty big program which should still be uploaded to a mega and in the future to the due. so i hope to have only one source instead of two.
Because my complete menu which is a static list and never change without a new upload i created the menu structure in progmem which i filter out with sscanf_p

here 10 of the 1000 lines

prog_char MenuNL_0[] PROGMEM = "0	1	H	Menu	Hoofdmenu	0	0	0	0	0";
prog_char MenuEN_0[] PROGMEM = "0	1	H	Menu	Hoofdmenu	0	0	0	0	0	";
prog_char MenuNL_1[] PROGMEM = "1	1	S	Instellingen	SubMenu	0	0	0	0	1";
prog_char MenuEN_1[] PROGMEM = "1	1	S	Settings	SubMenu	0	0	0	0	1	";
prog_char MenuNL_2[] PROGMEM = "2	1	B	Status	SubMenu	0	0	0	0	2";
prog_char MenuEN_2[] PROGMEM = "2	1	B	Status	SubMenu	0	0	0	0	2	";
prog_char MenuNL_3[] PROGMEM = "3	1	S	Acties	SubMenu	0	0	0	0	3";
prog_char MenuEN_3[] PROGMEM = "3	1	S	Actions	SubMenu	0	0	0	0	3	";
prog_char MenuNL_4[] PROGMEM = "4	1	S	Logs	SubMenu	0	0	0	0	4";
prog_char MenuEN_4[] PROGMEM = "4	1	S	Logs	SubMenu	0	0	0	0	4	";

I still don't know if these are translated properly but i know the next lines won't work

i also use a lot of

n=sprintf_P(Tekst, PSTR("SD Card Initialized"));
myGLCD.print(Tekst, CENTER, 32);
Log(Tekst,2,6);

so i added the following code as described in the other progmem topics but still the same error

#if defined(__SAM3X8E__)
    #define PROGMEM
    #define pgm_read_byte(x)        (*((char *)x))
//  #define pgm_read_word(x)        (*((short *)(x & 0xfffffffe)))
    #define pgm_read_word(x)        ( ((*((unsigned char *)x + 1)) << 8) + (*((unsigned char *)x)))
    #define pgm_read_byte_near(x)   (*((char *)x))
    #define pgm_read_byte_far(x)    (*((char *)x))
//  #define pgm_read_word_near(x)   (*((short *)(x & 0xfffffffe))
//  #define pgm_read_word_far(x)    (*((short *)(x & 0xfffffffe)))
    #define pgm_read_word_near(x)   ( ((*((unsigned char *)x + 1)) << 8) + (*((unsigned char *)x)))
    #define pgm_read_word_far(x)    ( ((*((unsigned char *)x + 1)) << 8) + (*((unsigned char *)x))))
    #define PSTR(x)  x
  #if defined F
    #undef F
  #endif
  #define F(X) (X)
#endif
1_Setup:49: error: expected primary-expression before ')' token        
1_Setup:54: error: expected primary-expression before ')' token
1_Setup:59: error: expected primary-expression before ')' token
1_Setup:64: error: expected primary-expression before ')' token
1_Setup:69: error: expected primary-expression before ')' token

All of the mentioned lines start with n=sprintf_P(Tekst, PSTR("

so how do i change it during the compilation without rewriting every line

Kind regards

Johan

Due doesn't have PROGMEM. You can't read flash memory at all, you can only execute
it as code, this is a basic security measure on the chip. From outside the chip you can't
read the flash either, you can only erase it totally then write it I believe.

MarkT:
You can't read flash memory at all, you can only execute
it as code, this is a basic security measure on the chip.

Are you sure about that?

MarkT:
Due doesn't have PROGMEM.

And because of that, the thread owner is using all those preprocessor macros, to make PROGMEM and the corresponding functions disappear!
And of course, you can read flash memory! You can store constant data there! In the AVR world it is tricky, so PROGMEM was introduced. In the ARM world, such tricks are not needed.

The poster tries now to write compatible code, which can be translated for the AVR world and the DUE, so he needs those macros!

However the thread owner needs to post more of his code, as it looks like just as an preprocessor issue.
When he writes:

All of the mentioned lines start with n=sprintf_P(Tekst, PSTR("

he has cutted of the more important piece with the closing bracket, which is mentioned in the error message.

Gogol i right thats what i need.

but I did post one of the lines which has the error completely

n=sprintf_P(Tekst, PSTR("SD Card Initialized"));
myGLCD.print(Tekst, CENTER, 32);
Log(Tekst,2,6);

some others

Log(Tekst,2,6);sprintf(Tekst, (PGM_P) pgm_read_word(&Teksten[1][Taal]));
 myGLCD.print(Tekst, 5, 150);

 n=sprintf_P(Tekst, PSTR("Spoelen Tijden[0] = %lu Spoeltijden[%lu-1] = %lu"),Spoeltijden[0],AantalSpoelBeurten,Spoeltijden[AantalSpoelBeurten-1]);
  Log(Tekst,1,1);
  n=sprintf_P(Tekst, PSTR("AantalMinutenSpoelBeurten*60 = %lu * 60 = %lu"),AantalMinutenSpoelBeurten,AantalMinutenSpoelBeurten*60);
  Log(Tekst,1,1);

everything i send to the serial port, log to a file or show on the tft screen is now declared as progmem.

or with the PSTR or with the prog_char command

And because i also want to use this code to upload to a mega i don't want to delete all progmem defenitions from my code.because then i need to write every change , fix or new feature twice.

I understand that if i delete everything and declare it as a normal constants it works but then i cannot upload it to a mega anymore.

if you need more or something else just say it and i will send it.

Johan

Just spotted this:

    #define pgm_read_word_near(x)   ( ((*((unsigned char *)x + 1)) << 8) + (*((unsigned char *)x)))
    #define pgm_read_word_far(x)    ( ((*((unsigned char *)x + 1)) << 8) + (*((unsigned char *)x))))

One of these must obviously be wrong!

as far as i know the compiler already change these lines if you compile for a due.
But the PSTR things are the biggest issue .
whatever i try it keep failing on that one

here a simple complete program which runs on the mega but even i added all the #define lines not on the DUE

char Tekst[100];
int n;
int Taal=0;
char Omschrijving[150];


#if defined(__SAM3X8E__)
    #define PROGMEM
    #define pgm_read_byte(x)        (*((char *)x))
//  #define pgm_read_word(x)        (*((short *)(x & 0xfffffffe)))
    #define pgm_read_word(x)        ( ((*((unsigned char *)x + 1)) << 8) + (*((unsigned char *)x)))
    #define pgm_read_byte_near(x)   (*((char *)x))
    #define pgm_read_byte_far(x)    (*((char *)x))
//  #define pgm_read_word_near(x)   (*((short *)(x & 0xfffffffe))
//  #define pgm_read_word_far(x)    (*((short *)(x & 0xfffffffe)))
    #define pgm_read_word_near(x)   ( ((*((unsigned char *)x + 1)) << 8) + (*((unsigned char *)x)))
    #define pgm_read_word_far(x)    ( ((*((unsigned char *)x + 1)) << 8) + (*((unsigned char *)x))))
    #define PSTR(x)  x
    #define _P
    
  #if defined F
    #undef F
  #endif
  #define F(X) (X)
#endif

prog_char MenuNL_0[] PROGMEM = "0	1	H	Menu	Hoofdmenu	0	0	0	0	0";
prog_char MenuEN_0[] PROGMEM = "0	1	H	Menu	Hoofdmenu	0	0	0	0	0	";

PGM_P Menu[][2] PROGMEM =
{
  MenuNL_0, MenuEN_0};
  
  
void setup() {
  Serial.begin(115200);
 n=sprintf_P(Tekst, PSTR("Version 1.1"));
 Serial.println(Tekst);
 sprintf_P(Tekst, (PGM_P) pgm_read_word(&Menu[0][Taal]));
 Serial.println(Tekst);
 
 sscanf_P(Tekst,PSTR("%*u\t%*d\t%*c\t%*15[a-zA-Z0-9().;,:><= ]\t%90[a-zA-Z0-9().;,:><= ]\t%*u\t%*u\t%*u\t%*u\t%*u"),Omschrijving);
 Serial.println(Omschrijving);


}
void loop() {
  // put your main code here, to run repeatedly:

}

Thanks for the simplified example code, it really does make debugging these problems much easier.

Firstly the PROGMEM compatibility code is already in avr/pgmspace.h which is automatically included, so you don't need most of the big #if block. The problem is that there are two bugs in pgmspace.h:

  1. sprintf_P only works if there are 3 or more arguments. There's not much point using sprintf with only 2 arguments (strcpy is better), however I think for consistency it should work.

  2. sscanf_P isn't there at all!

To work around this, change the #if block to just contain the following:

#if defined(__SAM3X8E__)
  #define sprintf_P sprintf
  #define sscanf_P sscanf
#endif

Hello Stimmer,

thanks for that information. Comparing pgmspace.h with the defines posted above, I see only one more difference:
#define F(X) (X) should also be included.

I think, that this should be included in pgmspace.h.

I see no advantage of the current define:
#define sprintf_P(s, f, ...) sprintf((s), (f), VA_ARGS)
compared to your pragmatic
#define sprintf_P sprintf

or does the pragmatic way break some other stuff?

I added them,
compiling runs without errors
But when i run the program on the due (test code) i only receive one line of text in my output instead of three
The first is perfect but something is still missing in de defines (i think) for the other lines

Kind regards

Johan

You are using pgm_read_word to read an address, but pgm_read_word is only 16-bits. That might work on a Mega (and even then only for 'near' addresses) but it won't work on a Due, which uses 32 bit addresses.

stimmer,

I understand that part but is there any way to convert the during compile time. because i have a lot of these

Kind regards

Johan

Ah, I am wrong :frowning: (but right in some weaker sense).

The chip does support this security model where the flash cannot be read, but there
is a control bit that enables it - section 9.1.3.5 "Security bit feature" - I clearly rememberd
the description of the mechanism but not that it was optional.

MarkT:
Ah, I am wrong :frowning: (but right in some weaker sense).
The chip does support this security model where the flash cannot be read, but there
is a control bit that enables it - section 9.1.3.5 "Security bit feature" - I clearly rememberd
the description of the mechanism but not that it was optional.

I think, that you are still wrong with that. This is a mechanism to protect your code from being read out by external programmers, JTAG devices etc., but not from preventing you, to initialize variables in the flash. The ARM architecture is here little bit different from the AVR architecture.