SOLVED: avr-gcc problem with PROGMEM above 64k

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

Hello all,

 

I am writing a boot loader for a xmega256a3u and I have constant data with PROGMEM attribute.   The linker places it nicely into flash above 0x40000 (byte address) and I am using pgm_read_word_far() which creates code with the ELPM instruction but when I step though the instructions 0x00 is moved into RAMPZ.

 

What have I missed?   Is there a different PROGMEM attribute above 64k?   Or maybe none at all?

This topic has a solution.
Last Edited: Wed. Apr 8, 2015 - 09:19 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you using morepgmspace.h from Carlos Llamas?

Last Edited: Sun. Apr 5, 2015 - 03:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is that the magic word?   No, I am using the "pgmspace.h" that comes with the compiler.   Thank you very much for the advice; I'll have a look at that.   Normally 64k const in ROM is enough for me but Atmel placed the boot loader in the top of the memory and the SPM command does not work below, so they really don't leave me much choice.

 

What surprises me is that the compiler generated the correct(ish) code, the linker is aware of the memory allocation but for some reason does not fill in the uppermost address word.
 

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

I'm a bit confused now.   As far as I can see are Carlos modifications already included in the "pgmspace.h" that I have installed (gcc-avr 4.7.2).   Also the xxxxx_FP prototypes are there.    So am I using "morepgmspace.h" already?

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> I am using pgm_read_word_far()

 

That alone does not suffice. You need a 32-bit address as a parameter, so the question is, what is the parameter to pgm_read_word_far().

 

See pgm_get_far_address().

 

A different approach is to use __flashN https://gcc.gnu.org/onlinedocs/g...

 

JW

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

So simply putting &my_variable as an argument into pgm_read_word_far is not sufficient?

 

I had a look at pgm_get_far_address() and I get the impression that things beyond 64k get very messy with AVR and/or the gnu-avr compiler.   The RAMPZ register reminds me a bit of the Intel patch to make a 16 bit processor out of an 8-bit 8080 design and having generations of software developer suffer for ever after (no, I did not participate).

 

Since the source code I write has to run on all kinds of processors that pgmspace.h business gets a bit in the way in that respect; so far I could eliminate compiler dependencies and Harward problems (not only limited to AVRs) with a few #defines in the processor specific variable type definition file.

 

I had a look at the __flashx before, it would work but I would create a compiler/source linker dependency.    I would have to know at compile time where the code is placed.

 

I replaced the table lookup by a hard coded setting of variables in the meantime; not nice but since the table is small it works for me (and is portable).

Last Edited: Wed. Apr 8, 2015 - 07:57 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The whole reason I suggested morepgmspace.h above was because of:

#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; \
 })

To be honest I hadn't realised that this was later integrated into the real pgmspace.h but looking at it now I see a rather familiar:

#define pgm_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;                                              \
})

So, yes, you need some way to break the fact that normal pointers in AVR land are just 16 bit and this appears to be the current name for the mechanism.

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

Hello clawson, wek3,

 

ok, that pretty much answers my question and it seems I am using the right header file but neglected to use the appropriate function for obtaining a 24-bit pointer.  

Thank you very much for your help and time!

 

Regards,

Last Edited: Wed. Apr 8, 2015 - 09:43 AM