Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
SoftI2C.cpp
- Committer:
- Sissors
- Date:
- 2016-11-22
- Revision:
- 0:fee70b6fe0e9
- Child:
- 1:05473196d133
File content as of revision 0:fee70b6fe0e9:
#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;
}