Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Pic I2C EEPROM problem.

Status
Not open for further replies.

HerbertMunch

New Member
Im trying to connect a pic18f4550 via i2c to a microchip 24fc64 EEprom.

Ive written two methods, one called WriteEEByte, and one called ReadEEBytes.
The write one should write 10 bytes to the eeprom, the read should read 10.

It SEEMS to work when i call my method WriteEEByte, but im not sure. I am trying to verify that the write was a success but code xecution gets stuck in the ReadI2C method.

It seems that the SSPIF bit never gets set to 1, so it just loops and loops.

Thanks for any help anyone can give.:)

Here is my I2C code.

Code:
//I2C
#include <p18f4550.h>

#define SSPIF   	PIR1bits.SSPIF			//Transmittion/receive complete if 1
#define ACKSTAT 	SSPCON2bits.ACKSTAT 	//Acknowledgement, 1 if no acknowledge from slave
#define RCEN		SSPCON2bits.RCEN     	//reception enabled --Master receive mode only
#define RSEN		SSPCON2bits.RSEN		//Restart enabled -- Cleared automatically
#define ACKEN		SSPCON2bits.ACKEN		//Transmit ack, ack or not ack depending on ACKDT bit
#define ACKDT		SSPCON2bits.ACKDT		//Determins whether (0) ACK or (1) NOT ack is sent to slave after receving data (MASTER TRANSMIT)
											//Sending a not ack tells slave to stop sending
#define SEN			SSPCON2bits.SEN			//Creates a start condition (master) or holds the clock (slave)
#define PEN			SSPCON2bits.PEN			//Sends a stop bit
typedef char byte;
typedef char bool;


void IdleI2C( void );

//Check whether i2c bus is idle
void IdleI2C( void )
{
  while ( ( SSPCON2 & 0x1F ) || ( SSPSTATbits.R_W ) )
     continue;
}

bool WriteI2C(byte* sendByte);
void StopI2C();

void StartI2C();

void StartI2C()
{
	IdleI2C();
	SEN = 1;//Create start condition
	
	while(SEN); //Wait while start condition sent
}
	
void StopI2C()
{
	IdleI2C();
	PEN =1;
	
	while(PEN); //Wait while stop bit is sent
}	

byte ReadI2C ();
void RestartI2C();	
void RestartI2C()
{
	IdleI2C();//Wait while i2c bus is idle
	RSEN = 1;
	
	while(RSEN);
}	
byte ReadI2C ()
{
	IdleI2C();//wait until idle
	SSPIF =0;
	RCEN = 1;
	while(SSPIF==0);
	SSPIF =0;
	return SSPBUF;
	
}
		
bool WriteI2C(byte* sendByte)
{
	IdleI2C();
	SSPIF = 0; //Reset send complete interrupt
	SSPBUF = *sendByte; //Move byte into buffer
	
	while(SSPIF);//loop until sent
	
	return !ACKSTAT;//ackstat is true if no ack for slave
	
		
	
}	

void AckI2C(bool notAck);

//Sends an ack or a not ack depeding on the value of the parameter
void AckI2C(bool notAck)
{
	ACKDT = notAck; //Set type of ack
	ACKEN = 1; 		//Send acknowledge
	
	while(ACKEN); //Wait until ack has been sent (bit cleared by hardware when done)
	
}	






//Writes a byte to the specified location
bool WriteEEByte(byte address,byte* data)
{
		byte i =0;
	//Set address
	SSPBUF = 0b10100000 ; //0 LSB = write
	IdleI2C(); //wait until idle
	WriteI2C(0x00);//Write higher address
	WriteI2C(&address); //Write lower address
	

	for (i=0;i<10;i++)
	{	
		WriteI2C(data);//Write 10 bytes of data to the eeprom
	

	}
	StopI2C(); //Send stop
}	


byte readBytes[10];

void ReadEEBytes(byte* address)
{
	byte* dest=readBytes;
	bool result=0;
	byte i =0;
	
	//Clear memory
	for (i =0;i<10;i++)
		*dest++ = 0;
		
	dest =readBytes;
		
			
	
	//Set address
	SSPBUF = 0b10100000 ; //0 LSB = write
	result=WriteI2C(0x00);//Write higher address
	result=WriteI2C(&address); //Write lower address
	RestartI2C();//Send start condition
	SSPBUF = 0b10100001 ; //1 LSB = read
	
	//now read 10 bytes
	for (i=0;i<10;i++)
	{	
		*dest++ = ReadI2C(); //Store byte in buffer
		AckI2C(0); 			 //Signal slave to send more
	

	}
	StopI2C(); //Send recieve
	
	dest =0;
}
 
Last edited:
Forgot to include my main method!

Code:
void main(void)
{
	ADCON1 =0x0F;
	PORTA=0x00;
	TRISA =0;
	LATA =0x01;

	TRISB = 0xff;
	//setupInterrupts();
	//Setup i2c
	SSPSTAT = 0b10000000;
	SSPCON1 = 0xff; //Reset register turn off ssp module
	SSPCON2 = 0b00000001; //Clock streching enable/ no masking
	SSPCON1 = 0b00111000; //Enable module, setup for master mode
	
	
	SSPCON2bits.SEN =1; //Enable module
	SSPADD = 0x13; //Set for 100khz operation @ 8mhz fosc
	

	
//	WriteEEByte(0x00,0x0F); //Write byte to eeprom
	ReadEEBytes(0x00);	
	while(1)
	{
	
	}	
}

Thanks
 
Pic I2C EEPROM problem

Hi Herbert,
take a look to Microchips's Application Note AN991. There is a complete code example. The routines will run, I use them as a template for coding all other device types.
Good luck
Erhard
 
I didn't think you could read the various bits (SEN etc.) to tell when the signal had been sent. I always check SSPIF to test for completion.

Here are my working I²C routines for the 4550,
Code:
#include <p18f4550.h>

void InitI2C();
void WaitSSP();
void SendStart();
void SendStop();
void SendRestart();
char SendByte(char);
char ReceiveByte();
void SendNack();
void SendAck();
char WriteByte(int,char);
char ReadByte(int);

//initialise the MSSP module
void InitI2C(){
    TRISBbits.TRISB0=1;
    TRISBbits.TRISB1=1;
    SSPCON1=0b00101000;
    SSPCON2=0;
    SSPSTAT=0b10000000;
    SSPADD=50;  //20000/(4*100);   //Fosc/(4*baud)
    PIR1bits.SSPIF=0;
    PIR2bits.BCLIF=0;
}

//Wait for the module to finish it's last action.
void WaitSSP(){
    while(PIR1bits.SSPIF==0);
    PIR1bits.SSPIF=0;
}

//send start bit
void SendStart(){
    SSPCON2bits.SEN=1;
    WaitSSP();
}

//Send stop bit.
void SendStop(){
    SSPCON2bits.PEN=1;
    WaitSSP();
}

//Send restart bit
void SendRestart(){
    SSPCON2bits.RSEN=1;
    WaitSSP();
}

//Send byte and return ack bit - 1=Ack  0=NAck
char SendByte(char Byte){
    SSPBUF=Byte;
    WaitSSP();
    return(!SSPCON2bits.ACKSTAT);
}

//Get a byte from the slave
char ReceiveByte(){
    SSPCON2bits.RCEN=1;
    WaitSSP();
    return(SSPBUF);
}

//Send a Not Acknowledge (NAck) to the slave
void SendNack(){
    SSPCON2bits.ACKDT=1;
    SSPCON2bits.ACKEN=1;
    WaitSSP();
}

//Send an Acknowledge (Ack) to the slave
void SendAck(){
    SSPCON2bits.ACKDT=0;
    SSPCON2bits.ACKEN=1;
    WaitSSP();
}

//Sends the start and device address.
//If the device is busy then it resends until accepted.
void SendID(char DeviceID){
    SendStart();
    if(SendByte(DeviceID)==1)
        return;
    do{
        SendRestart();
    }while(SendByte(DeviceID)==0);
}

//Write a byte to 24LC256
char WriteByte(int Address, char Byte){
    SendID(0b10100000);
    if(SendByte(Address>>8)==0)
        return(0);
    if(SendByte(Address&0xff)==0)
        return(0);
    if(SendByte(Byte)==0)
        return(0);
    SendStop();
    return(1);
}

//Read a byte from a 24LC256
char ReadByte(int Address){
char Byte;
    SendID(0b10100000);
    if(SendByte(Address>>8)==0)
        return(0);
    if(SendByte(Address&0xff)==0)
        return(0);
    SendRestart();
    if(SendByte(0b10100001)==0)
        return(0);
    Byte=ReceiveByte();
    SendNack();
    SendStop();
    return(Byte);
}

HTH

Mike.
 
Sorry ive been busy.
Thanks both of you, ill give the microchip note a read, and ill try your code mike.

Cheers
 
Last edited:
I didn't think you could read the various bits (SEN etc.) to tell when the signal had been sent. I always check SSPIF to test for completion......Mike.

Hi mike,
thanks for the code, it really helped me out. Ive found the problem: bool WriteI2C(byte* sendByte).

I had delcared sendByte as a pointer, but i wasnt passing a pointer to the method!

It turns out mate, that you can check SEN bits etc. the datasheet says "If the I2C module is active, these bits may not be set (no spooling) and the SSPBUF may not be written (or
writes to the SSPBUF are disabled)." It doesnt mention anything about not being able to read these bits.


Whats more the data sheet specifies (cryptically) that you should check these bits to see if the bus is idle.

Code:
//Check whether i2c bus is idle
void IdleI2C( void )
{


  while ( ( SSPCON2 & 0x1F ) || ( SSPSTATbits.R_W ) )
     continue;
}

I think that the SSPIF bit that you check, should only be checked when transmitting or receiving. All other times (i.e start,restart,etc) you should keep checking to see if the bit that you set (sen,etc) has been cleared yet, to see if the operation was a success.

Cheers
 
Last edited:
I think that the SSPIF bit that you check, should only be checked when transmitting or receiving. All other times (i.e start,restart,etc) you should keep checking to see if the bit that you set (sen,etc) has been cleared yet, to see if the operation was a success.
Cheers
I just changed a project of mine to check the SEN bit after it was set and it didn't work until I added the bcf PIR1,SSPIF. So yes, you can wait for the bit to be clear but you have to clear the IF bit after. It just seems easier to have the one routine to check for the last action completing.

Mike.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top