EmbDev.net

Forum: µC & Digital Electronics WinAVR Accessing string in flash using pointer in struct in flash


von jerryr (Guest)


Attached files:

Rate this post
useful
not useful
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

von mizch (Guest)


Rate this post
useful
not useful
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().

von jerryr (Guest)


Rate this post
useful
not useful
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
No account? Register here.