cwanish
cwanish

Reputation: 29

Variable address in eeprom space as function argument in C

I have a simple and quick problem with C in PIC24f16ka102 and xc16 compiler.

I want to pass a variable reference to my function. The variable is in eeprom space:

   int __attribute__ ((space(eedata))) eeData; // Variable located in EEPROM,declared as a global variable.

With this sequence I am able to save some data in eeprom memory:

unsigned int offset;
// Set up NVMCON to erase one word of data EEPROM
NVMCON = 0x4004;
// Set up a pointer to the EEPROM location to be erased
TBLPAG = __builtin_tblpage(&eeData2); // Initialize EE Data page pointer
testDebug = TBLPAG;

offset = __builtin_tbloffset(&eeData); // Initizlize lower word of address
__builtin_tblwtl(offset, 0x9876); // Write EEPROM data to write latch
asm volatile ("disi #5"); // Disable Interrupts For 5 Instructions
__builtin_write_NVM(); // Issue Unlock Sequence & Start Write Cycle
while(NVMCONbits.WR == 1);

This way I write value 0x9876 to first 16 bits of eeprom. But I need to have it as &eeData

I want to write my own function:

void eeprom_writeWord(unsigned int __attribute__ ((space(eedata)))  addresOfMyEEpromVariable, unsigned int value)
{
    unsigned int offset;
// Set up NVMCON to erase one word of data EEPROM
NVMCON = 0x4004;
// Set up a pointer to the EEPROM location to be erased
TBLPAG = __builtin_tblpage(&addresOfMyEEpromVariable); // Initialize EE Data page pointer
offset = __builtin_tbloffset(&addresOfMyEEpromVariable); // Initizlize lower word of address
__builtin_tblwtl(offset, value); // Write EEPROM data to write latch
asm volatile ("disi #5"); // Disable Interrupts For 5 Instructions
__builtin_write_NVM(); // Issue Unlock Sequence & Start Write Cycle
while(NVMCONbits.WR == 1);
}

but How to pass my address as a function argument so that my function would see that it is still adress in eeprom space? It cannot be just address, becouse if so I get error. __builtin functions need address with some attribute that it is eeprom memory.

How to pass eeprom address with attribute to my function? Please help

edit:

Thank You for Your advise, but I still get the same error:

    error: Argument to __builtin_tbloffset() is not the address
of an object in a code, psv, or eedata section;

Function __builtin_tbloffset needs an address of the eeprom memory, not just an address of something. It works well if I use the whole sequence but not in a function (I mean the sequence in my first post).

Now i tried as You said:

void eeprom_writeWord(unsigned int *addresOfMyEEpromVariable, unsigned int value)
{
        //write word
// Set up NVMCON to write one word of data EEPROM
NVMCON = 0x4004;
// Set up a pointer to the EEPROM location to be written
TBLPAG = __builtin_tblpage(*addresOfMyEEpromVariable);
unsigned int offset = __builtin_tbloffset(*addresOfMyEEpromVariable);
// Write Data Value To Holding Latch
__builtin_tblwtl(offset, 0x9999);
// Disable Interrupts For 5 Instructions
asm volatile ("disi #5");
// Issue Unlock Sequence & Start Write Cycle
__builtin_write_NVM();
while(NVMCONbits.WR == 1);
}

or even without '*' sign:

void eeprom_writeWord(unsigned int *addresOfMyEEpromVariable, unsigned int value)
{
        //write word
// Set up NVMCON to write one word of data EEPROM
NVMCON = 0x4004;
// Set up a pointer to the EEPROM location to be written
TBLPAG = __builtin_tblpage(addresOfMyEEpromVariable);
unsigned int offset = __builtin_tbloffset(addresOfMyEEpromVariable);
// Write Data Value To Holding Latch
__builtin_tblwtl(offset, 0x9999);
// Disable Interrupts For 5 Instructions
asm volatile ("disi #5");
// Issue Unlock Sequence & Start Write Cycle
__builtin_write_NVM();
while(NVMCONbits.WR == 1);
}

The result is still the same. __builtin_tblpage and other __builtin_(...) functions are functions built into xc16 compiler.

Upvotes: 1

Views: 1627

Answers (2)

EBlake
EBlake

Reputation: 755

It may be that the builtin routines can deal with hard-coded addresses (as in your first example - compiler/linker knows where eeData is located), but cannot deal with variable addresses.

Two things you can try:

(1) make the eeprom_writeWord an inline function (so that once again, the compiler can hard-code the address). Note that if this works, it still will likely fail for "complicated" situations such as addresses stored in indexed arrays.

(2) look at the assembler code generated for the builtin routines in your working sample and rewrite them for what you want (using C or inline assembler). These routines are only a few instructions long. e.g. __builtin_tblpage is just stripping off the upper part of the address - something easily accomplished in C with masking and/or right shifts.

Upvotes: 1

user2371524
user2371524

Reputation:

Consider that prototype:

void eeprom_writeWord(unsigned int addresOfMyEEpromVariable, unsigned int value)

The attribute probably doesn't do anything here, left out for readability. What you do ist not taking the address (which would be of type unsigned int *) but the value itself (a plain unsigned int, that's not magically a pointer just by calling it addressOfSomething ;)), so it just gets copied to your function.

Change it to the following

void eeprom_writeWord(unsigned int *addresOfMyEEpromVariable, unsigned int value)

And use like this

eeprom_writeWord(&eeData, 0x9876);

And, of course, don't use the addressOf operator & inside the function any more ... cause now you already have a pointer. This will then do what you expected.

edit: Regarding your answer, you should delete this (because it is not an answer) and instead edit your original question and put it there.

The version without the asterisks ist the correct one. Not knowing your compiler, it might help to have the attribute in your function prototype as well:

void eeprom_writeWord(
    unsigned int __attribute__ ((space(eedata))) *addresOfMyEEpromVariable,
    unsigned int value)

Just saying without the asterisk there (marking the argument to be a pointer), it definitely cannot work.

Upvotes: 0

Related Questions