array of pointers to strings in flash- how to code?

Go To Last Post
28 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How do I code an array containing pointers to strings in flash? Something like:

PGM_P alpha[] =
{
PSTR("line 1"),
PSTR("line 2"),
0
};

Which isn't correct, but gives the idea. PGM_P probably isn't correct. The PSTR macro refuses to be used inside an initializer. I'm all hosed up.

The last element of the array is intended to be a zero/NULL signifying end-of-list.

And with a corrected version of the above, what do I declare for a pointer that takes values from this array?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The documentation is your friend

http://www.nongnu.org/avr-libc/u...

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

glitch wrote:
The documentation is your friend

http://www.nongnu.org/avr-libc/u...

Actually - I've read all that and much more.

The examples like:

char string_1[] PROGMEM = "String 1";
char string_2[] PROGMEM = "String 2";
char string_3[] PROGMEM = "String 3";
char string_4[] PROGMEM = "String 4";
char string_5[] PROGMEM = "String 5";

Yield independent strings in flash that are not an array. A separate table can list these named strings, but that's a code maintenance challenge.

I think the answer is that GCC/WinAVR's macros for program memory do not have a way to create arrays of pointers to anonymously located strings in flash. For non-Harvard architectures, with constants in RAM initialized from flash at startup, it can. But the goal is to conserve RAM.

Right?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

stevech wrote:
I think the answer is that GCC/WinAVR's macros for program memory do not have a way to create arrays of pointers to anonymously located strings in flash.
That's my understanding, Steve. One first has to store the string in flash and then store the pointers to those strings in flash. A bit of maintainence and the reward is a significant savings of precious SRAM.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

untested, but you might try:

const PROGMEM char *alpha[] PROGMEM =
{
((const PROGMEM char *)("line 1")),
((const PROGMEM char *)("line 2")),
NULL
};

barring that a 2 dim array of char would work, though not exactly the same way. The downside is that you would waste a lot of space if the strings are not of equal, or close, size.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I haven't actually checked but isn't this covered in Dean's PROGMEM tutorial?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I had to resort to assembler to enable me to use 7 or 8 different languages without having to waste memory because of unequal length strings. I don't think C can do this efficiently, although I'd be happy to be proved wrong.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's not a "C" problem, as "C" does this fine in RAM... it's a problem with GCC and the extensions that have been added to support the Harvard architecture of the AVR.

For multi-language support (and other applications like this) I usually do this with a resource file, and a small program I wrote that converts the resource file into a source file. (I could have had it compile into an object file, but I wanted something more generic, that I could easily adapt to other compilers). Doing it this way, I don't have to worry about the physical construct in source, and maintenance is much easier too.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

glitch wrote:
It's not a "C" problem, as "C" does this fine in RAM... it's a problem with GCC and the extensions that have been added to support the Harvard architecture of the AVR.

For multi-language support (and other applications like this) I usually do this with a resource file, and a small program I wrote that converts the resource file into a source file. (I could have had it compile into an object file, but I wanted something more generic, that I could easily adapt to other compilers). Doing it this way, I don't have to worry about the physical construct in source, and maintenance is much easier too.


Sorry, I should have been more specific.
When you say "C does this fine in RAM", could you go as far as to say "C does this fine in linear address space"?

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have a look here
https://www.avrfreaks.net/index.p...

And maybe you'll end up here
https://www.avrfreaks.net/index.p...

/Bingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here's a decent method for lots of strings in flash. It avoids having to name/label each string and avoids making a table of pointers, each being the named string. It's not as clean as in RAM, but, much easier to revise when there are many strings in several collections.

// One string, below, has three substrings, each ending with a null byte. 

// The WinAVR compiler concatenates these constants.
const char strings1[] PROGMEM =
"I am line 1\n\r\0"
"I am line 2 with the following word quoted: \"me\"\n\r\0"
"I am the last line\0"
"\0"; // end of substrings

// and in the code (note: add casts to stop compiler warnings)
char strBuffer[100];
char *p;

p = strings1; // flash data
do {   // print all substrings
    strcpy_P(strBuffer, p); // copy substring to RAM
    // do things with the chosen string, such as...    
    puts(strBuffer);
    p += (strlen(strBuffer) + 1); // skip to next substring
} while (*p != '\0')  // empty substring?

Possible flaw: The pointer to flash is a 16 bit variable. So this can address only the first 64KB of flash, as a byte pointer. Maybe there is a far pointer I should use, and a far version of strcpy_P. I've never fiddled with far pointers in flash with WinAVR.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sure that works if you only need linear access to your strings.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Possible flaw: The pointer to flash is a 16 bit variable.
the progmem section in the linker scripts is placed right after the vector table, so unless you have >64k of strings, I think you are safe. I think.

I have a variation of previous code-

//string array
const prog_char strings1[] =
    "I am line 1"             "\n\r\0"
    "I am line 2"             "\n\r\0"
    "I am the last line"      "\0"
    "\0"; // end of substrings

//function
const prog_char* find_string(const prog_char* array,uint8_t line){
    while(line--){ 
        while(pgm_read_byte(array++)!=0); 
        if(pgm_read_byte(array)==0){ //if end
            return 0; //bad line number passed
        }
    }
    return array;
}

//my test routine
const char* test;
test=find_string(strings1,1);
//test=&strings1[1]
//I don't have anything better, so I just
//feed it right back to the function
if(test) test=find_string(test,1);
//test=&strings1[2]

but it sure is a time killer looking for those lines.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But isn't this exactly what Steve was after - a way to make a flash based table of pointers to flash based variable strings? Because the pointers make indexing the data easy (in fact the pointers ARE the index) ? IOW he wants to index the strings at COMPILE time, not at run time.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
But isn't this exactly what Steve was after - a way to make a flash based table of pointers to flash based variable strings? Because the pointers make indexing the data easy (in fact the pointers ARE the index) ? IOW he wants to index the strings at COMPILE time, not at run time.

Cliff

Well apparently it was, or at least it was a solution that works for him, as he proposed it. I too was under the impression that he wanted an array of pointers to strings, so that he could have random access to those strings.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This strikes me as one of those cases where we should simply admit that gcc is has it's feeble corners and look for another solution. Seems to me that in this case the maintenance of a .S file is no worse than a .c file, with no contortions required.

   .section .text
s0:
   .ascii "Hello\12\0"
s1:
   .ascii "World\12\0"
s2:
   .ascii "Third string.\12\0"
.global themessages
themessages:
   .word s0
   .word s1
   .word s2
   .end

What's wrong with this picture?

If it was me, I'd probably write a simple tool to take a file of strings and turn it into the above .S file. Which is probably a bad idea on balance, since requiring weirdo one-off tools for a build usually ends up being problematic down the road. But writing little tools like that is a particular sickness of mine.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dbc wrote:
This strikes me as one of those cases where we should simply admit that gcc is has it's feeble corners and look for another solution. Seems to me that in this case the maintenance of a .S file is no worse than a .c file, with no contortions required.

   .section .text
s0:
   .ascii "Hello\12\0"
s1:
   .ascii "World\12\0"
s2:
   .ascii "Third string.\12\0"
.global themessages
themessages:
   .word s0
   .word s1
   .word s2
   .end

What's wrong with this picture?

If it was me, I'd probably write a simple tool to take a file of strings and turn it into the above .S file. Which is probably a bad idea on balance, since requiring weirdo one-off tools for a build usually ends up being problematic down the road. But writing little tools like that is a particular sickness of mine.

They are called generator programs, and are typical of larger and/or complex projects. In my case I usually decide to generate C code, but certainly generating assembly code can work just as well.

Though, in this case, the assembly code you posted, is no different than the working C model. (which was rejected by the OP as being too complicated for maintenance)

char s0[] PROGMEM = "Hello\12\0";
char s1[] PROGMEM = "World\12\0";
char s2[] PROGMEM = "Third string.\12\0";

PGM_P themessages[] PROGMEM = 
{
    s1,
    s2,
    s3
};

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

glitch wrote:
clawson wrote:
But isn't this exactly what Steve was after - a way to make a flash based table of pointers to flash based variable strings? Because the pointers make indexing the data easy (in fact the pointers ARE the index) ? IOW he wants to index the strings at COMPILE time, not at run time.

Cliff

Well apparently it was, or at least it was a solution that works for him, as he proposed it. I too was under the impression that he wanted an array of pointers to strings, so that he could have random access to those strings.

No - random access not needed. Access sequentially.

I found no way to index the strings at compile time other than manually naming every single-wingle string and manually placing those names in an array. Too impractical at scale.

Does Codevision have a way to produce string arrays in flash, as easily as GCC (et al) can do in RAM? Maybe, since unlike GCC, the AVR/Harvard-architecture-specific compilers should do this well and easily, else why would one buy them?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:
Quote:
Possible flaw: The pointer to flash is a 16 bit variable.
the progmem section in the linker scripts is placed right after the vector table, so unless you have >64k of strings, I think you are safe. I think.

thanks. that makes it easy. GULP! This linker convention is never going to change, right??? Is there a "far" byte pointer to flash in WinAVR's macros? 17 bits or more.

and thanks for the improved variation.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No, AFICK WinAVR doesn't have any far byte pointer. The only C AVR compiler that I know of that supports applications with mixed memory models (8, 16, and 24 bit) is IAR.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kmr wrote:
No, AFICK WinAVR doesn't have any far byte pointer. The only C AVR compiler that I know of that supports applications with mixed memory models (8, 16, and 24 bit) is IAR.

I was just reading Codevision's manual. It supports a "LARGE" memory model where flash pointers are 32 bits, for the AVRs with > 128KB of flash. I presume that a pointer to constants can be declared, as well as a pointer to a function(). Other CV memory models go down all the way to TINY, with 8 bit pointers. I used that mode once to cram a lot into a 90S2313. I confess, though, that I've not purchased CV, just used the demo version. It is, er, somewhat less expensive than IAR.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avr-libc includes some pgm_read_XXX_far() functions with which it is possible to use a 32-bit integer as a pseudo-pointer. However, the regular address operator (&) doesn't work in that case - in order to obtain a 32-bit address of any variable you need to use a special inline assembly macro (which is not currently a part of avr-libc, but which has been posted on this forum several times).

In any event, I don't imagine it would be practical (probably not even possible, in its current form) to use it for building tables of compile-time constant pointers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
What's wrong with this picture?
besides being the same as the C method as glitch says, you also would need an '.align 2' added in there unless you want to count on the fact that you have a 50% chance of not needing it.
Quote:
This linker convention is never going to change, right???
Its put where it is for a very good reason, so unless the ld script writers start losing their minds, I think your safe. But in the end, the script that's on your pc is the one that gets used at compile time, and there's no one that can stop you from changing that script to way you want it.

Probably the easiest way to do what you want, is to write a little pc app in your favorite language that creates the C string arrays and tables for you.

(I just wrote a little Rebol script to do it if anyone is interested- http://www.mtcnet.net/~henryvm/g... it seems to work, but has not been thoroughly tested)

if you previously downloaded it, get it again as I had an error in using the delimiter (was not being used)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kmr wrote:
No, AFICK WinAVR doesn't have any far byte pointer. The only C AVR compiler that I know of that supports applications with mixed memory models (8, 16, and 24 bit) is IAR.

How does one use WinAVR for a mega256?

Codevision shows memory models for TINY (8 bit pointers) up to LARGE 32 bit pointers to flash for >128MB avrs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

stevech wrote:
How does one use WinAVR for a mega256?
lfmorrison explained (a few posts up) the macro to create a pseudo-pointer for accessing flash data above 64KB.
Quote:
Codevision shows memory models for TINY (8 bit pointers) up to LARGE 32 bit pointers to flash for >128MB avrs.
Thanks for the info, that's good to know. Are pointer sizes constant across an application or does it do like IAR and allow mixed memory models with variable size pointers within an application? BTW, IAR only goes up to 24-bit pointers (not 32-bit like CodeVision) since that is sufficient for all AVRs. (well, there are two 24-bit pointer models in IAR -- one for when you know that an object is less than 64KB in size and the other allowing for objects greater than 16-bits in size).
Quote:
LARGE 32 bit pointers to flash for >128MB avrs
Don't you mean kilobytes?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Quote:
LARGE 32 bit pointers to flash for >128MB avrs
Don't you mean kilobytes?

Haven't you seen the new press releases?

:lol:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

stevech wrote:
Haven't you seen the new press releases?
Sure seems likely to be the case at some point with all the multigigabit flash modules around.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well maybe not flash, but possibly RAM (SDRAM) ;-)

(T-7 days!)