Problem with pgm_get_far_address macro. Please, help...

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

Dears,

I defined some big arrays in the program space as follows:

 

const uint16_t Picture[] PROGMEM = {....}

 

As they crossed the 64kb limit, I had to use macro pgm_get_far_address to get the far data address and used it as follows:

 

pixelData = pgm_read_word_far(pgm_get_far_address(Picture++));

 

where the pixelData is 16-bit data to read.

 

Unfortunately I got the error: 

lvalue required as unary '&' operand

pixelData = pgm_read_word_far(pgm_get_far_address(Picture++));
                                ^

Where is the problem? I cannot understand. Please, give me a tip. Best regards... Robert

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

robiw wrote:
Where is the problem?
Picture++ doesn't make sense even without all the Flash stuff.

 

uint32_t pixelAddress = pgm_get_far_address(Picture);

pixelData = pgm_read_word_far(pixelAddress++);

 

Stefan Ernst

Last Edited: Tue. Mar 7, 2017 - 12:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:
Picture++ doesn't make sense even without all the Flash stuff.

Why? It is the argument of the function showPicture(const uint16_t *Picture), where the Picture is the array consisted picture's data (each pixel is represented by 16-bits). It works fine, when data doesn't cross the 64kb limit (for pgm_ functions without the far suffix)...Robert

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

robiw wrote:
Why? It is the argument of the function showPicture(const uint16_t *Picture)
And how should I know that? In the context you have given in #1 it is a global variable.

 

Make the argument an uint32_t and use pgm_get_far_address(Picture) within the function call.

Stefan Ernst

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

What is more, your code:

 

uint32_t pixelAddress = pgm_get_far_address(Picture);

 

gave following, additional error (strange): error: invalid 'asm': invalid expression as operand

 

I don't know what is going on :-(...R

 

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

robiw wrote:
What is more, your code: uint32_t pixelAddress = pgm_get_far_address(Picture); gave following, additional error (strange): error: invalid 'asm': invalid expression as operand
Yes, if using it with Picture the function argument. Not if you use it with Picture the global variable.

Stefan Ernst

Last Edited: Tue. Mar 7, 2017 - 12:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:
Make the argument an uint32_t and use pgm_get_far_address(Picture) within the function call.

 

But the array consists of 16-bit elements, so the argument is const uint16_t *Picture and seems to be good. What should I change it to? R

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

 

robiw wrote:
But the array consists of 16-bit elements
I don't mean changing from uint16_t* to uint32_t*. I mean literally uint32_t.

 

robiw wrote:
What should I change it to?
showPicture(uint32_t PictureAdr)

 

Stefan Ernst

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

Once again...

I have the array in the flash as follows:  const uint16_t Picture[] PROGMEM = {...}

 

Now, I have the function, which argument is the pointer to the picture: showPicture(const uint16_t *Picture)

 

Then, you suggest to change the argument od the function as follows: showPicture(uint32_t Picture)??? What next? R

 

 

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

What about the use of the new function showPicture(uint32_t Picture)?

 

Now should I use it as follows: showPicture(Picture)? But the declared argument is 32-bit wide whilst the picture is the 16-bit wide pointer to the array  const uint16_t Picture[] PROGMEM = {...}. It doesn't seem to be good? R

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

robiw wrote:
What next?
Call that function with pgm_get_far_address to get the address.

showPicture(pgm_get_far_address(Picture));

 

You can't use any regular C pointer for the far stuff. They work only below 0xFFFF. That's why you need pgm_get_far_address at all.

Stefan Ernst

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

Hmm, it is not so easy I thought. That means that I should call all the showPicture functions like follows:

 

showPicture(pgm_get_far_address(Picture));

 

And what about the body of the function above? Now, how should I read the data? Like this:

 

pixelData = pgm_read_word_far(Picture++), where the picture is the argument showPicture(uint32_t Picture)? Hmm, are you sure? R

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

BTW: Picture++ will not work anyway. Instead of a pointer you have now a plain uint32_t to hold the address, so you have no longer the convenience of the pointer arithmetic.

 

pixelData = pgm_read_word_far(Picture);

Picture += 2;

 

Stefan Ernst

Last Edited: Tue. Mar 7, 2017 - 01:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, you're right, Picture++ gives the wrong address due to the size of the type uint32_t and plain increasing. Thank you! R

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

This type of address passing I should use for all the arrays above 64kB? Is there the possibility to instruct the compiler (linker) which arrays should be placed first (below 64kB limit)? R

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

robiw wrote:
This type of address passing I should use for all the arrays above 64kB?
For simplicity I would use it for all the Flash arrays.

Stefan Ernst

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

The compiler endeavors to put as much of .promem in the first 64K. The only stuff "below" are the reset jump and IVT but it's then placed (deliberately) right after. But once you break 64K (minus a few hundred bytes) then you are back to needing 32bit pointers.

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

Hmm, but for the arrays below the 64kB could I use simple pgm_read (without _far etc.) even if the rest of arrays are above 64kB? I ask for it because I use a lot of different structures and functions for which pointers to these structures are arguments, so it would be easily to do that simpler...R

 

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

So, Is it the way to ask compiler to put some data first, right after IVT, that is below 64kB? R

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

My suggestion: use a custom section (gets located behind the code IIRC) and far access for the bigger things (like pictures), and PROGMEM and "normal" access for all other stuff in Flash then.

Stefan Ernst

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

This post was quite helpful when dealing with constants stored in flash memory over 64K.

https://www.avrfreaks.net/forum/r...

 

Based on the info gleaned from it, the routine below works with GCC and avr-lib 1.8c on an xMega128A1U.

 

One unfortunate hack was to add 0x00020000 to the address since the message_table array only stores the low two bytes of the string addresses.  I looked at the memory map to see the full address.  Does anybody know a way to generate the full address in the array?

 

const char const message_000[] PROGMEM = "String0";
const char const message_001[] PROGMEM = "String1";
const char const message_002[] PROGMEM = "String2";
const char const message_003[] PROGMEM = "String3";

const char * const message_table[] PROGMEM = {
    message_000, message_001, message_002, message_003, message_004
};

char s[16];
uint_farptr_t prog_ptr;

    prog_ptr = pgm_read_word_far(pgm_get_far_address(message_table[0]) + msgnum * sizeof(message_table[0]));
    strcpy_PF(s, (uint_farptr_t)0x00020000 + prog_ptr);
    send_message((char *)s);

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

Pointers are 16 bit. What were you expecting?

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

The address space for flash memory on a xMega128 is 17 bits.  Rather than calculating the offset with sizeof(message_table[0]) it would be better to let the compiler fill message_table with full addresses.  Right now it truncates them to 16 bit pointers.  I can't find a way to generate full addresses.

 

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

Use __memx (23 bit pointers) 

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

That's what I was looking for.  Thanks!