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

von jerryr (Guest)

Attached files:

Rate this post
0 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;
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 
+0000008B:   81F9        LDD       R31,Y+1        Load indirect with 
+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,

von mizch (Guest)

Rate this post
0 useful
not useful
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:
and make this expression the argument of your other program_read_word().

von jerryr (Guest)

Rate this post
0 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


Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.

Rules — please read before posting

  • Post long source code as attachment, not in the text
  • Posting advertisements is forbidden.

Formatting options

  • [c]C code[/c]
  • [avrasm]AVR assembler code[/avrasm]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]

Bild automatisch verkleinern, falls nötig
Note: the original post is older than 6 months. Please don't ask any new questions in this thread, but start a new one.