I'm working with a PIC16F690, using Microchip's XC8 compiler. I want to embed EEPROM values into the hex file, so that the EEPROM gets programmed at the same time as the program memory.

I've done this in the past with the C18 compiler (it was for a PIC18, not this PIC16), as follows:

#pragma romdata eedata_scn=0xf00000
    rom unsigned char my_eeprom_values[256] = {0, 4, 2, 1, (and so on), 3};
#pragma romdata

The EEPROM isn't actually at that memory space (0xf00000), but it's how C18 accesses it. You can get this address by looking in the linker script:


Anyway, this doesn't work in XC8. There is another statement that is similar:

__EEPROM_DATA (0,1,2,3,3,2,1,0);

But this statement can only take eight arguments, and you can't give it a starting location in EEPROM, as far as I can tell. So, your code ends up with 32 of these statements (for 256 bytes of EEPROM), which seems unwieldy.

Also, the XC8 User's Manual says that this statement isn't implemented for PIC18's. This doesn't effect me now, but it will in the future!

Is there a better way to do this in XC8?


I opened a support ticket with Microchip and asked this question. It turns out that the __EEPROM_DATA macro is the only way they recommend to initialize the EEPROM values.

On the good side, this macro does, in fact, work for all PIC18 devices with internal EEPROM. My misunderstanding came from this statement in the User's Manual: CAVEATS MPLAB XC8 does not implement the __eeprom qualifiers for any PIC18 devices; this qualifier works as expected for other 8-bit devices.

The __EEPROM_DATA macro, however, does work. I've just tested it successfully.

Even so, this is still unwieldy. Is there a work-around out there that will allow initialization of a specific EEPROM location, without starting at the beginning?

Thanks again.


2 Answers 2


To test all below I used MPLAB 8.76, compiler XC8 ver 1.30:

First a digression/advice: If you have switched to PIC16F690 recently: ~ 6 weeks ago I decided to abandon this chip, except for really small projects. It has little FLASH, little RAM and only 256 EEPROM. And you can not debug it easily on real target. I use 18FK4620 now: it has 16 times as much FLASH (64kB) , 4 times more EEPROM (1kB), and almost 16 times RAM (~ 4kB), it can run at up to 64MHz Fosc (!), plus more ports, etc.

And the MOST IMPORTANT: you can DEBUG 18F46K20 using standard PICKIT2 and MPLAB 8.76 ... 8.91 (I do not use MPLAB X yet, as I heard a lot of bad stories about it). And you do not need any extra interface boards etc. Just your target board --> PICKIT2 (i.e. you do not have to switch to a mishap PICKIT3)

And price is very similar: 18F46K20 is ~ $2.90 and 16F690 is ~ $2.40 in retail.


---------------------- Solution 1a: Use something like this (and change '20' to the array size you want):

__eeprom unsigned char my_eeprom_values[20] =  
        {   0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20,
            0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30};**

But if you use the above then you do NOT know where compiler will place these in EEPROM. (Note though that __eeprom qualifier is ignored by XC8 compiler for many PIC18Fxxx devices)

---------------------- Solution 1b:

const unsigned char abc1 @ 0x2100 = 0x11; // @ EEPROM addr = 0
    // ......
    const unsigned char abc2 @ 0x2110 = 0x22; // @ EEPROM addr = 17**

Note that it looks that EEPROM in 16F690 starts at addr. 0x2100 (not 0xF00000 as you mentioned). I checked .map file after build. I also checked the result of the above after compiling the code and then I viewed the EEPROM using PICKIT2 (or if you debug under MPLAB using MPLAB SIM, then after you build the code, go to Menu -> VIEW -> EEPROM). You will see al data there as desired.

---------------------- Solution 1c:

You can mix (1a) and (1b) above, you can use 'int' instead of 'char', but : - be aware that because __EEPROM_DATA does not allow to specify the eerpom address, one statement will overwrite some of the other ones. To illustrate this I placed 0x99 in locations that WOULD be overwritten. XC8 warns about this anyway - see the end of my post. - Endian that XC8 uses 'swaps' bytes OF 'int' type: the below 'abc' data will be stored as : 22114433, instead of as 11223344.

---------------------- EXAMPLE:

Here is a tested example for 16F690 under XC8 ver 1.30:

    const unsigned int abc1 @ 0x2100 = 0x1122;
    const unsigned int abc2 @ 0x2102 = 0x3344;
  __EEPROM_DATA(0x99, 0x99, 0x99, 0x99, 5, 6, 7, 8);
    const unsigned int abc3 @ 0x2108 = 0x5566;
    __EEPROM_DATA(0x99, 0x99, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88);
    __eeprom unsigned char my_eeprom_values[20] = \ 
    {   0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20,
        0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30};

Resulting EEPROM CONTENTS is this:

22 11 44 33 05 06 07 08 66 55 83 84 85 86 87 88
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

So 0x(22 11 44 33) have overwritten 4 x 0x99. Same with 0x(66 55). But note that the rest is just a plain copy of data in C code.

---------------------- Solution 2: 'yours': Just as you said place as many '8 byte' long __EEPROM_DATA statements as you need. What's wrong with this ? It is simple and works always. Compiler places data in the order you will have them in your C code. If you need some bytes to be unchanged then place 0xFF for them. Eg.

__EEPROM_DATA(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);  // addr: 0x00 ... 0x07 
__EEPROM_DATA(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88);  // addr: 0x08 ... 0x0F
__EEPROM_DATA(0x55, 0x66, 0x87, 0x65, 0xFF, 0xFF, 0xFF, 0xFF);  // addr: 0x10 ... 0x17 

During build in (1b/1c) XC8 compiler gives these warnings:

.... object "_abc1" lies outside available code space

... (1343) hexfile data at address 0x4200 (0x99) overwritten with 0x22 

but I got data I wanted in EEPROM where I wanted it so I don;t care.

Memory Summary: Program space used F00h ( 3840) of 1000h words ( 93.8%) Data space used E4h ( 228) of 100h bytes ( 89.1%) EEPROM space used 24h ( 36) of 100h bytes ( 14.1%) ...



After looking at the above suggestions and and some other searches i came across the following solution. This includes the updates to compiler so I am using MPLABX 5.25 and XC8 v2.1. I used the following command since eeprom for the PIC1846K80 is "located" starting at 0xF00000.

const uint8_t my_variable __at(0xF0000C) = 0xA5; //0xF0000C to write at location 0xC

The above yielded the following a hex file with the following chunk. The first line indicates that it is now referring to eeprom, second line lists 1 byte at memory 0x0C of eeprom has 0xA5, last line indicates end of file.

:0200000400F00A // offset to eeprom location

:01000C00A54E // at at eeprom address 0x0C write 0xA5

:00000001FF // end of file


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.