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
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 }
Generated on Tue Jul 12 2022 19:30:00 by 1.7.2