In spite of reading the previous contributions here, and the AVR
tutorial, I still have a problem to read a string in flash, using a
pointer in an array of structs, which is also in flash. The problam is
that the compiled program accesses the correct address, but in RAM. The
access to a function pointer is as expected.
I've been trying for a long time to fix this, but no success
The attached file is a complete source of an example.
The struct is:
typedef uint8_t (*PROCFNP)(char *);
typedef struct namefnpntr
{ PGM_P namestr;
PROCFNP procfnp;
} NAMEFNPNTR;
The strings are put in flash with:
const char PROGMEM pgmPGALM[] = "PGALM";
and a function dummy is:
uint8_t procPGALM(char *str)
{
return 0;
}
The initialisation is like:
const NAMEFNPNTR namefntab[] PROGMEM =
{ {pgmPGALM, procPGALM},
{ ... },
};
We process the string with:
int8_t procGPS(char *chrp, NAMEFNPNTR *namefnp)
{ uint8_t i;
/* pointer to current struct in name/func table */
void *pgmp;
PROCFNP procfnpntr;
/* search the table for the sentence name, note that the table is
in the program space
*/
for (i = 0; i < NAMEFNCNT; i++)
{ pgmp = (void *) pgm_read_word(&(namefnp[i].namestr[0]));
/* ***** Bug is in the above line **** */
if (strcmp_P(&chrp[1], pgmp) != 0) /* sentence name starts at 1
*/
{ pgmp = (void *) &namefnp[i].procfnp;
procfnpntr =
(PROCFNP) pgm_read_word(pgmp);
return procfnpntr(chrp); /* process the sentence */
}
} /* for table entry */
return 0;
}
The bug is in the marked pgm_read_word()
The compiler produces LDD instructions to access the pointer to the
string, not LPM. See the lss file produced by the compiler, a snippet
from the disassembler is:
68: { pgmp = (void *) pgm_read_word(&(namefnp[i].namestr[0]));
+0000008A: 81E8 LDD R30,Y+0 Load indirect with
displacement
+0000008B: 81F9 LDD R31,Y+1 Load indirect with
displacement
+0000008C: 9165 LPM R22,Z+ Load program memory
and postincrement
+0000008D: 9174 LPM R23,Z
This produces Z = 0x0000, not the contents of flash at the address
Thanks for reading this far,
Jerry
With
1 | (namefnp[i].namestr[0]) |
you access an element located in Ram, just as with any other variable reference. There's nothing in your argument to pgm_read_word() that indicates it is to be fetched from flash. Just as with any other element located in flash, you have to wrap your reference into a pgm_read_word() call:
1 | pgm_read_word(&(namefnp[i].namestr[0])) |
and make this expression the argument of your other program_read_word().
Hello mizch,
Thanks a lot, I wish I'd asked earlier! Now I understand that
pgm_read_word is the only thing which persuades it to read flash ROM
Best wishes, Jerry
Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
Log in with Google account
No account? Register here.