Keil Logo Arm Logo

Discussion Forum

Problem when implement i2c interface between AT24C04 EEPROM with 8051

Next Thread | Thread List | Previous Thread Start a Thread | Settings

Details Message
Read-Only
Author
Jonh Bob
Posted
9-Aug-2005 03:22 GMT
Toolset
C51
New! Problem when implement i2c interface between AT24C04 EEPROM with 8051
Hello!
I have write a program to write and read to/from AT24c04 serial ROM (89C52 interface with AT24C04). I am using Keil C to program.

But i can read any data which i have write to AT24c04.
I don't know exacterly why.

My purpose is very simple. I listent from USART and get data from PC key board. If the character which i get from pc is 'w' or 'W' then i do get data from PC and write to AT24c04 until i get the 0x0D. Now if i get the 'r' or 'R' character from PC i read data which i have just write to AT24c04 and send back to PC.
But i can't read any.

Here is my code

#include <REG52.h>

unsigned char data DEVICEADD;

sbit SDA = P1^0;
sbit SCL = P1^1;

int data c;
char data wrom;
char data rrom;


void outchar(char data chr)
{
while(!TI)
{
}
TI = 0;
SBUF = chr;
}

void outstr(char* str)
{
while(*str != 0)
{
outchar(*str++);
}
}
char i2c_start(void)
{
/*
if(!SDA || !SCL)
return 0; // i2c_start error: bus not free
*/
// Both bus lines are high,
SDA = 0; // so set data line low to generate a start condition.
SCL = 0;
/*
SDA = 1;
SCL = 1;
SDA = 0;
SCL = 0;
*/
return 1;
}

void i2c_stop(void)
{
/*
SDA = 0;
SCL = 1;
SDA = 1;
*/
unsigned char input_var;
SCL = 1;
SDA = 0;
SCL = 1;
SDA = 1;
input_var = SDA;
}

// return ack value: 0 for fale; 1 for success
char i2c_write(char data byte)
{
int data i;
for(i = 0; i < 8 ; i++)
{
SDA = ((byte & 0x80) ? 1 : 0);
SCL = 1; // Ensure that the data is stable during the high period.
byte <<= 1;
SCL = 0;
}
// Get ack
SDA = 1;
SCL = 1;
i = SDA;
//i = 500;
SCL = 0;
/*
while(i-- && SDA)
{
}
*/
return !i; // Get data at end of cycle.
}

char i2c_writebyte(int data address, char data byte)
{
if(!i2c_start())
{
outstr("i2c_start error: bus not free.\n");
return 0;
}
if(!i2c_write(DEVICEADD))
{
i2c_stop();
i2c_start();
if(!i2c_write(DEVICEADD)) // Interface failed to acknowledge device address
{
i2c_stop();
outstr("Interface failed to acknowledge device address.\n");
return 0;
}
}

if(!i2c_write(address >>8)) // Interface failed to acknowledge byteH address
{
i2c_stop();
outstr("Interface failed to acknowledge byteH address.\n");
return 0;
}
if(!i2c_write(address)) // Interface failed to acknowledge byteL address
{
i2c_stop();
outstr("Interface failed to acknowledge byteL address.\n");
return 0;
}
if(!i2c_write(byte)) // Interface failed to acknowledge data
{
i2c_stop();
outstr("Interface failed to acknowledge data.\n");
return 0;
}
i2c_stop();
return 1; // success
}

char i2c_read(char data ACK)
{
char index, byte;
index = SDA; // Put data pin into read mode
byte = 0x00;
for(index = 0; index < 8; index++) // Send 8 bits to the I2C Bus
{
byte <<= 1;
SCL = 1; // Clock the data into the I2C Bus
byte |= SDA; // Input the data from the I2C Bus
SCL = 0;
}

// Write ack bit
SDA = ACK;
SCL = 1; // Ensure that the data is stable during the high period.
SCL = 0;
return byte;
}

char i2c_readbyte(int data address)
{
char data byte;
if(!i2c_start())
{
outstr("i2c_start error: bus not free.\n");
return 0;
}
if(!i2c_write(DEVICEADD))
{
i2c_stop();
i2c_start();
if(!i2c_write(DEVICEADD)) // Interface failed to acknowledge device address
{
i2c_stop();
outstr("Interface failed to acknowledge device address.\n");
return 0;
}
}

// Transmit address to read from.
if(!i2c_write(address >> 8)) // Interface failed to acknowledge byteH address
{
i2c_stop();
outstr("Interface failed to acknowledge byteH address. \n");
return 0;
}
if(!i2c_write(address)) // Interface failed to acknowledge byteL address
{
i2c_stop();
outstr("Interface failed to acknowledge byteL address. \n");
return 0;
}

// Now terminate write operation and do a read.
if(!i2c_start())
{
outstr("i2c_start error: bus not free.\n");
return 0;
}
// Transmit address to read from.
if(!i2c_write(DEVICEADD | 1)) // Slave failed to ack read access
{
i2c_stop();
outstr("Slave failed to ack read access.\n");
return 0;
}
// Read from address and ack = 1.
byte = i2c_read(1);
i2c_stop();
return byte;
}

char get_char()
{
while(!RI)
{
}
RI = 0;
return SBUF;
}


void WriteData()
{
char data ch;
ch = get_char();
while(ch != 0x0D)
{
i2c_writebyte(c++,ch);
outchar(ch);
ch = get_char();
}
wrom = 0;
ES = 1;
}

void ReadData()
{
char data index;
char data input;
for(index = 0; index < c; index++)
{
input = i2c_readbyte(index);
if(input != 0)
outchar(input);
}
c = 0;
rrom = 0;
ES = 1;
}

void main(void)
{
// Init serial
SCON = 0x52;
// Set timer1 mode and reload value
TMOD &= ~0xF0; // clear timer 1 mode bits
TMOD |= 0x20; // put timer 1 into MODE 2 8 bit auto reload
TH1 = 0xFD;
TR1 = 1; // start timer 1
TI = 0;
ES = 1; // Enable Serial interrupt
EA = 1; // Enable all interrupts

c = 0;
rrom = 0;
wrom = 0;
DEVICEADD = 0xA0; // 10100000B
while(1)
{
if(wrom == 1)
{
outchar('W');
WriteData();
}
if(rrom == 1)
{
outchar('R');
ReadData();
}
/*
count = get_char();
outchar(count);
*/
}
}

void serial (void) interrupt 4 using 3
{
char data inp;
if(RI) // Received data interrupt
{
RI = 0;
inp = (char)SBUF;
if((inp == 'w') || (inp == 'W'))
{
ES = 0;
rrom = 0;
c = 0;
TI = 1;
wrom = 1;
}
else if((inp == 'r') || (inp == 'R'))
{
ES = 0;
wrom = 0;
TI = 1;
rrom = 1;
}
}
else if(TI) // Transmitted data interrupt
{
TI = 0;
}
}

Could you help me ?
Read-Only
Author
A.W. Neil
Posted
9-Aug-2005 07:38 GMT
Toolset
C51
New! RE: Problem when implement i2c interface between AT24C04 EEPROM with 8051
Please see the instructions for posting code:
http://www.keil.com/forum/tips.asp
then re-post your code.
Read-Only
Author
Jonh Bob
Posted
9-Aug-2005 07:55 GMT
Toolset
C51
New! RE post Problem when implement i2c interface between AT24C04 EEPROM with 8051
Hello!
I have write a program to write and read to/from AT24c04 serial ROM (89C52 interface with AT24C04). I am using Keil C to program.

But i can read any data which i have write to AT24c04.
I don't know exacterly why.

My purpose is very simple. I listent from USART and get data from PC key board. If the character which i get from pc is 'w' or 'W' then i do get data from PC and write to AT24c04 until i get the 0x0D. Now if i get the 'r' or 'R' character from PC i read data which i have just write to AT24c04 and send back to PC.
But i can't read any.

Here is my code

#include <REG52.h>

unsigned char data DEVICEADD;

sbit SDA = P1^0;
sbit SCL = P1^1;

int data c;
char data wrom;
char data rrom;


void outchar(char data chr)
{
while(!TI)
{
}
TI = 0;
SBUF = chr;
}

void outstr(char* str)
{
while(*str != 0)
{
outchar(*str++);
}
}
char i2c_start(void)
{
/*
if(!SDA || !SCL)
return 0; // i2c_start error: bus not free
*/
// Both bus lines are high,
SDA = 0; // so set data line low to generate a start condition.
SCL = 0;
/*
SDA = 1;
SCL = 1;
SDA = 0;
SCL = 0;
*/
return 1;
}

void i2c_stop(void)
{
/*
SDA = 0;
SCL = 1;
SDA = 1;
*/
unsigned char input_var;
SCL = 1;
SDA = 0;
SCL = 1;
SDA = 1;
input_var = SDA;
}

// return ack value: 0 for fale; 1 for success
char i2c_write(char data byte)
{
int data i;
for(i = 0; i < 8 ; i++)
{
SDA = ((byte & 0x80) ? 1 : 0);
SCL = 1; // Ensure that the data is stable during the high period.
byte <<= 1;
SCL = 0;
}
// Get ack
SDA = 1;
SCL = 1;
i = SDA;
//i = 500;
SCL = 0;
/*
while(i-- && SDA)
{
}
*/
return !i; // Get data at end of cycle.
}

char i2c_writebyte(int data address, char data byte)
{
if(!i2c_start())
{
outstr("i2c_start error: bus not free.\n");
return 0;
}
if(!i2c_write(DEVICEADD))
{
i2c_stop();
i2c_start();
if(!i2c_write(DEVICEADD)) // Interface failed to acknowledge device address
{
i2c_stop();
outstr("Interface failed to acknowledge device address.\n");
return 0;
}
}

if(!i2c_write(address >>8)) // Interface failed to acknowledge byteH address
{
i2c_stop();
outstr("Interface failed to acknowledge byteH address.\n");
return 0;
}
if(!i2c_write(address)) // Interface failed to acknowledge byteL address
{
i2c_stop();
outstr("Interface failed to acknowledge byteL address.\n");
return 0;
}
if(!i2c_write(byte)) // Interface failed to acknowledge data
{
i2c_stop();
outstr("Interface failed to acknowledge data.\n");
return 0;
}
i2c_stop();
return 1; // success
}

char i2c_read(char data ACK)
{
char index, byte;
index = SDA; // Put data pin into read mode
byte = 0x00;
for(index = 0; index < 8; index++) // Send 8 bits to the I2C Bus
{
byte <<= 1;
SCL = 1; // Clock the data into the I2C Bus
byte |= SDA; // Input the data from the I2C Bus
SCL = 0;
}

// Write ack bit
SDA = ACK;
SCL = 1; // Ensure that the data is stable during the high period.
SCL = 0;
return byte;
}

char i2c_readbyte(int data address)
{
char data byte;
if(!i2c_start())
{
outstr("i2c_start error: bus not free.\n");
return 0;
}
if(!i2c_write(DEVICEADD))
{
i2c_stop();
i2c_start();
if(!i2c_write(DEVICEADD)) // Interface failed to acknowledge device address
{
i2c_stop();
outstr("Interface failed to acknowledge device address.\n");
return 0;
}
}

// Transmit address to read from.
if(!i2c_write(address >> 8)) // Interface failed to acknowledge byteH address
{
i2c_stop();
outstr("Interface failed to acknowledge byteH address. \n");
return 0;
}
if(!i2c_write(address)) // Interface failed to acknowledge byteL address
{
i2c_stop();
outstr("Interface failed to acknowledge byteL address. \n");
return 0;
}

// Now terminate write operation and do a read.
if(!i2c_start())
{
outstr("i2c_start error: bus not free.\n");
return 0;
}
// Transmit address to read from.
if(!i2c_write(DEVICEADD | 1)) // Slave failed to ack read access
{
i2c_stop();
outstr("Slave failed to ack read access.\n");
return 0;
}
// Read from address and ack = 1.
byte = i2c_read(1);
i2c_stop();
return byte;
}

char get_char()
{
while(!RI)
{
}
RI = 0;
return SBUF;
}


void WriteData()
{
char data ch;
ch = get_char();
while(ch != 0x0D)
{
i2c_writebyte(c++,ch);
outchar(ch);
ch = get_char();
}
wrom = 0;
ES = 1;
}

void ReadData()
{
char data index;
char data input;
for(index = 0; index < c; index++)
{
input = i2c_readbyte(index);
if(input != 0)
outchar(input);
}
c = 0;
rrom = 0;
ES = 1;
}

void main(void)
{
// Init serial
SCON = 0x52;
// Set timer1 mode and reload value
TMOD &= ~0xF0; // clear timer 1 mode bits
TMOD |= 0x20; // put timer 1 into MODE 2 8 bit auto reload
TH1 = 0xFD;
TR1 = 1; // start timer 1
TI = 0;
ES = 1; // Enable Serial interrupt
EA = 1; // Enable all interrupts

c = 0;
rrom = 0;
wrom = 0;
DEVICEADD = 0xA0; // 10100000B
while(1)
{
if(wrom == 1)
{
outchar('W');
WriteData();
}
if(rrom == 1)
{
outchar('R');
ReadData();
}
/*
count = get_char();
outchar(count);
*/
}
}

void serial (void) interrupt 4 using 3
{
char data inp;
if(RI) // Received data interrupt
{
RI = 0;
inp = (char)SBUF;
if((inp == 'w') || (inp == 'W'))
{
ES = 0;
rrom = 0;
c = 0;
TI = 1;
wrom = 1;
}
else if((inp == 'r') || (inp == 'R'))
{
ES = 0;
wrom = 0;
TI = 1;
rrom = 1;
}
}
else if(TI) // Transmitted data interrupt
{
TI = 0;
}
}
Could you help me ?
Read-Only
Author
A.W. Neil
Posted
9-Aug-2005 09:37 GMT
Toolset
C51
New! RE: RE post Problem when implement i2c interface between AT24C04 EEPROM with 8051
Oh dear - do you actually write your code like that?

It is customary to lay-out your code with indenting, etc, so that the "structure" is quickly visible.
Of course, this makes absolutely no difference whatsoever to the compiler - but it will be a great help to you in following and understanding your code.

It will also be a great help if you want anyone else to look at your code...

The code in your exisiting post here could do with the same treatment:
http://www.8052.com/forum/read.phtml?id=98834
Read-Only
Author
erik malund
Posted
9-Aug-2005 16:07 GMT
Toolset
C51
New! RE: RE post Problem when implement i2c interface between AT24C04 EEPROM with 8051
It will also be a great help if you want anyone else to look at your code...

If someone were to pay me to look at the above code, I would say "no thanks".

So, I have absolutely no intention of even glancing at unformatted code for free.

Erik
Read-Only
Author
Stefan Duncanson
Posted
9-Aug-2005 17:03 GMT
Toolset
C51
New! RE: RE post Problem when implement i2c interface between AT24C04 EEPROM with 8051
"But i can read any data which i have write to AT24c04.
I don't know exacterly why."

You're trying to mix interrupt driven and polled serial comms. It would be much easier to stick with one or the other, for what you are doing I think polled would be quite adequate.

Try and get the program working bit by bit - you could sort out the serial comms first by responding with known data rather than stuff read out of the EEPROM, for instance. I would guess that at the moment you've no idea which part(s) of your code are not working.
Read-Only
Author
A.W. Neil
Posted
9-Aug-2005 19:14 GMT
Toolset
C51
New! It's that deja vu feeling all over again...!
"Try and get the program working bit by bit..."

He has already been given exactly the same advice in his earlier post:
http://www.8052.com/forum/read.phtml?id=98987
Read-Only
Author
Jonh Bob
Posted
10-Aug-2005 07:52 GMT
Toolset
C51
New! RE: It's that deja vu feeling all over again...!
I had do as your advice, but i can read any things.

I don't know why, even i has make a program write by c# read/write from/to 24c04 interface with PC via Serail Port. It's work ok.

but when i implement in Keil C to using in some small project then it isn't working.
Read-Only
Author
A.W. Neil
Posted
10-Aug-2005 08:21 GMT
Toolset
C51
New! RE: It's that deja vu feeling all over again...!
"I had do as your advice, but i can read any things."

So why didn't you show what you'd done, and ask for further help with that?

A nice, compact piece of code is not only easier for you to debug, but also for others to help you with!

So, go on - show the simple code, explain carefully what it's meant to do, what it actually does, and what you've done so far to debug it.

Note that interfacing an I2C EEPROM to an 8051 is a very, very common thing - there are loads of examples all over the internet (including here). Have you checked the device manufacturer for sample code, or looked at any other examples?
Read-Only
Author
Jonh Bob
Posted
10-Aug-2005 10:41 GMT
Toolset
C51
New! RE: It's that deja vu feeling all over again...!
#include <REG52.h>
#include <intrins.h>

unsigned char data DEVICEADD;

sbit SDA = P1^0;
sbit SCL = P1^1;

// Delay for one miliseconnd
void time1ms(void)
{
	unsigned char c;

	for(c = 0;c < 200;c++)
	{
		_nop_();
	}
}

// Delay function, delay time in millisecond
void delay(int data i)
{
	data int time;

	for(time = 0;time < i;time++)
	{
		time1ms();
	}
}

// Send a character to PC
void outchar(char data chr)
{
	while(!TI)
	{
	}
	TI = 0;
	SBUF = chr;
}


// Send a string to PC
void outstr(char* str)
{
	while(*str != 0)
	{
		outchar(*str++);
	}
}
char i2c_start(void)
{
	SDA = 1;
	SCL = 1;
	SDA = 0;
	SCL = 0;
	return 1;
}
void i2c_stop(void)
{
	unsigned char input_var;
	SCL = 1;
	SDA = 0;
	SCL = 1;
	SDA = 1;
	input_var = SDA;
}

// return ack value: 0 for fale; 1 for success
char i2c_write(char data byte)
{
	int data i;
	for(i = 0; i < 8 ; i++)
 	{
		SDA = ((byte & 0x80) ? 1 : 0);
		SCL = 1;               // Ensure that the data is stable during the high period.
		byte  <<= 1;
  		SCL = 0;
	}
	// Get ack
	SDA = 1;
	SCL = 1;
	i = SDA;
	SCL = 0;
	return !i;  // Get data at end of cycle.
}

// Write a byte to @4C04 at address
char i2c_writebyte(int data address, char data byte)
{
	if(!i2c_start())
	{
		outstr("i2c_start error: bus not free.\n");
			return 0;
	}
	if(!i2c_write(DEVICEADD))
	{
		i2c_stop();
		i2c_start();
		if(!i2c_write(DEVICEADD))	// Interface failed to acknowledge device address
		{
			i2c_stop();
			outstr("Interface failed to acknowledge device address.\n");
			return 0;
		}
	}

	if(!i2c_write(address >>8)) // Interface failed to acknowledge byteH address
	{
		i2c_stop();
		outstr("Interface failed to acknowledge byteH address.\n");
		return 0;
	}
	if(!i2c_write(address))	// Interface failed to acknowledge byteL address
	{
		i2c_stop();
		outstr("Interface failed to acknowledge byteL address.\n");
		return 0;
	}
  	if(!i2c_write(byte))	// Interface failed to acknowledge data
	{
		i2c_stop();
		outstr("Interface failed to acknowledge data.\n");
		return 0;
	}
	i2c_stop();
	return 1;	// success
}
char i2c_read(char data ACK)
{
	char index, byte;
   	index = SDA;							// Put data pin into read mode
	byte = 0x00;
	for(index = 0; index < 8; index++)  	// Send 8 bits to the I2C Bus
	{
		byte <<= 1;
		SCL = 1;           				// Clock the data into the I2C Bus
      	byte |= SDA; 		   		// Input the data from the I2C Bus
		SCL = 0;
	}

	// Write ack bit
	SDA = ACK;
  	SCL = 1;               // Ensure that the data is stable during the high period.
	SCL = 0;
	return byte;
}
// Red a byte from 24c04 at address
char i2c_readbyte(int data address)
{
	char data byte;
	if(!i2c_start())
	{
		outstr("i2c_start error: bus not free.\n");
			return 0;
	}
	if(!i2c_write(DEVICEADD))
	{
		i2c_stop();
		i2c_start();
		if(!i2c_write(DEVICEADD))	// Interface failed to acknowledge device address
		{
			i2c_stop();
			outstr("Interface failed to acknowledge device address.\n");
			return 0;
		}
	}

	// Transmit address to read from.
  	if(!i2c_write(address >> 8)) // Interface failed to acknowledge byteH address
	{
		i2c_stop();
		outstr("Interface failed to acknowledge byteH address. \n");
		return 0;
	}
	if(!i2c_write(address))	// Interface failed to acknowledge byteL address
	{
		i2c_stop();
		outstr("Interface failed to acknowledge byteL address. \n");
		return 0;
	}

  	// Now terminate write operation and do a read.
	if(!i2c_start())
	{
		outstr("i2c_start error: bus not free.\n");
			return 0;
	}
	// Transmit address to read from.
	if(!i2c_write(DEVICEADD | 1))	// Slave failed to ack read access
	{
		i2c_stop();
		outstr("Slave failed to ack read access.\n");
		return 0;
	}
    // Read from address and ack = 1.
  	byte = i2c_read(1);
  	i2c_stop();
	return byte;
}
// Write a string to 24c04
void WriteToROM(char* str)
{
	char data index = 0;
	while(*str != 0)
	{
		i2c_writebyte(index++,*str++);
	}
}

// My purpose is very simple, i send Hello string to ROM and delay for 200 milisecond and read back from rom and send to PC and loop forever

void main(void)
{
	char data index;
	char data byte;
	// Init serial 9600 baud, 8 bit, enable receive...
	SCON  = 0x52;
	// Set timer1 mode and reload value
	TMOD &= ~0xF0; // clear timer 1 mode bits
	TMOD |= 0x20;  // put timer 1 into MODE 2 8 bit auto reload
	TH1 = 0xFD;
	TR1 = 1; // start timer 1
	DEVICEADD = 0xA0;	// 10100000B
	while(1)
	{
			// Write Hello to ROM
		WriteToROM("Hello");
		delay(200); // delay for 200 milisecond
		// Read data back from rom
		for(index = 0; index < 4; index++)
		{
			byte = i2c_readbyte(index);
	  		outchar(byte);
		}
		delay(200); // delay for 200 milisecond
	}
}

Read-Only
Author
erik malund
Posted
10-Aug-2005 14:32 GMT
Toolset
C51
New! RE: RE post Problem when implement i2c interface between AT24C04 EEPROM with 8051
just a glance revealed these two

char i2c_readbyte(int data address)
{
char data byte;

If this actually were to compile you would have a conflict between " int data" and "char data".

Did you retype the program into the post????

It is typical that the response to a post get all wrong when the code is retyped because unavoidable errors in retyping. Use cut-and-paste and, please a program that compiles without errors - unless, of course, you are asking about a compile error.

Erik

anyhow, you can find much help here:
The best (and most) IIC appnotes:
http://www.semiconductors.philips.com/buses/i2c/support/index.html , Do not "reject" an appnote because it refer to a specific derivative, if the derivative discussed does not have hardware IIC the code will work on any.
Read-Only
Author
Stefan Duncanson
Posted
10-Aug-2005 16:50 GMT
Toolset
C51
New! RE: RE post Problem when implement i2c interface between AT24C04 EEPROM with 8051
"char i2c_readbyte(int data address)
{
char data byte;

If this actually were to compile you would have a conflict between " int data" and "char data"."

You would actually get a warning that the memory space specifier on the function parameter would be ignored. This would have absolutely no effect on the function of the program.

I don't know what this conflict between 'int data' and 'char data' you are talking about is supposed to be.

"It is typical that the response to a post get all wrong when the code is retyped because unavoidable errors in retyping. Use cut-and-paste and, please a program that compiles without errors - unless, of course, you are asking about a compile error."

It does compile without errors. It's nice to hear your observations about retyping versus cut and paste but that is clearly not a problem here.
Read-Only
Author
Jonh Bob
Posted
11-Aug-2005 01:18 GMT
Toolset
C51
New! RE: RE post Problem when implement i2c interface between AT24C04 EEPROM with 8051
Here
char data byte;
To indicated to the compiler that
the byte variable (type char) is in data memeory.

ti's the same with
int data index;
indicate that the index variable (type int) is in data memory.

So it's never conflict.
Read-Only
Author
erik malund
Posted
11-Aug-2005 21:00 GMT
Toolset
C51
New! RE: RE post Problem when implement i2c interface between AT24C04 EEPROM with 8051
To indicated to the compiler that
the byte variable (type char) is in data memeory.

Nothing wrong here, just unusual enough for me to miss what it was. :(

Erik
Read-Only
Author
T.R. Dufour
Posted
11-Aug-2005 20:38 GMT
Toolset
C51
New! RE: Problem when implement i2c interface between AT24C04 EEPROM with 8051
I suspect you are seeing the AT24C02 "stretch" the I2C clock when it stores the data in the shift register into the memory.

The clock on the I2C bus is "negotiated". Any time you write 0 to the SCL you are pulling down the clock line; any time you write 1 to SCL you are releasing your pull down expecting the clock to float high. However, when a slave sees the clock transition low, it latches the clock line as well in conjunction with the master. Even though the master floats the clock high, it can still be held low by the slave util it is ready for the next clock. This way the clock actually "slows" down to the slowest device on the I2C bus, basically stretching things out a little.

Basically:

--------------------------------------
To send the clock low:

Replace

SCL = 0

with

// If the clock is still held low, back off
// a little
while(!SCL)
i2c_nop();
// -- Some arbitrary delay (typically 600nS) to keep from violating timing specs
// Now drive the clock low
SCL = 0;

--------------------------------------
To send the clock high:

Replace

SCL = 1

with

// Release the pull-down
SCL = 1;
// Wait for the slave to release its
// latch as well
while(!SCL)
i2c_nop();


In either case the i2c_nop() function should provide some form of reset for the watchdog timer and whatever other time critical activity needs to be done in the interrim.
Read-Only
Author
Jonh Bob
Posted
12-Aug-2005 02:24 GMT
Toolset
C51
New! RE: Problem when implement i2c interface between AT24C04 EEPROM with 8051
Hello.
I had change some base function such as i2c_start,i2c_stop, i2c_write and i2c_read
And send the clock low was Replace SCL = 0 with the RELEASE_SCL_LOW function and send the clock hight was Replace SCL = 1 with the RELEASE_SCL_HIGHfunction.
But when i write a byte to AT24C04 then i can't write device address.
I mean in my program it's generate an error such as: Wrire: Interface failed to acknowledge device address

Here is my change.

void RELEASE_SCL_HIGH()
{
	SCL = 1;
	while(!SCL)
	{
	}
}
void RELEASE_SCL_LOW()
{
	SCL = 0;
	while(SCL)
	{
	}
}
char i2c_start(void)
{
	SDA = 1;
	//SCL = 1;
	RELEASE_SCL_HIGH();
	_nop_();
	SDA = 0;
	SCL = 0;
	RELEASE_SCL_LOW();
	_nop_();
	return 1;
}
void i2c_stop(void)
{
	unsigned char data input_var;
	SCL = 1;
	RELEASE_SCL_HIGH();
	_nop_();
	SDA = 0;
	SCL = 1;
	RELEASE_SCL_LOW();
	_nop_();
	SDA = 1;
	//SCL = 0;
	input_var = SDA;
}

// return ack value: 0 for fale; 1 for success

char i2c_write(char data dta)
{
	for(index = 0; index < 8 ; index++)
 	{
		//SCL = 1;               // Ensure that the data is stable during the high period.
		SDA = ((dta && 0x80) ? 1 : 0);
		//SCL = 1;               // Ensure that the data is stable during the high period.
		RELEASE_SCL_HIGH();
		_nop_();
		dta  <<= 1;
  		//SCL = 0;
		RELEASE_SCL_LOW();
		_nop_();
	}
	// Get ack
	SDA = 1;
	//SCL = 1;
	RELEASE_SCL_HIGH();
	_nop_();
	index = SDA;
	//SCL = 0;
	RELEASE_SCL_LOW();
	_nop_();
	return !index;  // Get data at end of cycle.
}
char i2c_read(char data ACK)
{
	char data result;
   	index = SDA;							// Put data pin into read mode
	result = 0;
	for(index = 0; index < 8; index++)  	// Send 8 bits to the I2C Bus
	{
		//result <<= 1;
		//SCL = 1;           				// Clock the data into the I2C Bus
		RELEASE_SCL_HIGH();
		_nop_();
		_nop_();
      	result |= SDA; 		   		// Input the data from the I2C Bus
		result <<= 1;
		//SCL = 0;
		RELEASE_SCL_LOW();
		_nop_();
	}

	// Write ack bit
	SDA = ACK;
  	//SCL = 1;               // Ensure that the data is stable during the high period.
	RELEASE_SCL_HIGH();
	_nop_();
	//SCL = 0;
	RELEASE_SCL_LOW();
	_nop_();
	return result;
}
Read-Only
Author
erik malund
Posted
12-Aug-2005 14:02 GMT
Toolset
C51
New! RE: Problem when implement i2c interface between AT24C04 EEPROM with 8051
without "digging into" your code a couple of things

I do not recall any IIC bitvangers without delay, I see none in the above with the exception of a _nop_ here and there. The IIC bus is limited to (depending on the device) 100 or 400kHz and you definitely seem to clock faster.

also I suggest you have a look at

The best (and most) IIC appnotes:
http://www.semiconductors.philips.com/buses/i2c/support/index.html

and, if you or anyone else are interested in really understanding IIC, may I suggest the IIC "class"
http://www.semiconductors.philips.com/acrobat_download/various/design_con_2003_tecforum_i2c_bus_overview.pdf
Read-Only
Author
Jonh Bob
Posted
18-Aug-2005 09:38 GMT
Toolset
C51
New! RE: Problem when implement i2c interface between AT24C04 EEPROM with 8051
I can't do any things.
Write/read...
Poor me.

Have any one from you do this ?
Read-Only
Author
erik malund
Posted
18-Aug-2005 13:39 GMT
Toolset
C51
New! RE: Problem when implement i2c interface between AT24C04 EEPROM with 8051
Have any one from you do this ?

I have bit-banged IIC many times, always using the code in one of the Philips appnotes (long ago, do not ask which) as a base.

Ther is a DEAD EASY way out:
Today I would not even dream of bit-banging IIC. There are chips galore with hardware IIC such as Philips LPC or P89C66x or even SILabs chip (stay away from the f3xx crap) which all have hardware IIC> Then use CodeArchitect (free from http://www.esacademy.com )to generate the code. For the LPC it works out of the box, for the P89C66x it takes 10 minutes to modify, for the SILabs about an hour.

Erik

Next Thread | Thread List | Previous Thread Start a Thread | Settings

Keil logo

Arm logo
Important information

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies.