Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Write fails but Read successful in EEPROM using I2C protocol

Status
Not open for further replies.

sayonee

Newbie level 6
Joined
Nov 22, 2011
Messages
14
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,390
Hello there I have almost completed coding interfacing with EEPROM - AT24C04 using I2C protocol,But using this I am able to perform a "READ" operation but not a WRITE.

I am using a similar kind of program( found on this forum ) for interfacing the EEPROM using I2C and this program works.

This program that I found can do both READ/WRITE....But when I burn my program on the MC ..it cannot write but it can read the values stored at addresses 0x000,0x001,0x002 using the program found on this forum.
Attached to this post is my source code ..can someone let me know as to what mistake I am doing ...thanks

Code:
/*
  AT24C04 EERPOM HEADER FILE

*/
#include <reg51.h>
#include <intrins.h>
#include <stdlib.h>
#include <string.h>
#include "AT24C04-EEPROM.h"
#include "AT24C04-LCD.h"
#include "AT24C04-I2C.h"

void main()
{
	unsigned char value2,i;
	char *str1 = "SUCCESS";
	char *str2 = "FAIL";
	unsigned char *p;

	lcdinitialize();
	EEPROMwrite( 0x000,'Z' );
	lcddata('M');  
	value2 = EEPROMread( 0x000 );
	Delay(150);
	lcddata(value2);
}

Code:
/*
  AT24C04 I2C BUS HEADER FILE - ROUTINE/FUNCTION DECLARATIONS
*/

#ifndef __I2C_H
#define __I2C_H

void I2C_delay(void);		 	//Delay needed while doing I2C related coding

void I2C_clock(void);
						
void I2C_start(void);

void I2C_stop(void);

void I2C_write( unsigned char );

unsigned char I2C_read( void );

void I2C_ackpolling(void);

void I2C_check_NACK(void);

void I2C_ack(void);					  //master sending the acknowlege to slave

void I2C_nack(void);

#endif


Code:
#include <reg51.h>
#include <intrins.h>
#include "AT24C04-LCD.h"
#include "AT24C04-I2C.h"

sbit SDA = P3^6;	 			//refer circuit board schematics for the assignment of SDA & SCL
sbit SCL = P3^7;

bit NACK;						//bit FLAG to set status of NACK 

void I2C_delay(void)		 	//Delay needed while doing I2C related coding
{
 	_nop_();
}

void I2C_clock(void)
{
	//I2C_delay();
	SCL = 1;
	I2C_delay();
	SCL = 0;
}			
			
void I2C_start(void)
{
	SDA = 1;
	I2C_delay();
	SCL = 1;
	I2C_delay();
	SDA = 0;
	I2C_delay();
	SCL = 0;
	I2C_delay();
}

void I2C_stop(void)
{
	SCL = 1;
 	I2C_delay();
	SDA = 0;
	I2C_delay();
	SDA = 1;
	I2C_delay();
	SCL = 0;
}

/*void I2C_ackpolling(void)
{
 	SDA = 1;						//release SDA high 
	I2C_delay();
	SCL = 1;						//release SCL high for acknowledge,start clock
	I2C_delay();
	while( SDA );					//wait,loop while SDA = 1( HIGH ),if HIGH this means EEPROM is busy,will wait till it pulls SDA low
	SCL = 0;
} */

void I2C_check_NACK()
{
	SDA = 1;							 //release SDA high 
	I2C_delay();

	SCL = 1;							 //release SCL high for acknowledge,start clock
	I2C_delay();
 
	if( !SDA )							 //Check for acknowledge status from slave if SDA == 0,then ACK is 0 & OK from slave 
	{	
		SCL = 0;						 // pull down SCL,end the clock for acknowledge	
		I2C_delay();
		NACK = 0;
		//lcddata('R');
	}
	else							// SDA status is still HIGH so NACK ,i.e NACK is 1
	{
		SCL = 0;
		NACK = 1;					//ACK -acknowledge bit not received from EEPROM(receiver),EEPROM has pulled SDA high
		lcddata('W');				//to indicate on LCD of a possible ACK failure
	}
}

void I2C_write( unsigned char userdata )
{
	bit databit;				//bit variable for determining whether bit is 1 or 0
	unsigned char i;			//loop counter variable for a byte received
	unsigned char temp;
	//lcddata( userdata );
 	
	SCL = 0;
	for( i = 0; i<8 ;i++)
	{
	 	databit = SDA = userdata & 0x80;		 //store MSB in databit
		temp = (unsigned char )databit + 0x30;							 //assign it to the SDA 
		lcddata(temp);
		I2C_delay();					 //clock out the bit,do this for a byte
		I2C_clock();

		userdata = userdata << 1;		 // left shift to determine next MSB
	}
	
}

unsigned char I2C_read( void )
{
	bit read_bit;

	unsigned char received_data = 0x00,i;
	SDA = 1;
	SCL = 0;

	for( i = 0; i< 8 ;i++)
	{	
		
		SCL = 1; 			    //set SCL high,start of Clock,SCL = high here since before making it low the ACK is read in
		I2C_delay();
		received_data = received_data << 1;	  //left shit,MSB goes in first 
		received_data = received_data | (unsigned char )SDA;

		SCL = 0;						//set SCL low,end the clock
		//received_data = received_data | read_bit;		
	}
 

	SDA = 0;	  
//	received_data = received_data | read_bit;
	lcddata( received_data );


	//lcddata( received_data );
	return received_data;		
}


void I2C_ack(void)					  //master sending the acknowlege to slave
{
	SDA = 0;						 //clear SDA 
	I2C_delay();
									 //clock out
	I2C_clock();
	SDA = 1;
}


void I2C_nack(void)					  //master sending NACK to slave
{
	SDA = 1;						 //set SDA high
	I2C_delay();
	
	I2C_clock();
	
	SDA = 0; 						 //set SCL to default high
}

Code:
/*
  AT24C04 EEPROM HEADER FILE - ROUTINE/FUNCTION DECLARATIONS
*/

#ifndef __EEPROM_H
#define __EERPOM_H

#define EEPROM_ID 0xA0			//in binary this would be 10100000 for read,and 0xA1 = 10100001 for write

extern bit NACK;
extern SCL;
extern SDA;


unsigned char EEPROMread( unsigned char );

void EEPROMwrite( unsigned char ,unsigned char );

#endif


Code:
/*
  AT24C04 EERPOM C FILE

*/
#include <reg51.h>
#include <intrins.h>
#include "AT24C04-I2C.h" 					//HEADER FILE FOR I2C RELATED OPERATIONS
#include "AT24C04-EEPROM.h"
#include "AT24C04-LCD.h"

/*PLEASE REFER AT24C04 datasheet's PAGE 12 - FIGURE 11 FOR THIS RANDOM READ IMPLEMENTATION */


unsigned char EEPROMread( unsigned char eeprom_word_address )
{
	unsigned char received_data;

	NACK = 1;
	while(NACK)
	{
		I2C_start();

		I2C_write( EEPROM_ID );					//to identify the particular EEPROM device on I2C bus
		I2C_check_NACK();  					//call function to check for ACK/NACK and set the flag NACK
		if( NACK )
			continue;	
		lcddata('4');

		I2C_write( eeprom_word_address );		//write to the word address in that particular EEPROM  device
		I2C_check_NACK();  					//call function to check for ACK/NACK and set the flag NACK
		if( NACK )
			continue;
		lcddata('5');
	
		I2C_start();						//REPEATED START
	
		I2C_write( EEPROM_ID + 1 );			// EEPROM_ID+1, R/W bit is now 1 for READ,passed to indicate reading from EEPROM device
		I2C_check_NACK();  					//call function to check for ACK/NACK and set the flag NACK
		if( NACK )
			continue;	
		lcddata('6');
		
		received_data = I2C_read();			//read data from that particular word address 
		I2C_ack();			   				//SEND THE ACKNOWLEDGE TO TRANSMITTER - HERE TRANSMITTER IS EEPROM

		lcddata('7');
		//lcddata( received_data );	
	
		I2C_nack();					   		//MCU sending NOACK because no further reading is to be done,NACK necessary for STOPing condition
		
		I2C_stop();							// Stop I2C bus operations

	}
	return received_data;

}
	 
void EEPROMwrite( unsigned char eeprom_word_address,unsigned char store_data )
{	
	NACK = 1;						 //NACK intially set to 1 to make sure the while() loops execute,inside while loop it 
									// may be set to 0 if ACK from transmitter is 0 ..
	while( NACK )					//NACK global bit variable is set if no ACK in I2C routine..
	{
		I2C_start();						  	//start I2C bus operation

	   	//lcddata( EEPROM_ID );
		I2C_write( EEPROM_ID );				//get to interact the particular EEPROM device using its unique address
		I2C_check_NACK();  					//call function to check for ACK/NACK and set the flag NACK
		if( NACK )
			continue;	
		//lcddata('1');						   //PRINT SUCH VALUES TO LCD TO KNOW THE SEQUENCE OF STEPS HAPPENING
		
		I2C_write( eeprom_word_address );	  //send particular word address,where data from RAM is to be written in that EEPROM device
		I2C_check_NACK();  					//call function to check for ACK/NACK and set the flag NACK
		if( NACK )
			continue;	
		//lcddata('2');

		I2C_write( store_data );
		I2C_check_NACK();  					//call function to check for ACK/NACK and set the flag NACK
		if( NACK )
			continue;	 
		//lcddata('3');

		I2C_stop();							//stop I2C bus operations	 
	
	}
}
 

Man, why are you bit-banging I2C? Most MCUs have hardware module which can handle about 80% of the code you have posted in hardware...

What MCU are you using?
 

Hello Poorchava I am using P89V51RD2BN ...
 

the Write Protect pin on the readymade CIRCUIT is correct and connected to GND ...I am able to READ/WRITE with other program I found on this forum...But i decided to code my own to understand how things work ....Please check my code for any deceptive errors ....I have also tried googling for similar programs - they all work ...but its only mine which fails on WRITING !!! :( ...thanks
 

Possible, you forgot about write delay?
Code:
void main()
{
	unsigned char value2,i;
	char *str1 = "SUCCESS";
	char *str2 = "FAIL";
	unsigned char *p;

	lcdinitialize();
	EEPROMwrite( 0x000,'Z' );
           [COLOR="#FF0000"]Delay(150);[/COLOR] //6 ms dalay must be here!
	lcddata('M');  
	value2 = EEPROMread( 0x000 );
	Delay(150);
	lcddata(value2);
}
 

Hello Easyrider83 ...this Delay(150) didn't help ...may be I have to be careful about giving/removing Delays at some other places........Here is the program thats working all right ...strange I have almost followed the same logic ..but mine is more generic ..trying to build some libraries ..writing in more modular way...
Code:
#include "AT24C04-LCD.h"
#include <reg51.h>
#include <intrins.h>


sbit sda = P3^6;
sbit sclk = P3^7;

/************************** prototypes begin*******************/
void send_byte_s_eeprom(char );
void send_to_mem(unsigned char , unsigned char );
unsigned char get_byte_s_eeprom();
void noacknowledge();
void acknowledge();
unsigned char get_from_mem(unsigned char );
void wait();
void start_s_eeprom();
void stop_s_eeprom();
/************************** prototypes end******************/



void send_to_mem(unsigned char s_address, unsigned char s_data)
 {
    start_s_eeprom();             // sending start condition to eeprom 
    send_byte_s_eeprom(0XA0);     // A0 = 10100000 = sending device address word for write
    acknowledge();
    send_byte_s_eeprom(s_address); // sending data address
    acknowledge();
    send_byte_s_eeprom(s_data);   // sending data 
    acknowledge();
    stop_s_eeprom();              // sending stop condition to eeprom
//    acknowledge();
    
 }


// fxn to get the data back frm the serial eeprom
// just give the adress from where the data is to be retrieved


unsigned char get_from_mem(unsigned char s_address)
{
 unsigned char i;
//-------dummy write seq----+ word address--------------------------------------
    start_s_eeprom();              // sending start condition to eeprom 
    send_byte_s_eeprom(0XA0);      // sending A0 = 10100000 = device address word for write
    acknowledge();
    send_byte_s_eeprom(s_address); // sending data address
    acknowledge();
//----------------dummy over----------------------------------------------------

    start_s_eeprom();
    send_byte_s_eeprom(0XA1);     // sending A1 =10100001 = device adress word for read
    acknowledge();
    i = get_byte_s_eeprom();       // sending data 
    noacknowledge();
    stop_s_eeprom();              // sending stop condition to eeprom

   return(i); 
 }


/* fxn to transmit a byte to the eeprom
this fxn just send the 8 bits serialy on the SDA line
just pass the byte to be transmitted as parameter to this fxn */
void send_byte_s_eeprom(char s_byte)
{
    //unsigned  char temp ;
    char i ;

    
    for(i = 7 ; i >= 0 ; i--) //scan data do be place in SDA
    {
     /* note SCL is low during transitions on SDA */
        if( ((s_byte >> i) & 0x01) == 0) //check individual bits
        sda =   0;
        else
        sda =   1;

        sclk   =   1;
        wait();
        sclk   =   0;
       
    }
}
 
 

// fxn to receive 8 bits serialy from sda line
// this is not a fxn to read from eeprom
// it just receives 8 bits serialy and retuns the byte received to the calling fxn

unsigned char get_byte_s_eeprom()
 {
    char temp, temp_h, i;
    temp = 0;
    temp_h = 1;    

    sda = 1;    // making SDA as input pin for microcontroller
      sclk    =    0;

    for(i = 7; i >=0 ; i--)
    {
        sclk = 1;
     
        if(sda == 1)
        {
            temp = temp | temp_h<<i ;                      
        }
        wait();
        sclk = 0;

    }
    
    sclk = 0;
    return(temp);
 }


// fxn to send the start condition
 void start_s_eeprom()
 {
    sda     =   1;
    sclk    =   1;
    wait();
    sda     =   0;
    sclk    =   0;  

 }


// fxn to send stop condition
 void stop_s_eeprom()
 {
    sda     =   0;
    sclk    =   1;
    wait();
    sda     =   1;
    sclk    =   0;  
 }


// fxn for acknowledging the eeprom
// this fxn actualy does not read the acknowledge signal
// it just waits for sufficient time and assumes that the eeprom has given tha ack by the time the wait gets over
 void acknowledge()
 {
       
     sda  = 0;
     sclk = 1;
       wait();
    sclk = 0;
 }


//  a small delay fxn to ensure the line settles down after transition
 void wait()
 {
    //char i;
    //for(i=0;i<=20;i++)
    //i++;

 }

void noacknowledge()
{   
     sda  = 1;
     sclk = 1;
       wait();
    sclk = 0;
}  


void main()
{
	lcdinitialize();
	//send_to_mem(0x002,'X');
	Delay(150);
	lcddata(get_from_mem(0x000));

}

Code:
/*
  AT24C04 LCD HEADER FILE - ROUTINE/FUNCTION DECLARATIONS
*/
#include <reg51.h>

#ifndef __LCD_H
#define __LCD_H




//SFR names declarations
sfr lcd_port = 0x90;  		//address of PORT P1 ,used for data lines to LCD
sbit EN = P3^4;
sbit RS = P3^5;

//sbit RW = 

//ANSI STYLE PROTOTYPE
void lcddata( unsigned char value);

void lcdcmd( unsigned char value);

void Delay( unsigned int itime );

void lcdinitialize(void);

#endif

Code:
	#include "AT24C04-LCD.h"
	#include <intrins.h>


	void Delay( unsigned int itime)
	{
		int i,j;
		for( i = 0; i < itime ;i++)
			for( j = 0; j < 1275; j++);
	}

	void lcdcmd( unsigned char value )
	{
		  lcd_port = value;
		  RS = 0;		//register select = 0 for command mode
		  EN = 1; 		//latch enable = HIGH
		  _nop_();
		  EN = 0;		//latch enable = LOW
		  Delay(10);
		  return;
	}

	void lcddata( unsigned char value )
	{
		  lcd_port = value;
		  RS = 1;		//register select = 1 for data register
		  EN = 1; 		//latch enable = HIGH
		  _nop_();
		  EN = 0;		//latch enable = LOW
		  Delay(30);
		  return;
	}

	void lcdinitialize(void)
	{
		unsigned char l[10] = {0x38,0x0E,0x06,0x01,0x41};
		unsigned char i;
			for(i = 0 ;i <= 3 ; i++)
			lcdcmd(l[i]);		//sending basic LCD commands to LCD
	}
 

Hi sayonee. Can you scope the I2C lines to see if your getting any NACK where you shouldn't be? Or maybe you could add to your code
if( NACK )
{
lcddata('x');
continue;
}


use:
lcddata('y');
lcddata('z');

for the different locations where NACK is checked. This might narrow done where the issue is.
 

Hi sayonee. Can you scope the I2C lines to see if your getting any NACK where you shouldn't be? Or maybe you could add to your code
if( NACK )
{
lcddata('x');
continue;
}


use:
lcddata('y');
lcddata('z');

for the different locations where NACK is checked. This might narrow done where the issue is.


Hello Joeyla ...I have just modified the code for debugging Nack...I included the lcddata('X'); statements in if condition and these values for WRITE operation don't get printed on LCD ...this means the NACK is not set ...we are receiving the ACK properly .... its really strange and frustrating that other code works flawlessly whereas its only mine which is READing the values burnt in EEPROM by other code but failing to WRITE ...

can make it out where that deceptive error could be.... is it with the DELAY factor ??? ...please let me know ..thanks for you help ...regards
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top