Maker Pro
Maker Pro

External I2C EEPROM Interfacing with PIC18F4550

i'm using AT24C04 I2C EEPROM ,i want to write 48 bytes into EEPROM but internally EEPROM organized to max 16bytes of each page write.
i can possible to write 16bytes in first...My doubt is ...How to write 16bytes into another page...
My code is here...
MAIN.C
#include <p18f4550.h>
#include "I2C_EEPROM.h"
#include <i2c.h>

// CONFIG1L
#pragma config PLLDIV = 5 // PLL Prescaler Selection bits (Divide by 5 (20 MHz oscillator input))
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])
// CONFIG1H
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator, PLL enabled (HSPLL))
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
// CONFIG2L
#pragma config BOR = ON // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
// CONFIG2H
#pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
// CONFIG3H
#pragma config PBADEN = OFF // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config MCLRE = OFF // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
// CONFIG4L
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config ICPRT = OFF // Dedicated In-Circuit Debug/Programming Port (ICPORT) Enable bit (ICPORT disabled)
// CONFIG5L
#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM is not code-protected)
//#pragma config DUBUG = ON
#define PAGESIZE 16

void InitI2C(void);
void I2CEeprom(void);
void PollI2CEeprom (void);
void Error(void);

unsigned int PageSize = 16;
unsigned char eeprom_address = 0xA0;
unsigned int EepAdd = 0x01; // address

unsigned char WrData[] = {0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
unsigned char RdData[PAGESIZE] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};


void main(void)
{
unsigned char delay;

InitI2C();

I2CEeprom();

// incase of successful operation control reach here..
TRISDbits.TRISD2= 0;
while (1)
{
LATDbits.LATD2= ~(LATDbits.LATD2);// toggle RD2
delay = 0x50;
while(delay--);
}
}

void InitI2C(void)
{
TRISBbits.TRISB1 = 1; // SCL dir input
TRISBbits.TRISB0 = 1; // SDA dir input

PIR1bits.SSPIF = 0; // clear interrupt flag
SSPSTAT = 0x00;
SSPADD = 0x31; // I2C baud = 100KHz @ Fosc = 20MHz
SSPCON2 = 0x00;
SSPCON1 = 0x28; // Master mode I2C
}

void I2CEeprom(void)
{
unsigned char i;
unsigned char length;

length = 16;
ForWrite(eeprom_address, EepAdd, WrData);
PollI2CEeprom();
ForRead(eeprom_address, EepAdd, RdData, length);
for(i=0; i<length; i++)
{
if(RdData != WrData)
{
Error();
}
}
}

void PollI2CEeprom (void)
{
while (1)
{
StartI2C();
IdleI2C();
WriteI2C( eeprom_address );
IdleI2C();

if (SSPCON2bits.ACKSTAT == 0)
{
StopI2C();
IdleI2C();
break;
}

StopI2C();
IdleI2C();
}
}

void Error(void)
{
unsigned char delay;

TRISDbits.TRISD1 = 0;

while (1)
{
LATDbits.LATD3= ~(LATDbits.LATD3);// toggle RD3
delay = 0x50;
while(delay--);
}
}
EEPROM.C

#include <p18f4550.h>
#include <i2c.h>
#include "I2C_EEPROM.h"


unsigned char ForWrite( unsigned char ControlByte, unsigned char LowAdd, unsigned char *wrptr )
{
IdleI2C(); // ensure module is idle
StartI2C(); // initiate START condition
while ( SSPCON2bits.SEN ); // wait until start condition is over
WriteI2C( ControlByte ); // write 1 byte - R/W bit should be 0
IdleI2C(); // ensure module is idle
WriteI2C( LowAdd ); // write LowAdd byte to EEPROM
IdleI2C(); // ensure module is idle
putstringI2C ( wrptr ); // pointer to data for page write
IdleI2C(); // ensure module is idle
StopI2C(); // send STOP condition
while ( SSPCON2bits.PEN ); // wait until stop condition is over
return ( 0 ); // return with no error
}


unsigned char ForRead( unsigned char ControlByte, unsigned char address, unsigned char *rdptr, unsigned char length )
{
IdleI2C(); // ensure module is idle
StartI2C(); // initiate START condition
while ( SSPCON2bits.SEN ); // wait until start condition is over
WriteI2C( ControlByte ); // write 1 byte
IdleI2C(); // ensure module is idle
WriteI2C( address ); // WRITE word address to EEPROM
IdleI2C(); // ensure module is idle
RestartI2C(); // generate I2C bus restart condition
while ( SSPCON2bits.RSEN ); // wait until re-start condition is over
WriteI2C( ControlByte | 0x01 ); // WRITE 1 byte - R/W bit should be 1 for read
IdleI2C(); // ensure module is idle
getsI2C( rdptr, length ); // read in multiple bytes
NotAckI2C(); // send not ACK condition
while ( SSPCON2bits.ACKEN ); // wait until ACK sequence is over
StopI2C(); // send STOP condition
while ( SSPCON2bits.PEN ); // wait until stop condition is over
return ( 0 ); // return with no error
}


unsigned char putstringI2C( unsigned char *wrptr )
{

unsigned char x;
for (x = 0; x < PageSize; x++ ) // transmit data until PageSize
{
if ( SSPCON1bits.SSPM3 ) // if Master transmitter then execute the following
{
if ( putcI2C ( *wrptr ) ) // write 1 byte
{
return ( -3 ); // return with write collision error
}
IdleI2C(); // test for idle condition
if ( SSPCON2bits.ACKSTAT ) // test received ack bit state
{
return ( -2 ); // bus device responded with NOT ACK
} // terminateputstringI2C() function
}
else // else Slave transmitter
{
PIR1bits.SSPIF = 0; // reset SSPIF bit
SSPBUF = *wrptr; // load SSPBUF with new data
SSPCON1bits.CKP = 1; // release clock line
while ( !PIR1bits.SSPIF ); // wait until ninth clock pulse received

if ( ( !SSPSTATbits.R_W ) && ( !SSPSTATbits.BF ) )// if R/W=0 and BF=0, NOT ACK was received
{
return ( -2 ); // terminateputstringI2C() function
}
}
wrptr ++; // increment pointer
} // continue data writes until null character
return ( 0 );
}
 
The address word is 8 bits long. When you do a page write the bottom 4 bits are autoincremented, but the upper 4 bits are not. When you send the address word you select the page by setting the upper bits to the appropriate page number. Be aware that the lower auto increment will wrap - so if you start writing at an address that has a non-zero bottom 4 bits and you write 16 bytes then then when the autoinc reaches zero for the 4 bits, it will start writing at the beginning of the same page.
 
Top