A software I2C interface which is a drop-in replacement for the regular mbed I2C interface in case you run out of I2C ports

Dependents:   Luminocity laser-tag

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SoftI2C.cpp Source File

SoftI2C.cpp

00001 #include "SoftI2C.h"
00002 
00003 SoftI2C::SoftI2C(PinName sda, PinName scl) : _sda(sda), _scl(scl) {
00004     // Set defaults
00005     _sda.mode(PullNone);
00006     _scl.mode(PullNone);
00007     _sda.input();
00008     _scl.input();
00009     frequency(100000);
00010     
00011     active = false;
00012     
00013     }
00014     
00015 void SoftI2C::frequency(int hz) {
00016     delay_us = 1000000 / hz / 4; //delay is a quarter of the total period
00017 }
00018 
00019 int SoftI2C::read(int address, char *data, int length, bool repeated) {
00020     start();
00021     
00022     // Write address with LSB to one
00023     if (write(address | 0x01) == 0) {
00024         return 1;
00025     }  
00026     
00027     // Read the data
00028     for(int i = 0; i<length - 1; i++) {
00029         data[i] = read(1);
00030     }
00031     data[length-1] = read(0);
00032     
00033     if (repeated == false) {
00034         stop();
00035     }
00036     return 0;
00037 }
00038 
00039 int SoftI2C::write(int address, const char *data, int length, bool repeated) {
00040     start();
00041     
00042     // Write address with LSB to zero
00043     if (write(address & 0xFE) == 0) {
00044         return 1;
00045     }  
00046     
00047     // Write the data
00048     for(int i = 0; i<length; i++) {
00049         if(write(data[i]) == 0) {
00050             return 1;
00051         }
00052     }
00053     
00054     if (repeated == false) {
00055         stop();
00056     }
00057     return 0;
00058 }
00059 
00060 int SoftI2C::read(int ack) {
00061     int retval = 0;
00062     _scl.output();
00063     
00064     // Shift the bits out, msb first
00065     for (int i = 7; i>=0; i--) {
00066         //SCL low
00067         _scl.write(0);
00068         _sda.input();
00069         wait_us(delay_us);
00070         
00071         //read SDA
00072         retval |= _sda.read() << i;
00073         wait_us(delay_us);
00074         
00075         //SCL high again
00076         _scl.write(1);
00077         wait_us(delay_us << 1); //wait two delays
00078     }
00079     
00080     // Last cycle to set the ACK
00081     _scl.write(0);
00082     if ( ack ) {
00083         _sda.output();
00084         _sda.write(0);
00085     } else {
00086         _sda.input();
00087     }
00088     wait_us(delay_us << 1);
00089     
00090     _scl.write(1);
00091     wait_us(delay_us << 1);
00092 
00093     
00094     return retval;
00095 }
00096 
00097 int SoftI2C::write(int data) {
00098      _scl.output();
00099      
00100     // Shift the bits out, msb first
00101     for (int i = 7; i>=0; i--) {
00102         //SCL low
00103         _scl.write(0);
00104         wait_us(delay_us);
00105         
00106         //Change SDA depending on the bit
00107         if ( (data >> i) & 0x01 ) {
00108             _sda.input();
00109         } else {
00110             _sda.output();
00111             _sda.write(0);
00112         }
00113         wait_us(delay_us);
00114         
00115         //SCL high again
00116         _scl.write(1);
00117         wait_us(delay_us << 1); //wait two delays
00118     }
00119     
00120     // Last cycle to get the ACK
00121     _scl.write(0);
00122     wait_us(delay_us);
00123     
00124     _sda.input();
00125     wait_us(delay_us);
00126     
00127     _scl.write(1);
00128     wait_us(delay_us);
00129     int retval = ~_sda.read(); //Read the ack
00130     wait_us(delay_us);
00131     
00132     return retval;
00133 }
00134 
00135 void SoftI2C::start(void) {
00136     if (active) { //if repeated start
00137         //Set SDA high, toggle scl
00138         _sda.input();
00139         _scl.output();
00140         _scl.write(0);
00141         wait_us(delay_us << 1);
00142         _scl.write(1);
00143         wait_us(delay_us << 1);
00144     }
00145     // Pull SDA low
00146     _sda.output();
00147     _sda.write(0);
00148     wait_us(delay_us);
00149     active = true;
00150 }
00151 
00152 void SoftI2C::stop(void) {
00153     // Float SDA high
00154     _scl.output();
00155     _scl.write(0);
00156     _sda.output();
00157     _sda.write(0);
00158     wait_us(delay_us);
00159     _scl.input();
00160     wait_us(delay_us);
00161     _sda.input();
00162     wait_us(delay_us);
00163     
00164     active = false;
00165 }