Softi2c with pull up enabled
Diff: SoftI2C.cpp
- Revision:
- 0:fee70b6fe0e9
- Child:
- 1:05473196d133
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SoftI2C.cpp Tue Nov 22 20:45:35 2016 +0000 @@ -0,0 +1,166 @@ +#include "SoftI2C.h" + +SoftI2C::SoftI2C(PinName sda, PinName scl) : _sda(sda), _scl(scl) { + // Set defaults + _sda.mode(PullNone); + _scl.mode(PullNone); + _sda.input(); + _scl.input(); + frequency(100000); + + active = false; + + } + +void SoftI2C::frequency(int hz) { + delay_us = 1000000 / hz / 4; //delay is a quarter of the total period +} + +int SoftI2C::read(int address, char *data, int length, bool repeated) { + start(); + + // Write address with LSB to one + if (write(address | 0x01) == 0) { + return 1; + } + + // Read the data + for(int i = 0; i<length - 1; i++) { + data[i] = read(1); + } + data[length-1] = read(0); + + if (repeated == false) { + stop(); + } + return 0; +} + +int SoftI2C::write(int address, const char *data, int length, bool repeated) { + start(); + + // Write address with LSB to zero + if (write(address & 0xFE) == 0) { + return 1; + } + + // Write the data + for(int i = 0; i<length; i++) { + if(write(data[i]) == 0) { + return 1; + } + } + + if (repeated == false) { + stop(); + } + return 0; +} + +int SoftI2C::read(int ack) { + int retval = 0; + + // Shift the bits out, msb first + for (int i = 7; i>=0; i--) { + //SCL low + _scl.output(); + _scl.write(0); + _sda.input(); + wait_us(delay_us); + + //read SDA + retval |= _sda.read() << i; + wait_us(delay_us); + + //SCL high again + _scl.input(); + wait_us(delay_us << 1); //wait two delays + } + + // Last cycle to set the ACK + _scl.output(); + _scl.write(0); + if ( ack ) { + _sda.output(); + _sda.write(0); + } else { + _sda.input(); + } + wait_us(delay_us << 1); + + _scl.input(); + wait_us(delay_us << 1); + + + return retval; +} + +int SoftI2C::write(int data) { + // Shift the bits out, msb first + for (int i = 7; i>=0; i--) { + //SCL low + _scl.output(); + _scl.write(0); + wait_us(delay_us); + + //Change SDA depending on the bit + if ( (data >> i) & 0x01 ) { + _sda.input(); + } else { + _sda.output(); + _sda.write(0); + } + wait_us(delay_us); + + //SCL high again + _scl.input(); + wait_us(delay_us << 1); //wait two delays + } + + // Last cycle to get the ACK + _scl.output(); + _scl.write(0); + wait_us(delay_us); + + _sda.input(); + wait_us(delay_us); + + _scl.input(); + wait_us(delay_us); + int retval = ~_sda.read(); //Read the ack + wait_us(delay_us); + + return retval; +} + +void SoftI2C::start(void) { + if (active) { //if repeated start + //Set SDA high, toggle scl + _sda.input(); + _scl.output(); + _scl.write(0); + wait_us(delay_us << 1); + _scl.input(); + wait_us(delay_us << 1); + } + // Pull SDA low + _sda.output(); + _sda.write(0); + wait_us(delay_us); + active = true; +} + +void SoftI2C::stop(void) { + // Float SDA high + _scl.output(); + _scl.write(0); + _sda.output(); + _sda.write(0); + wait_us(delay_us); + _scl.input(); + wait_us(delay_us); + _sda.input(); + wait_us(delay_us); + + active = false; +} \ No newline at end of file