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.