Steve Martin / libdrv_SoftI2C

Fork of SoftI2C by Erik -

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     
00063     // Shift the bits out, msb first
00064     for (int i = 7; i>=0; i--) {
00065         //SCL low
00066         _scl.output();
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.input();
00077         while (!_scl.read());
00078         wait_us(delay_us << 1); //wait two delays
00079     }
00080     
00081     // Last cycle to set the ACK
00082     _scl.output();
00083     _scl.write(0);
00084     if ( ack ) {
00085         _sda.output();
00086         _sda.write(0);
00087     } else {
00088         _sda.input();
00089     }
00090     wait_us(delay_us << 1);
00091     
00092     _scl.input();
00093     while (!_scl.read());
00094     wait_us(delay_us << 1);
00095     
00096     return retval;
00097 }
00098 
00099 int SoftI2C::write(int data) {
00100     // Shift the bits out, msb first
00101     for (int i = 7; i>=0; i--) {
00102         //SCL low
00103         _scl.output();
00104         _scl.write(0);
00105         wait_us(delay_us);
00106         
00107         //Change SDA depending on the bit
00108         if ( (data >> i) & 0x01 ) {
00109             _sda.input();
00110         } else {
00111             _sda.output();
00112             _sda.write(0);
00113         }
00114         wait_us(delay_us);
00115         
00116         //SCL high again
00117         _scl.input();
00118         while (!_scl.read());
00119         wait_us(delay_us << 1); //wait two delays
00120     }
00121     
00122     // Last cycle to get the ACK
00123     _scl.output();
00124     _scl.write(0);
00125     wait_us(delay_us);
00126     
00127     _sda.input();
00128     wait_us(delay_us);
00129     
00130     _scl.input();
00131     while (!_scl.read());
00132     wait_us(delay_us);
00133     int retval = ~_sda.read(); //Read the ack
00134     wait_us(delay_us);
00135     
00136     return retval;
00137 }
00138 
00139 void SoftI2C::start(void) {
00140     if (active) { //if repeated start
00141         //Set SDA high, toggle scl
00142         _sda.input();
00143         _scl.output();
00144         _scl.write(0);
00145         wait_us(delay_us << 1);
00146         _scl.input();
00147         while (!_scl.read());
00148         wait_us(delay_us << 1);
00149     }
00150     // Pull SDA low
00151     _sda.output();
00152     _sda.write(0);
00153     wait_us(delay_us);
00154     active = true;
00155 }
00156 
00157 void SoftI2C::stop(void) {
00158     // Float SDA high
00159     _scl.output();
00160     _scl.write(0);
00161     _sda.output();
00162     _sda.write(0);
00163     wait_us(delay_us);
00164     _scl.input();
00165     while (!_scl.read());
00166     wait_us(delay_us);
00167     _sda.input();
00168     wait_us(delay_us);
00169     
00170     active = false;
00171 }