Go Down

Topic: I2C communication to external EEPROM via digital pins (Read 8162 times) previous topic - next topic

marthal

There have been occasional questions about the possibility of using digital pins instead of analog pins for I2C communication. Also I myself had the need to save analog pins for other purposes and so I wrote a code which enables any two digital pins to take over I2C communication, in this example with a 24lc256 EEPROM. The sketch shows how to write and to read a number to and from any address of the eeprom.
I'm not a pro so there might be space for improvement. If someone out there wants to transform it into a proper library, please feel free. Now to the sketch. Hope you'll enjoy. Here we go...
Code: [Select]
/*Example code for using two digital pins to establish I2C communication
with a 24LC256 EEPROM
Written by Martin Thalheimer, 2011.
*/

byte data = 4;  //digital pin 4 = data - connect to pin 4 of 24lc256
byte clock = 5;  //digital pin 5 = clock - connect to pin 5 of 24lc256
int address=160;  //address of the 24lc256 with all address pin tied to GND
int i2c_out;
int i;
int number=234;   //put here a number of your choice (0-255) to be stored in the external eeprom
int memory_address=23456; /*put here the address of your choice (0-32767) within the eeprom where
                            you want the number to be stored*/
int adr_hi;
int adr_low;

void setup(){
Serial.begin(9600);
pinMode(clock, OUTPUT);
pinMode(data, OUTPUT);
}

void loop() {
   Serial.println("writing...");
   dig_eeprom_write(); //this function writes the number into the external eeprom
   Serial.println(number);
   Serial.print("to eeprom address ");
   Serial.println(memory_address);
   
   Serial.println("reading...");
   dig_eeprom_read(); //this function reads the number from the external eeprom
   Serial.println(i2c_out);
   Serial.print("from eeprom address ");
   Serial.println(memory_address);
   Serial.println();

   delay(2000);   
   }
     
  void dig_eeprom_write() {
   common_routine();
   i2c_out=number;
   putbyte();   //the number is being sent to the eeprom
   getack();   //get acknowledge
   Stop();
   delay (100); //
   } 
 
  void dig_eeprom_read() {
   common_routine();
   start();
   i2c_out=address+1; //address of 24lc256 in read mode
   putbyte();   //send byte
   getack();   //get acknowledge
   getbyte(); //retrieve content of the memory cell
   givenoack();   //no acknowledge
   Stop();
   delay(10);
   }
   
  void common_routine () {  //this part is common to each writing or reading cycle
    start();    //start signal for eeprom to wake up
    i2c_out=address; //address of 24lc256 in write mode
    putbyte();   //send byte
    getack();   //get acknowledge
    adr_hi=memory_address/256;    //
    adr_low=memory_address % 256; //
    i2c_out=adr_hi; //send the highbyte of the memory-address
    putbyte();   //send byte
    getack();   //get acknowledge
    i2c_out=adr_low; //send the lowbyte of the memory-address
    putbyte();   //send byte
    getack();   //get acknowledge
    }   
           
   void start() {
       digitalWrite (clock, HIGH);
       digitalWrite (data, HIGH);
       digitalWrite (data, LOW);
       digitalWrite (clock, LOW);
       }
   
    void putbyte() {
       for (i=7; i>=0; i--){
       if ((i2c_out &(1<<i))==0) {   
         digitalWrite (data, LOW);
       }
        else {
          digitalWrite (data, HIGH);
       }
       digitalWrite (clock, HIGH);    //pulse clock
       digitalWrite (clock, LOW);
       }
       }
       
void getbyte() {
       pinMode(data, INPUT);
       i2c_out=0;
       for (i=7; i>=0; i--){
       if (digitalRead(data)==HIGH) {   
       i2c_out=(i2c_out + (1<<i));
       delay(10);
       }
       digitalWrite (clock, HIGH);    //pulse clock
       digitalWrite (clock, LOW);
       }     
       pinMode(data, OUTPUT);   
       }
   
  void getack() {
      digitalWrite (data, HIGH);
      pinMode(data, INPUT);
      digitalWrite (clock, HIGH);
      if(digitalRead(data)==LOW) {
      digitalWrite (clock, HIGH); //acknowledge ack
      digitalWrite (clock, LOW);
      }
      pinMode(data, OUTPUT);
      }
     
   void Stop() { 
      digitalWrite (data, LOW);
      digitalWrite (clock, HIGH); 
      digitalWrite (data, HIGH);
      }
   
  void givenoack() {
     digitalWrite (data, HIGH);
     digitalWrite (clock, HIGH);    //pulse clock
     digitalWrite (clock, LOW);
     digitalWrite (data, LOW);
     }
 

JanD

I have also for some time now wondered why there isn't any Software I2C or SPI library. There is a Software library for UART (SoftSerial, NewSoftSerial) so why not for I2C and SPI???

I would really like to make a library, and your code is a good thing to start from, but I think i don't have the time to do that. Perhaps some time the next week.

Jan


robtillaart


Soft I2C => check this blog article  => http://arduino.cc/blog/2010/10/01/softi2cmaster-library-lets-you-add-i2c-to-any-arduino-pin/

As it is work in progress maybe you can add your energy to get this effort on a higher level iso starting a new one?

my 2 cnts,
Rob
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up