Using Internal EEPROM of PIC Microcontroller
Contents
There are commonly three types of memories in a PIC Microcontroller, Flash Program Memory, Data Memory (RAM) and EEPROM Data Memory. We write Programs in the Flash Program Memory of a microcontroller. Flash memory makes it possible to program a microcontroller many times before installing to device and even after the installation we can change the program. RAM Data Memory is used for storing data temporarily during program execution and it is volatile. That is, this memory is cleared when the power is gone or after CPU reset. RAM Data Memory locations are also called General Purpose Registers (GPR). These two memories have faster response time. The third memory is EEPROM memory which is an abbreviation for Electrically Erasable Programmable Read Only Memory. EEPROM memory can be read and write electrically, can be accessed through program. It is a non volatile memory but has slower response time. EEPROM memory can be used to store data such as sensor logs, device parameters which should not be loss during power loss or CPU reset. Here I using PIC 16F877A for explanation.
EEPROM Special Function Registers
The data in the EEPROM and Flash Program Memory can be read/write during normal operations (over full VDD range). These memories are not mapped in the register file space, instead of it can be accessed through the following six Special Function Registers (SFR) for read and write operations.
- EECON1
- EECON2
- EEDATA
- EEDATH
- EEADR
- EEADRH
EEDATA register hold 8-bit data for read/write and EEADR holds the address of EEPROM memory location to be accessed. PIC Microcontrollers usually have 128/256 bytes of data EEPROM memory with address ranging from 00h to FFh. On devices having 128 bytes, memory locations from 80h to FFh are unimplemented and will be wraparound to beginning of the data EEPROM memory. On-Chip charge pump (used while writing data to EEPROM) is turned off when writing these unimplemented locations. EEDATH and EEADRH registers are used when interfacing program memory block with Program Flash Memory. Here we deals only with EEPROM data memory.
EEPROM data memory allows only single byte read and write. When a data byte is written in to EEPROM, automatically erases the particular location first and then writes the new data (erase before write). The write time is controlled by and on-chip timer and write/erase voltages are generated automatically by an on-chip charge pump. When the device is code protected, program or data memory will not be accessible to programmer but CPU may read or write data EEPROM memory.
EECON1 is the control register used for memory access.
EEPGD control bit is used to select Program Memory or Data Memory access. If it is set Program Memory is selected and vice versa. Control bits RD, WR are used to initiate read, write, erase operations. These bit cannot be cleared in program, only able to set. These bits are cleared in hardware on the completion of read or write operations.
The WREN control bit is the Write Enable bit, when set it enables write or erase operation. On power-up, the WREN bit will be automatically cleared. The WRERR bit is the Write Error Flag bit, it sets when a write (or erase) operation is interrupted by a MCLR or a WDT Time-out Reset during normal operation. In these situations, we can check the WRERR bit and rewrite the location as the data and address will be unchanged in the EEDATA and EEADR registers.
On the completion of write operation Interrupt flag bit, EEIF in the PIR2 register is set. It must be cleared in program.
EECON2 register is not a physical register and it is used exclusively in the EEPROM write sequence. Reading EECON2 will read all zeros.
Reading from Data EEPROM Memory
- Write the address of the memory location to be read to EEADR register.
- To select EEPROM data memory, clear the EEPGD control bit.
- Set the RD bit to initiate the read cycle.
- Then we can read data from EEDATA register.
Writing to Data EEPROM Memory
- Write the address of the memory location to write to EEADR register.
- Write the 8-bit data to be written in the EEDATA register.
- To select EEPROM data memory, clear the EEPGD control bit.
- Set the WREN control bit to enable write operations.
- Disable Interrupts if enabled in your program. (You may store interrupt register (INTCON) to enable interrupts)
- Then the special five instruction sequence is executed.
- Enable Interrupts if using.
- Disable the program operations by clearing WREN control bit.
- WR control bit is cleared and EEIF interrupt flag bit is set after completion of the write operation. EEIF bit must be cleared in the program.
MikroC Programming
Functions Developed by Us
MikroC Function to Read Data from Internal EEPROM :
unsigned char readEEPROM(unsigned char address) { EEADR = address; //Address to be read EECON1.EEPGD = 0;//Selecting EEPROM Data Memory EECON1.RD = 1; //Initialise read cycle return EEDATA; //Returning data }
MikroC Function to Write Data to Internal EEPROM :
void writeEEPROM(unsigned char address, unsigned char datas) { unsigned char INTCON_SAVE;//To save INTCON register value EEADR = address; //Address to write EEDATA = datas; //Data to write EECON1.EEPGD = 0; //Selecting EEPROM Data Memory EECON1.WREN = 1; //Enable writing of EEPROM INTCON_SAVE=INTCON;//Backup INCON interupt register INTCON=0; //Diables the interrupt EECON2=0x55; //Required sequence for write to internal EEPROM EECON2=0xAA; //Required sequence for write to internal EEPROM EECON1.WR = 1; //Initialise write cycle INTCON = INTCON_SAVE;//Enables Interrupt EECON1.WREN = 0; //To disable write while(PIR2.EEIF == 0)//Checking for complition of write operation { asm nop; //do nothing } PIR2.EEIF = 0; //Clearing EEIF bit }
To read or write data to EEPROM, you may use built-in MikroC Libraries or user defined functions as following.
Using MikroC EEPROM Libraries
MikroC PRO for PIC Microcontrollers provides library to work with Internal EEPROM. We can easily read/write form EEPROM using the following library functions.
- Eeprom_Read
- Eeprom_Write
Eeprom_Read
Prototype: unsigned short EEPROM_Read(unsigned int address);
Eeprom_Read function reads data from a specified address. Note that parameter address is of integer type, which implies that this functions supports microcontrollers with more than 256 bytes of EEPROM. There must me atleast 20ms delay between successive using of these routines.
Eeprom_Write
Prototype: void EEPROM_Write(unsigned int address, unsigned short data);
EEPROM_Write function write data to the specified address. As I said above, since the address parameter is of integer type, it supports microcontrollers with more than 256 bytes of EEPROM. There must me atleast 20ms delay between successive using of these routines. Beware that all Interrupts will be disabled during the execution of this function.
Note: Address ranges from 00h to FFh for devices having 256 bytes while for 128 bytes devices it is 00h to 7Fh.
Mikro Code
void main() { unsigned int a, i; TRISC = 0; do { for(i=0,a=1;i<8;i++) { EEPROM_Write(i, a); a = a<<1; } for(i=0;i<8;i++) { PORTC = EEPROM_Read(i); Delay_ms(1000); } }while(1); }
Circuit Diagram
Note: VDD and VSS of the pic microcontroller is not shown in the circuit diagram. VDD should be connected to +5V and VSS to GND.
In this example we writes 00000001 to the first memory location, 00000010 to second, 000000100 to third etc sequentially up to 10000000. Then it is read sequentially and output through PORTC.
Download Here
You can download the hex file, MikroC source code, Proteus files etc here.
Hi, how to swap the data from one register to another register without eeprom.
Hi, I have some issues with mikroC EEPROM_Read function. There are some cases when I read a location but no data is saved in ram. I am 100% sure the right addresses are being read since I had written the address after to check if I don´t read any random location. This problem has been solved writing a Delay_ms(20) before the eeprom read instruction. I don´t really know if less time is needed but it works. My question is if someone knows why this problem is solved this way. Thanks.
Dear sir
Thankyou for your nice blog. I have a question..I want to write a large number I.e 12000000 in EEPROM and want to recall the number for further use. How can I do this?
Thanks
Then you have to make necessary changes in the program to make it compatible with 18F452. Kindly use our forums https://electrosome.com/forums/ for support as it is outside the scope of above article.
oh im sorry i forget to mention, i am usin pic18f452 and mikroc 6.6.3
Are you using the same microcontroller, 16F877A in simulation ?
16F877A and 16F877 are different microcontrollers.
HI sir
I downloaded yor project and run the simulation it is giving such warning :
[PIC16 EEPROM] PC=0x0032. Cannot set EECON1 without first setting EECON1 in a previous instruction. [U1]
[PIC16 EEPROM] PC=0x0033. Write to EECON1 sets both EECON1 and EECON1 simultaneously. This is ambiguous – both bits will be considered clear. [U1]
Also,i have tried lot of methods even the mikroc default examples but i am not able to write and read anything to eemprom however when i use eeprom editor it is working, can you give any advice?
Hello Sir, I am trying to write a code to store user input string into an array using simple 4 push buttons and then writing it in internal EEPROM of pic microcontroller. The string is stored in an array but unable to write into EEPROM. Sir can you help me on this issue, below is my code:
#include “INCLUDE.h”
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_OFF & BOREN_ON & LVP_OFF & CPD_OFF & WRT_OFF & CP_ON);
__EEPROM_DATA(‘W’,’E’,’L’,’C’,’O’,’M’,’E’,’ ‘); // Initial string character for 1st time programming.
__EEPROM_DATA(‘E’,’E’,’P’,’R’,’O’,’M’,’ ‘,’ ‘);
// String array to store 3 digit access code
char message4[] = “WRITE COMPLETED”;
char message5[] = “Reading Data”;
char message7[] = “Welcome EEPROM”;
char Edata[] = “0000000000000000”;
unsigned short k, NUM ;
unsigned int ADD; // Start EEPROM Location
char temp, cursor;
void main (void)
{
TRISC = 0x20; //PORTC as output
TRISD = 0x08; //PORTD as output
TRISB = 0b01000000; //IR SENSOR INPUT ON RB6
TRISB7 = 0;
POWER_LED = 0;
PORTA = 0;
PORTC = 0;
PORTD = 0;
InitLCD ();
InitADC ();
lcd_gotoxy(0,3);
WriteStringToLCD(“Testing”);
lcd_gotoxy(1,0);
WriteStringToLCD(“internal EEPROM”);
__delay_ms(1000);
ClearLCDScreen();
lcd_gotoxy(0,3);
WriteStringToLCD(“ENTER TEXT”);
do
{
// Read operation
if(POWER == 1)
{
__delay_ms(400);
ClearLCDScreen();
lcd_gotoxy(0,2);
WriteStringToLCD(message5);
ADD = 0;
for (k = 0; k < 16; k++)
{
temp = eeprom_read(ADD+k);
Edata[k] = temp;
}
lcd_gotoxy(1,0);
WriteStringToLCD(Edata);
__delay_ms(2000);
}
// Cursor increment Operation
if (ENTER == 1)
{
__delay_ms(400);
k = k + 1;
cursor = cursor + 1;
}
// Read & Write Operation
if (BACK == 1)
{
// Write operation
__delay_ms(400);
ADD = 0;
for (k = 0; k ‘Z’) message7[k] = ‘A’;
else if(message7[k] ‘Z’) message7[k] = ‘A’;
else if(message7[k] < 'A') message7[k] = 'Z';
lcd_gotoxy(1,cursor);
WriteDataToLCD(message7[k]);
message7[ADD] = message7[k];
}
}
while(1);
}
It is saving to the internal EEPROM of the PIC. It doesn’t need power to keep the data.
Hi Ligo,I have a dc motor .” char t ” that my “duty cycle=t ” I increase it with push button,
but how can I save it to a variable that be saved in pic after off and on again?
thank you in advance.
you only need 2 eeprom addreses to save all 16 relays . one eeprom location can store 8bits of info. For example 00000000 whith could mean that all relays are off and 11111111 could mean that relays are on also this way easy to enable all outputs of a single port in micro just porta = 0b11110000.
For eg, let i be the variable on the SSD.
EEPROM address can be 0 to 255. But you need 2 bytes per set… so max sets values of sets will be 0 to 127.
So you can read memory locations 2i & 2i+1
Dear Ligo,
Many thanks for your reply.
I understood your suggestion and tested with a very basic project in mikroC and Proteus, but I have to yet succeed in the part where I can select a memory address from two multiplexed 7-Segments and save the state of each relay as High or Low and then save them all in the selected memory location.
I am using PIC16F877A, briefly with the following setup:
I have 2 buttons named Up and Down which show the memory address/number (total 16 memory locations as 1 to 16) on two multiplexed SSDs, but I am not able to translate them (the SSD number) into a memory location for state save of the relay ports, all on PORTD.
Total 16 relays, as each relay has a button for its On/Off toggle. 8 on PORTB, 8 on PORTC, with state LEDs on their coils for visual status feedback.
All mentioned above are possible to be done using manual memory address pass to the EEPROMWrite(address, data) function, for instance writing the EEPROMWrite(1, PORTB) works fine, but not by getting the SSD numbers and passing it, which should be the case.
Your feedback is highly appreciated in advance.
Naser
For, eg: you can use 2 bytes (16 bits) for saving the ON OFF status of 16 relays. You can save multiple status in multiple EEPROM locations and recall or edit it based on different conditions.
Dear Ligo,
Your website and tutorials are a big help to the community and I highly appreciate the time and effort you put into this task. God bless you sir.
I have a question please:
How to set and have programmed presets like if I had 16 relays and wanted to save the multiple On or Off states of each/any combination inside the EEPROM memory in different locations for later recall, edit and save again based on the selected memory address?
Thank you again.
Naser
That’s the easy way.
My teacher want the hard way…
You don’t need EEPROM for that… just save it to a variable.
Hallo
I have 4 DC motors with one potentiometer each. I read the values of pot from analog pins A0 A1 A2 A3. I want to save 5-6 values of each in and call them by group of four (A0-3) and drive the motors with these values.
How can I do that with eprom?
Any suggestion?
The value will not lost if you store the value correctly. Note that ADC result is 10 bit.. while EEPROM are 8 bits.
my program reads adc channel and if a button is pressed , that value is stored in eeprom . but when i press the button and then cut the power and put it up again the value is lost
I don’t understand what your problem is. How do you know that PIC’s EEPROM gets restarted ?
i have the same problem and i use internal EEPROM PIC 16F887
EEPROM ? or PIC ?
The above article is for using Internal EEPROM of PIC itself.
my eeprom always gets restarted, how can I solve that kind of problem?
You should split integer in to 2 (high significant and low significant 8 bits) and save it…
Hi, It works perfectly!! Thank you. How do I go about saving and recalling unsigned int (16bit)? form EEPROM?
Thanks for the feedback
Thank you so much ! For delivering this EXCELLENT tutorial. Hope you will post some more like that. Many Thanks !
Hi , I’m using EEPROM memory and interrupt as well , what is the final form of the register ????
If you need more data memory, better use external EEPROM..
In interest of lowering the complexity and part count, I want to hit up the highly dense program memory. I need about 16K bytes of data space. I’m having issues finding a MCU under $1 with that density of EEPROM on board… Self Writing seems like the way to go?
Yes… but to log sensor data you don’t need to use program flash memory.. use EEPROM data memory… It can be read or write when the device is write protected too..
So, can you read and write to program memory during execution if it is not write protected? So if i get a 32KB MCU and can use that to log sensor data?