| Author |
Message |
|
|
Posted: Jul 07, 2007 - 01:15 AM |
|


Joined: Aug 29, 2006
Posts: 229
Location: Kingston, Jamaica
|
|
Yes arrays are passed by reference but you aren't passing an array, you are passing one elemental element of that array. If on the other hand you tried-
Code:
tempChar0 = pgm_read_byte(font[cTemp]);
you'd find it worked, since you are passing the 5 element array (it's still an element in the larger array but it is an array itself).
Of course you could only do that to get the first byte of each character so not that usefull..
Edward |
|
|
| |
|
|
|
|
|
Posted: Jul 09, 2007 - 10:12 AM |
|

Joined: Jul 06, 2007
Posts: 3
|
|
| Explaine pls. how can I access fields of structure located in program memory ? |
|
|
| |
|
|
|
|
|
Posted: Jul 09, 2007 - 01:55 PM |
|

Joined: Dec 08, 2004
Posts: 4502
Location: Nova Scotia, Canada
|
|
|
Code:
#include <avr/pgmspace.h>
struct MyStruct
{
char x;
char y;
int z;
};
struct MyStruct foo PROGMEM = {'a', 'b', 312};
int main(void)
{
int MyInt = pgm_read_word(&foo.z);
}
|
|
|
| |
|
|
|
|
|
Posted: Jul 09, 2007 - 02:54 PM |
|

Joined: Jul 06, 2007
Posts: 3
|
|
|
Code:
#include <avr/pgmspace.h>
struct MyStruct
{
char x;
char y;
int z;
void (*Procedure)();
};
struct MyStruct foo PROGMEM =
{'a', 'b', 312, Read_Procedure};
int main(void)
{
int MyInt = pgm_read_word(&foo.z);
}
If structure is located in RAM I can call read procedure:
Code:
int main(void)
{
int MyInt = pgm_read_word(&foo.z);
foo.Read_Procedure();
}
Tell me please how can I call read procedure if I locate structure in program memory ? |
|
|
| |
|
|
|
|
|
Posted: Jul 09, 2007 - 03:37 PM |
|

Joined: Dec 08, 2004
Posts: 4502
Location: Nova Scotia, Canada
|
|
Note that this is off the top of my head so there may be some inconsistent syntax; I have done things similar to this before, but I don't have the source code in front of me as I write this.
Code:
typedef void (*function_pointer)();
int main(void)
{
function_pointer Proc = (function_pointer)pgm_read_word(&foo.Procedure);
Proc();
}
- Luke |
|
|
| |
|
|
|
|
|
Posted: Jul 31, 2007 - 11:26 PM |
|

Joined: Dec 02, 2004
Posts: 284
Location: San Diego, CA
|
|
Dean, I just wanted to say thanks for writing this tutorial... It just helped me out a lot!!!!
- James |
|
|
| |
|
|
|
|
|
Posted: Aug 16, 2007 - 03:05 AM |
|


Joined: Aug 10, 2007
Posts: 35
Location: Brisbane, Australia
|
|
Hi, Dean, Thanks for the tute.
You say, in two places:
Quote:
pgm_read_byte. This macro takes a PROGMEM pointer as its argument, and returns the string located at that pointer value.
It should say something like:
Quote:
pgm_read_byte. This macro takes a PROGMEM pointer as its argument, and returns one byte located at that pointer value.
Also maybe add pgm_read_dword() beside pgm_read_word(), something like. "Similarly, for 4-byte values, we can use prgm_read_dword()."
-- Alf |
|
|
| |
|
|
|
|
|
Posted: Aug 16, 2007 - 05:03 AM |
|


Joined: Jan 23, 2004
Posts: 7028
Location: Melbourne, Victoria, Australia
|
|
Thanks Alf, I fixed up the one incorrect reference to strings I could find, and added in a footnote about looking at the other avaliable functions. I didn't want to derail the paragraph about pgm_read_word with information about pgm_read_dword as the former was discussing reading out pointers from program space (hard enough as it is) so I went for the footnote.
Cheers!
- Dean  |
_________________
|
| |
|
|
|
|
|
Posted: Oct 07, 2007 - 05:59 PM |
|

Joined: Jun 04, 2007
Posts: 1075
Location: Cincinnati, Ohio - USA
|
|
Hi Dean,
Is there any reason that this correction was never made to the tutorial:
Quote:
void USART_TxString_P(const char *data)
{
while (pgm_read_byte(*data) != 0x00)
USART_Tx(pgm_read_byte(*data++));
}
The body of the function should read:
Code:
while (pgm_read_byte(data) != 0x00)
USART_Tx(pgm_read_byte(data++));
Very nice tutorial overall though!
Thanks |
|
|
| |
|
|
|
|
|
Posted: Oct 07, 2007 - 11:52 PM |
|


Joined: Jan 23, 2004
Posts: 7028
Location: Melbourne, Victoria, Australia
|
|
|
Quote:
Is there any reason that this correction was never made to the tutorial:
Yes, an extreamly good one - I forgot! It's now fixed, thanks!
- Dean  |
_________________
|
| |
|
|
|
|
|
Posted: Oct 09, 2007 - 04:04 AM |
|

Joined: Jun 04, 2007
Posts: 1075
Location: Cincinnati, Ohio - USA
|
|
Thanks Dean,
I was working on the IAR to GCC Converter when I found your tutorial which has been a lot of help. I'm nearly finished with the flash part, then I just need to tackle the EEPROM stuff.  |
|
|
| |
|
|
|
|
|
Posted: Oct 23, 2007 - 01:52 AM |
|

Joined: Jun 19, 2002
Posts: 92
Location: SF Bay area
|
|
First, thanks for the tutorial. It was helpful in understanding how things are supposed to be done.
Second... YUCK! Trying to define any data structure more complicated than a string or an array of simple data types reminds me of Fortran programs trying to implement 'data structures' with shared common areas and such. Does C++ permit operator overloading enough (ie including pointer dereference/etc) that one could use some C++ magic code to make the use of PROGMEM space invisible to the users?
I've got problems similar to everyone else; menus:
Code:
typedef const struct menu_item_ {
unsigned char menu_key;
menu_action_t menu_action; /* function or menu pointer */
} menu_item_t;
const menu_item_t foo[] PROGMEM = {
{'A', nextmenuA},
{'B', nextmenuB},
{0, "menu help string"}
};
And then code, for example, to draw a prompt (on a non-progmem implementation) that looks like:
Code:
menu_item_t *menu, *lastitem;
drawmenu:
lastitem = menu;
while ((lastitem->menu_key & 0x7F) != 0)
lastitem++; /* Find menu terminator to get type of draw */
if (lastitem->menu_action != 0) {
char *p = (char *) lastitem->menu_action;
while (*p)
printf("%c", *p++);
} else {
while (menu->menu_key != 0) {
printf("%c, ", menu->menu_key & 0x7F);
menu++;
}
}
printf("\r\n");
return; /* Done! */
and the code is looking really ugly as I try to insert pgm_read calls in the appropriate places... |
|
|
| |
|
|
|
|
|
Posted: Dec 14, 2007 - 10:25 AM |
|

Joined: Jun 19, 2002
Posts: 92
Location: SF Bay area
|
|
So how come the definition of PSTR defines the string as
Code:
((const PROGMEM char *)(s))
instead of using the typedefs for prog_char:
Code:
((const prog_char *)(s))
It seems like the latter would allow C++ code to run different methods for progmem strings rather than ram strings (which would be a good thing.) |
|
|
| |
|
|
|
|
|
Posted: Dec 20, 2007 - 11:27 PM |
|

Joined: Jun 10, 2007
Posts: 62
Location: Romania, Oradea
|
|
| Thanks Dean! Your tutorials helped me a lot. |
|
|
| |
|
|
|
|
|
Posted: Jul 17, 2008 - 04:20 PM |
|

Joined: Apr 16, 2008
Posts: 43
|
|
Many thanks for this great tutorial, that helped me to optimize my code and understand better how to use flash to store data. I have one question though: is there a size limit in using flash to store static data ?
While I was switching/improving my strings to flash, it then suddenly did strange things (printing a long list of unreadable cars, as if the string wasn't terminated properly...). I had to go back to RAM for some parts of code.
Is there something I'm not considering ? Maybe a mistake somewhere else, but I don't see it right now.
I'm using an atmega128, and the summary is:
Program: 23934 bytes (18.3% Full)
(.text + .data + .bootloader)
Data: 642 bytes (15.7% Full)
(.data + .bss + .noinit)
Once more, thanks to avrfreaks folks !
Vincent. |
|
|
| |
|
|
|
|
|
Posted: Jul 17, 2008 - 04:30 PM |
|


Joined: Jan 23, 2004
Posts: 7028
Location: Melbourne, Victoria, Australia
|
|
There are two limits:
1) The hard limit of the amount of FLASH memory in the AVR - this is a physical limit
2) The 64KB limit due to GCC using 16-bit pointers - this can be worked around using special "far pointer" functions and macros
Your code is only 23KB long, so you're hitting neither. Does your code have any large RAM arrays which might be stepping on the stack or string if you're copying it into RAM before use?
- Dean  |
_________________
|
| |
|
|
|
|
|
Posted: Jul 17, 2008 - 05:15 PM |
|

Joined: Apr 16, 2008
Posts: 43
|
|
Well, I don't copy anything myself to RAM. I just use large structure to store all states/transitions of the state machine driving the AVR. Something to do with mapping and 64k limit ? On the 64K limit, could you explain further the far pointer trick (is it in a tutorial I would have missed ?) ?
Thanks.
Vincent. |
|
|
| |
|
|
|
|
|
Posted: Jul 17, 2008 - 06:03 PM |
|


Joined: Jan 23, 2004
Posts: 7028
Location: Melbourne, Victoria, Australia
|
|
The avr-libc pgmspace.h module contains "far" versions of the existing methods - "pgm_read_byte_far()", for example. To use them on a string located over the 64KB barrier, you'd just OR the string's address (typecast as a long) with 0x10000 to create a psudo-pointer.
Code:
char StringLocatedOver64KB[] = "Test";
int main (void)
{
char a = pgm_read_byte_far(0x10000 | (uint16_t)&StringLocatedOver64KB);
}
You'd need to write your own "far" versions of the other library routines which deal with FLASH memory, such as memcmp_P(), using the far accessor routines.
Alternatively, use Carlos' macro to get the far address of a variable in FLASH space instead:
Code:
#define GET_FAR_ADDRESS(var) \
({ \
uint_farptr_t tmp; \
\
__asm__ __volatile__( \
\
"ldi %A0, lo8(%1)" "\n\t" \
"ldi %B0, hi8(%1)" "\n\t" \
"ldi %C0, hh8(%1)" "\n\t" \
"clr %D0" "\n\t" \
: \
"=d" (tmp) \
: \
"p" (&(var)) \
); \
tmp; \
})
int main (void)
{
char a = pgm_read_byte_far(GET_FAR_ADDRESS(StringLocatedOver64KB);
}
Which has the distinct advantage that it returns the correct address (albeit a long address) for any FLASH data whether it is over the 64KB boundary or not -- coupled with the far accessor routines and you have bulletproof code.
- Dean  |
_________________
|
| |
|
|
|
|
|
Posted: Jul 30, 2008 - 05:06 PM |
|

Joined: Jul 10, 2008
Posts: 150
Location: Ruhrpott, Germany
|
|
Nice tutorial, but I'm still totally screwed.
I read also the avr-libc FAQ http://www.nongnu.org/avr-libc/user-man ... _rom_array but I'm still not getting how to make an array of structs into flash.
I want to have a struct of strings for a menu.
like
struct {
char z[2][20]
} mystruct
And I want to make an array of this structs for different languages.
mystruct myarray[n_languages]
So that i can access the strings by something like
this example:
array[French].z[0]
or
array[French].z[1]
And now I want to have my 2.5k of strings in flash using Progmem
How to do that? |
_________________ http://xkcd.com/221/
|
| |
|
|
|
|
|
Posted: Jul 30, 2008 - 05:28 PM |
|


Joined: Jan 23, 2004
Posts: 7028
Location: Melbourne, Victoria, Australia
|
|
Easy, just add the PROGMEM attribute to the structure itself:
Code:
struct {
char z[2][20]
} mystruct PROGMEM;
If you want an array of structures, use the PROGMEM on the array instead.
To access the structure elements you can either read out the structs from FLASH into a RAM structure using pgm_read_block (and then use the RAM strucuture as you would normally), or use the pgm_read_* macros on the structure elements individually as you use them.
- Dean  |
_________________
|
| |
|
|
|
|
|