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
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.
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; }