This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

I2C read/write routines

Hi,

I am looking for simple read and write routines for I2C interface between Atmel low-end 89C2051 microcontroller and 24C04 serial EEPROM.

Any help would be great .

Thanks in Advance.
Rocknmoon

Parents Reply Children
  • Thanks for pointing to some of the resourses.

    Basically i am looking for C code.

    Bye.

  • It is difficult/impossible to code timing routines in C, the compiler manufaturer is under no obligation to make code run at specific execution times and often the time is release dependdent. Thus all IIC code will be in assebler. You can, of course make a "hich level" C interface to the assembler code.

    Erik

  • Hi,

    If you're interested, I have written an I2c routine (master mode only) in C. It's still not full mature, but it can give you some idea(s) of how to set up your own.

    Just send me your email to 'g-vcompernolle at tiscali dot be' and I'll send you the code.

    Rgds,

    Geert

  • Erik,
    While your comments about writing timing routines in C are true in the general sense, I2C is not a timing specific protocol (at least not for the master). Everything is state based, and as long as your timing is not shorter than the specification, you can change states as slowly as you like.
    It is entirely possible to make one transition a second, and the protocol will still work.

  • Richard,

    can you describe the sequence of states which the master goes through to do simple write and read functions ??

    I am trying to implement a write function that can write few bytes into the slave (serial EEPROM). The read function will read in the whole data once at the system power up time.

    Any help would be great.

    Bye.

  • "Basically i am looking for C code."

    You should not be afraid to use a little assembler where that is the most appropriate solution!

    Probably the two least appropriate areas for 'C' are timing-critical details, and extensive manipulation of individual bits for low-level hardware IO.

    This sounds like an ideal application for assembler!

  • Rockn,

    Here is some code I used to dump the contents of a 24C01 EEPROM on a PC.
    You will need to insert your own code into raise_sda(), drop_sda(), raise_scl(), drop_scl(), and read_sda().
    This was written in Borland C to run under DOS, so you may need some minor changes to work under Keil C.

    This code is not optimised, and was deliberately written to run slowly so I could easily watch each transition using a Digital Storage Oscilloscope.

    Read the data sheet for the EEPROM you want to talk to, then just do exactly what they tell you to...

    void raise_sda(void)
    {
    //code to raise(= float) the SDA pin
    }
    
    void drop_sda(void)
    {
    //code to drop(= drive low) the SDA pin
    }
    
    void raise_scl(void)
    {
    //code to raise(= float) the SCL pin
    }
    
    void drop_scl(void)
    {
    //code to drop(= drive low) the SCL pin
    }
    
    int read_sda(void)
    {
    //return 0 if SDA is low, or 1 if SDA is high
    }
    //----------------------------------------------------------------------
    void i2c_stop(void)
    {
    	delay(1);
    	raise_scl();
    	delay(1);
    	raise_sda();
    	delay(1);
    }
    
    void i2c_start(void)
    {
    	i2c_stop();	//make sure we are starting from a STOP condition
    	drop_sda();
    	delay(1);
    	drop_scl();
    	delay(1);
    }
    
    //send BYTE in data. Return 0 is slave sent an ACK, or 1 if slave did not respond
    int i2c_send(BYTE data)
    //assumes SCL is already low
    {
    	int i;
    
    	for (i=0; i<8; i++)
    	{
    		if ((data & 0x80) != 0)
    			raise_sda();
    		else
    			drop_sda();
    
    		delay(1);	//*** this delay for debugging only. remove later.
    		raise_scl();
    		delay(1);
    		drop_scl();
    		delay(1);
    		data <<= 1;
    	}
    	raise_sda();	//release SDA so slave can control it
    	delay(1);		//*** this delay for debugging only. remove later.
    	raise_scl();
    	delay(1);
    	i = read_sda();	//read ACK pulse
    	drop_scl();
    	delay(1);
    	drop_sda();
    	return i;		//return ACK value
    }
    
    int i2c_recv(void)
    //assumes SCL is low
    {
    	int i;
    	int accum=0;
    
    	raise_sda();	//release SDA so slave can control it
    	delay(1);		//*** this delay for debugging only. remove later.
    	for (i=0; i<8; i++)
    	{
    		raise_scl();
    		delay(1);
    		accum <<= 1;		//slide left one bit
    		accum |= read_sda();//and copy SDA to bit 0
    		drop_scl();
    		delay(1);
    	}
    	return accum;		//return data byte
    }
    
    void send_nak(void)
    {
    	raise_scl();
    	delay(1);
    	drop_scl();
    	delay(1);
    	drop_sda();			//prepare to send STOP
    }
    
    void send_ack(void)
    {
    	drop_sda();		//should always be floating after a read anyway
    	delay(1);		//*** this delay for debugging only. remove later.
    
    	raise_scl();
    	delay(1);
    	drop_scl();
    	delay(1);
    }
    
    #define EEP_ADDR 0xa0	//I2C address of EEPROM
    #define DUMP_END 0xff	//last address of EEPROM
    
    void main(void)
    {
    	int i,temp;
    	int result;
    
    
    	i2c_start();	//start a write cycle (just to set the address)
    	result = i2c_send(EEP_ADDR);//send write address
    	if (result != 0)
    	{
    		printf("Didn't ACK write cmmand\n",result);
    		return 1;
    	}
    
    	result = i2c_send(0x00);//to address 00
    	if (result != 0)
    	{
    		printf("Didn't ACK EEPROM address\n",result);
    		return 2;
    	}
    
    	i2c_stop();		//stop write cycle
    	i2c_start();    //and start a read cycle
    
    	result = i2c_send(EEP_ADDR | 0x01);	//send read address
    	if (result != 0)
    	{
    		printf("Didn't ACK read command\n",result);
    		return 3;
    	}
    
    	for (i=0;i < DUMP_END;i++)
    	{
    		temp = i2c_recv();		//read one byte
    		printf("%02x ",temp);
    		if ((i & 0xf) == 0xf)
    			printf("\n");
    
    		if (i != DUMP_END)
    			send_ack();
    		else
    			send_nak();
    	}
    
    	i2c_stop();
    	return 0;
    }

  • Hi Geert

    Could you please post your I2C routine (master mode only) in C to me?

    Thanksin advance!

    ShiShen