WinAVR Accessing string in flash using pointer in struct in flash

Guest #1472992
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
Attached files:
Guest
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().
Guest
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

Reply

A question of your own? This thread is over 16 years old. Ask it in a thread of its own – more people read along there, and it gets answered more often and sooner.

Start a new thread

A fix, an addition or feedback on this thread? Then reply here.

Formatting
  • [c]C-Code[/c]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]
  • [[Title]] – link to an article
  • Link to another post: right-click its post ID (#8078628), copy the address, paste it into the text

More about formatting

Post long source code as an attachment, not in the text.

Already registered? Log in

Not shown to anyone. We send you a link; your post appears once you confirm it there.

By submitting you create a free account and accept the terms of use.