How to use morepgmspace.h

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

Hello,

I use the atmega2561 and I put flash text in "high" memory. I would like to use the library of Carlos Lama (http://savannah.nongnu.org/patch/?6352) to get the text.

But I can't use it. I added

#include "morepgmspace.h"

in the head of my file and

ASRC = strcpy_PF

in the makefile.

But it can't build my code.
May be it should be built in winavr and it not possible to use it directly?

Thank you.

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

Depending on your makefile, you might need to add the whole filename:

ASRC = strcpy_PF.S

and of course make sure, that the strcpy_PF.S file is within the reach of compiler (in the directory where all other sources of your project are).

JW

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

To compile these files alone in a project avr-libc source files asmdef.h and macros.inc located at avr-libc-x.x.x/common directory are needed. They can be downloaded from Savannah repositories http://savannah.nongnu.org/cvs/?...

Carlos.

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

carloslamas wrote:
To compile these files alone in a project avr-libc source files asmdef.h and macros.inc located at avr-libc-x.x.x/common directory are needed. They can be downloaded from Savannah repositories http://savannah.nongnu.org/cvs/?...

Carlos.

sectionname.h was necessary too. Now it works.:D
Thank you for your works.

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

pcu wrote:
Thank you for your works.

I second it. Your work helped me a lot, Carlos, thank you.

I am trying to push this a little bit further towards programmers' convenience, but time is against me.

Jan Waclawek

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

Another problem: I can't store pointer in an array of structure in high memory and I don't know if it is possible?

This is my .h file of text(TEXTWEB_SECTION is the linker directive to store in high memory):

#include "../../section.h"

typedef struct {
	const long *str;
	unsigned int var;
	unsigned int taille;
}tablevar_t;


extern const char  TEXTWEB_SECTION STR1[];
extern const char  TEXTWEB_SECTION STR2[];
extern const char  TEXTWEB_SECTION STR3[];
extern const char  TEXTWEB_SECTION STR4[];
extern const tablevar_t TEXTWEB_SECTION tablevar[];

This is my .c file of text:

const char  STR1[]={"$TEST1"};
const char  STR2[]={"$TEST2"};
const char  STR3[]={"$TEST3"};
const char  STR4[]={"$TEST4"};

const tablevar_t tablevar[] ={
		{STR1, 1 ,1 },
		{STR2, 2 ,1 },
		{STR3, 3 ,1 },
		{STR4, 4 ,1 },

};

So tablevar[0].str contains an address.
If I do :

addr_ptr=GET_FAR_ADDRESS(tablevar[0].str);
addrOfString=pgm_read_dword_far(addr_ptr);
...

I get the correct value (flash address) for addr_ptr, but not for addrOfString(0x16000 instead of 0x13000):

I would like to use strcpy_PF(buf,addrOfString) but without a correct addrOfString, it will not work!
I don't know if there is a solution...

Note: If I replace GET_FAR_ADDRESS(tablevar[0].str) with GET_FAR_ADDRESS(tablevar[i].str) in a loop I get a build error: undefined reference to `r30'

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

GET_FAR_ADDRESS macro has many limitations. It requires a compile-time known constant address (that's the reason to fail when the array element is accesed using a variable index) and operates at run-time (that's the reason why GET_FAR_ADDRESS it's not allowed to be used in variable initializations for const, flash, and generally for any static storage).

Changing the code

typedef struct {
   long *str; /* can't be const */
   unsigned int var;
   unsigned int taille;
}tablevar_t;

extern tablevar_t tablevar[]; /* can't be const nor TEXTWEB_SECTION */

tablevar_t tablevar[] = {
      {0L, 1 ,1 }, /* the pointer has to be initialided in the code */
      ...
};

tablevar[0].str = GET_FAR_ADDRESS(STR1); /* can't be indexed */
...

addrOfString= tablevar[i].str;

This is not exactly as intended originally because the struct array now should reside in RAM wasting resources. I don't know any way to store those 32 bit pointers at compile time.

Carlos.

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

Carlos wrote:
I don't know any way to store those 32 bit pointers at compile time.
I also have some large tables that I would like to store in upper flash of my ATmega2560. I have also faced the OP's problem.

While this may not get the OP any closer, I have toyed with the idea of storing the offset from the beginning of the table of values, then using GET_FAR_ADDRESS to get the base address of the table. Referencing the stored value would then be a base address plus offset operation - complicated, but achievable.

The bad news is that I have not had time to actually chase this down and implement it.

It's an idea to pursue, if you want. If it helps and you get it to work, please post an example for others to follow!

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

Quote:

a base address plus offset operation - complicated, but achievable

Do struct{}s help? In that case you can group everything under one composite name (with only one composite base address) and then individual element offsets are calculated by the compiler when you use "struct.*" or "struct_p->*"

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

Cliff wrote:
Stu wrote:

a base address plus offset operation - complicated, but achievable

Do struct{}s help? In that case you can group everything under one composite name (with only one composite base address) and then individual element offsets are calculated by the compiler when you use "struct.*" or "struct_p->*"
This is probably the way to go. As I said, i have not spent any time trying to make this work. In my case, I have an almost endless list of error messages that I'd like to throw in to upper flash. Your approach might be the ticket, although I was thinking a simple array might be easier. Dunno, just need to experiment a while.

Thanks for the idea, Cliff!

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

This is what I use and it works.
I declare a string instead of a pointer, unfortunaly I spend some bytes:

typedef struct {
	const unsigned char str[15];
	const void *ptrEEprom;
	unsigned char size;
}tablevar_t;

This the data in flash:

const tablevar_t TEXTWEB_SECTION MAINSETTINGS_TBL[] ={
		{"$LANG", 		&EE_main_set.langue ,		sizeof(EE_main_set.langue) },
		{"$TOEV", 		&EE_main_set.toevoer ,		sizeof(EE_main_set.toevoer) },
...}

And after to get value in this array of struct in high memory, I get the 2 bytes of pointer and I add an offset (I know this offset because I allocate myself the file):

/****************************************************
*****************************************************/
void FindAndReplaceTagByVar(char *tag, char *file, char *ptrTo_uip_appdata,unsigned int *longueur)
{
char bufGetStringInTable[15]={};
unsigned int i;
unsigned int adr;
unsigned long adrWithOffset;
unsigned char sizeEE;
unsigned int pointeurEE;

#define OFFSET_ADDRESS 0x30000ul /*offset linker, see section.h and makefile*/


	*ptrTo_uip_appdata = '\0';//endOfString

	if (strstr(file,"mainset.htm"))
	{
		for (i=0;i<33;i++)
		{
			//should be like this, otherwise it does not work
			adrWithOffset=OFFSET_ADDRESS;
			adr=(unsigned int)&MAINSETTINGS_TBL[i].str;
			adrWithOffset+=adr;

			//Get the string in the table and compare with the tag in the HTML page
			strcpy_PF(bufGetStringInTable,adrWithOffset);
			if (strcmp(tag, bufGetStringInTable)==0)//on a la correspondance?
			{
				//should be like this, otherwise it does not work
				adrWithOffset=OFFSET_ADDRESS;
				adr=(unsigned int)&MAINSETTINGS_TBL[i].size;
				adrWithOffset+=adr;

				//Get the size of the EEPROM variable stocked in the table
				sizeEE=pgm_read_byte_far(adrWithOffset);



				//should be like this, otherwise it does not work
				adrWithOffset=OFFSET_ADDRESS;
				adr=(unsigned int)&MAINSETTINGS_TBL[i].ptrEEprom;
				adrWithOffset+=adr;

				//Get the EEPROM pointer stocked in the table
				pointeurEE=pgm_read_word_far(adrWithOffset);
				ConvertValueInEEpromToString(pointeurEE, sizeEE, ptrTo_uip_appdata, longueur);
				break;
			}
		}
	}
...
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

'offsetof()' in stddef.h might be of help here.
See:

http://www.embedded.com/columns/technicalinsights/18312031?_requestid=198125

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

stu_san wrote:

While this may not get the OP any closer, I have toyed with the idea of storing the offset from the beginning of the table of values, then using GET_FAR_ADDRESS to get the base address of the table. Referencing the stored value would then be a base address plus offset operation - complicated, but achievable.

Here is a real world example of using the obscure offsetof() macro with the XMega 128A1. Using offsetof() greatly simplifies using structures. I use it frequently with structures I have to place in flash.

#include  /* uint8_t et.al */
#include  /* offsetof() */
#include 

/* From application note AVR1316: */
#include "avr_compiler.h" /* Compile with GCC release of WinAVR20090313 */
#include "sp_driver.h"

/* Change hex8() to match what your hardware needs to display a byte */
#define hex8(x) do{ /* display byte here */ }while(0)

int main( void )
{
  /* Read the part signature and revision: */
  hex8( MCU.DEVID0 ); hex8( MCU.DEVID1 ); hex8( MCU.DEVID2 );
  hex8( (uint8_t) (MCU.REVID+'A') );

  /* Device serial number: */
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM0 ) ) ); /* First read after reset or possibly Power Up returns zero */

  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM0 ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM1 ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM2 ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM3 ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM4 ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM5 ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, WAFNUM ) )  );

  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, COORDX0 ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, COORDX1 ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, COORDY0 ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, COORDY1 ) ) );

  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, TEMPSENSE0 ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, TEMPSENSE1 ) ) );

  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, ADCACAL0 ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, ADCACAL1 ) ) );

  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, ADCBCAL0 ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, ADCBCAL1 ) ) );

  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, DACAOFFCAL ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, DACACAINCAL ) ) );

  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, DACBOFFCAL ) ) );
  hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, DACBGAINCAL ) ) );
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is what I use. COFFEE_START is a constant passed from the makefile and the strings are in a section called .coffeefiles, e.g.

 
#in the makefile
ifndef COFFEE_START
  COFFEE_START=0x14000;  #a little above the end of the program
endif
  CFLAGS  += -DCOFFEE_START=$(COFFEE_START)
  LDFLAGS+= -Wl,--section-start=.coffeefiles=$(COFFEE_START)

//in the source
#define PROGFLASH __attribute__ ((section (".coffeefiles")))
char http_htm[]  PROGFLASH ="text/html";
char http_css[]  PROGFLASH ="text/css";
char http_png[]  PROGFLASH ="image/png";
...
{
uint8_t buf[80];
avr_flash_read(http_htm, buf, sizeof(http_htm));
...
)

avr_flash_read(uint16_t addr, uint8_t *buf, uint16_t size)
{
  uint32_t addr32=COFFEE_START+addr;
#if DEBUG
  unsigned char *bufo=(unsigned char *)buf;
  uint8_t i;
  uint16_t w=addr32>>1;   //Show progmem word address for debug
  PRINTF("r0x% fooavr 04x(% fooavr u) ",w,size);
#endif
#ifndef FLASH_WORD_READS
  for (;size>0;size--) {
#if FLASH_COMPLEMENT_DATA
    *buf++=~(uint8_t)pgm_read_byte_far(addr32++);
#else
    *buf++=(uint8_t)pgm_read_byte_far(addr32++);
#endif /*FLASH_COMPLEMENT_DATA*/
  }
#else
/* 130 bytes more PROGMEM, but faster */
  if (size&0x01) {       //handle first odd byte
#if FLASH_COMPLEMENT_DATA
    *buf++=~(uint8_t)pgm_read_byte_far(addr32++);
#else
    *buf++=(uint8_t)pgm_read_byte_far(addr32++);
#endif /*FLASH_COMPLEMENT_DATA*/
     size--;
  }
  for (;size>1;size-=2) {//read words from flash
#if FLASH_COMPLEMENT_DATA
   *(uint16_t *)buf=~(uint16_t)pgm_read_word_far(addr32);
#else
   *(uint16_t *)buf=(uint16_t)pgm_read_word_far(addr32);
#endif /*FLASH_COMPLEMENT_DATA*/

    buf+=2;
    addr32+=2;
  }
  if (size) {            //handle last odd byte
#if FLASH_COMPLEMENT_DATA
    *buf++=~(uint8_t)pgm_read_byte_far(addr32);
#else
    *buf++=(uint8_t)pgm_read_byte_far(addr32);
#endif /*FLASH_COMPLEMENT_DATA*/
  }
#endif /* FLASH_WORD_READS */

#if DEBUG>1
  PRINTF("\nbuf=");
  for (i=0;i<16;i++) PRINTF("% fooavr 2x ",*bufo++);
#endif

When debugging raises the size of the program and the sections overlap use e.g. $make COFFEE_START=0x18000 to temporarily move that section upwards.

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

@pcu: Interesting idea, and useful for my parse tables, but not the error text tables. You have a fixed character string allocated in your struct, which makes life easier. My error text strings are of variable length.

@Bob and @DAK: offsetof() works fine for a struct, but I have a collection of variable length strings. Again, this will be very useful for my parse tables (which I intend to move to high memory as well), but the variable length string collection craps out.

All: I have started playing with this problem more seriously. I can get part way there with:

#define HIPROGMEM   __attribute__ ((section (".hiprogmem")))

const char et_CMD_ERROR_NO_ERROR [] HIPROGMEM =  "Command succeeded";
const char et_CMD_ERROR_TIMEOUT [] HIPROGMEM = "Command Timeout";


#define HITABLE   __attribute__ ((section (".hitable")))

const char * ErrorTextTable[CMD_LAST_ERROR+1] HITABLE = {
    /*  0 */ et_CMD_ERROR_NO_ERROR,
    /*  1 */ et_CMD_ERROR_TIMEOUT,
...

(where .hiprogmem and .hitable are defined sections (either by ta linker directive or in the linker script)).

I have stripped out some readability macros above to make things a little more standard.

In the case above the lower 16-bits of the address to the strings are stored in ErrorTextTable. I suppose I could force the strings to start at 0x30000, so this is a "solution".

What would be nicer is if I could store the offset from the first string, et_CMD_ERROR_NO_ERROR, in ErrorTextTable. I have tried the following:

const char * ErrorTextTable[CMD_LAST_ERROR+1] HITABLE = {
    /*  0 */ 0,
    /*  1 */ et_CMD_ERROR_TIMEOUT - et_CMD_ERROR_NO_ERROR,
...

but the compiler ignores the offset computation. Several other suggestions made result in compiler errors.

Well, I'll keep playing with it. I had hoped for something that would take manual computing a "safe" location for tables out of the picture, but that may not happen. Oh well. :?

Thanks for the ideas, folks, I appreciate it!

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

This is a compile time method to insert 32 bit addresses as static data in code. ".int" and ".long" assembler directives insert the full contents of the symbols. Then the table (or struct) can be defined in a .S assembler file in this way:

.global ErrorTextTable

/* Local strings (.Lxxxx) in .hiprogmem section */

.section .hiprogmem,"ax"

.Let_CMD_ERROR_NO_ERROR:
	.asciz "Command succeeded"
.Let_CMD_ERROR_TIMEOUT:
	.asciz "Command Timeout"


/* Table containing 32 bit pointers to error strings in .hitable section */

.section .hitable,"ax"

ErrorTextTable:
    .long .Let_CMD_ERROR_NO_ERROR
    .long .Let_CMD_ERROR_TIMEOUT

The array ErrorTextTable can be declared in C as

extern const uint_farptr_t ErrorTextTable[CMD_LAST_ERROR+1];

And the n-th 32 bit pointer element can be obtained as

uint_farptr_t ptr32 = pgm_read_dword_far(GET_FAR_ADDRESS(ErrorTextTable) + 4 * n);

Inline assembler macros can also be used in C to avoid the assembler file but the implementation is not very clean.

Carlos.

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

Thank you Carlos! I shall try this - I would rather use the space for the 32-bit addresses than anchor my strings at some "nice" boundary.

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

I am having a strange problem when I use memcpy_PF. I am using a atxmega128a1 and trying to implement a bootloader. I have a list of strings stored in the boot section and I use memcpy_PF to get them out. I then just use the UART to display the strings.

Here is my code

	
const char init[] PROGMEM = "Boot Version: 0.1 \r\n> \0";
const char flas[] PROGMEM = "FLASH\r\n> ";
const char boot[] PROGMEM = "BOOT\r\n> ";
const char spac[] PROGMEM = "\r\n> ";

PGM_P table[4] PROGMEM = { init,flas, boot, spac };
int main() {
       	char buf[32];
	uint_farptr_t addr;
	uint_farptr_t p;
        addr = GET_FAR_ADDRESS(table[0]);
	memcpy_PF(&p,addr,sizeof(PGM_P));
	strcpy_PF(buf,(0x20000 | p));
	UARTPutString("Test\r\n");
        UARTPutString(buf);
}

When I comment out memcpy_PF and strcpy_PF, "Test" gets printed out on HyperTerminal; but when I run the code as is I get nothing to print.

Not sure how this is possible any help would be appreciated.
Thanks.

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

Why 0x20000 ?

JW

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

Also look at the .lss (and the .s) if you wan't to understand what's really going on. Maybe also try running it in the simulator too.

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

wek wrote:
Why 0x20000 ?

JW


That is the address for the start of my bootloader. I have to OR it together because p is only a 2 byte address when I need 3.

clawson wrote:
Also look at the .lss (and the .s) if you wan't to understand what's really going on. Maybe also try running it in the simulator too.

I have been looking at both disassembler windows and .lss. I have looked at memcpy_P as well to compare. memcpy_PF does what it is suppose to do. The only weird thing that I am seeing is that in my UARTPutChar(), which is the similar to UARTPutString().

uint8_t  UARTPutChar (uint8_t c) {
		*pbuf->RingBufTxInPtr++ = c;
}

pbuf is just a pointer to a struct. RingBufTxInPtr points to a variable RingBufTx, which is just a large ring buffer.
When I comment out memcpy_PF, and watch this line of code "c" goes into my RingBufTx as it should since that is what the RingBufTxInPtr is pointing to. But when I run it with memcpy_PF and watch this line of code nothing happens besides RingBufTxPtr incrementing.
Why would this simple operation not work?

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

chrislego88 wrote:
wek wrote:
Why 0x20000 ?

JW


That is the address for the start of my bootloader. I have to OR it together because p is only a 2 byte address when I need 3.

Okay, I don't xMega so I did not know they have more FLASH than they advertise in their name.

But you are aware 0x20000 is effectively 0 in avr-gcc, due to int being 16 bit, aren't you.

chrislego88 wrote:
clawson wrote:
Also look at the .lss (and the .s) if you wan't to understand what's really going on.

I have been looking at both disassembler windows and .lss.


Okay, then let us too look at the .lss .

And perhaps start a new thread.

JW

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

I think I figured out the problem. After the memcpy_PF function I noticed the Z pointer went to 0x02xxxx. The Z pointer gets used for that pointer operation. This is obviously not where I need it to be for operations outside of the memcpy_PF. In the debugging, after the memcpy_PF I cut off the leading 2 on the Z pointer and I got everything to print out just fine. So it seems that after any *_PF operation I need to cut off the leading 2 on the Z pointer.

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

In a C program you should never need to be accessing machine registers directly. If you really have to include code to clear R31 it's not a solution - what happens when the next issue of the compiler chooses to use X rather than Z for indexing, for example?

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

This indeed appears as a bug, and even a known one: https://savannah.nongnu.org/bugs...

This applies apparently only for xmegas with EBI .

JW

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

clawson wrote:
In a C program you should never need to be accessing machine registers directly. If you really have to include code to clear R31 it's not a solution - what happens when the next issue of the compiler chooses to use X rather than Z for indexing, for example?

Cliff,

THe issue is not R31, but RAMPZ.

the trouble is with the memcpy_PF function from Carlos Lamas' package, raised now to official rank with avr-libc 1.7.0 (but ALL xxx_PF() and pgm_read_xxx_far() are affected in the same way).

In xMegas with EBI the RAMPZ register extending Z to 24 bits unfortunately serves both ELPM and LD/LDD/ST/STD. Normally, in avr-gcc, pointers still being 16-bit only, RAMPZ remains zero all the time (and no RAM nor FLASH above 64kB can be addressed, fullstop). The far FLASH support in avr-libc breaks this.

JW

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

clawson wrote:
In a C program you should never need to be accessing machine registers directly. If you really have to include code to clear R31 it's not a solution - what happens when the next issue of the compiler chooses to use X rather than Z for indexing, for example?

I agree with you. I merely changed my memcpy_PF and strcpy_PF to reset the RAMPZ back to zero, in assembly. This should be probably be done for all _PF functions in the future.

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

Oh sorry, I missed the fact you were talking about RAMPZ - as it's use is so localised and it's not likey to be used for anything else then I guess you can just put:

RAMPZ = 0;

into the source after it's been used as it's defined in the .h files just like any other SFRs:

C:\WinAVR-20100110\avr\include\avr>grep RAMPZ iox*
iox128a1.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox128a1.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox128a3.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox128a3.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox128d3.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox128d3.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox16a4.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox16a4.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox16d4.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox16d4.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox192a3.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox192a3.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox192d3.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox192d3.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox256a3.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox256a3.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox256a3b.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox256a3b.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox256d3.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox256d3.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox32a4.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox32a4.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox32d4.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox32d4.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox64a1.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox64a1.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox64a3.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox64a3.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)
iox64d3.h:#define RAMPZ  _SFR_MEM8(0x003B)  /* Ramp Z */
iox64d3.h:#define CPU_RAMPZ  _SFR_MEM8(0x003B)

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

chrislego88 wrote:
I merely changed my memcpy_PF and strcpy_PF to reset the RAMPZ back to zero, in assembly. This should be probably be done for all _PF functions in the future.
I submitted a suggestion along these lines to avr-libc tracker here.

JW