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

This is a first version. Doesn't mean more versions will come, mainly means it may be a bit buggy. If it does not work for you: first try exactly the same code with the regular hardware I2C. If that does work, well then I made an error somewhere :D. You can send me a message if you can't figure it out, although without your hardware it generally is hard for me to reproduce.

While basic I2C should work, advanced things like clock stretching and multi-master I2C busses are not supported.

If you find an error and solve it: Send a pull request and I generally will accept it :).

Committer:
Sissors
Date:
Mon Nov 28 19:55:30 2016 +0000
Revision:
1:05473196d133
Parent:
0:fee70b6fe0e9
Changed scl to push pull during transactions
; More efficient and we don't support clock stretching anyway
; Using OpenDrain mode maybe for future, however is device dependent

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sissors 0:fee70b6fe0e9 1 #include "SoftI2C.h"
Sissors 0:fee70b6fe0e9 2
Sissors 0:fee70b6fe0e9 3 SoftI2C::SoftI2C(PinName sda, PinName scl) : _sda(sda), _scl(scl) {
Sissors 0:fee70b6fe0e9 4 // Set defaults
Sissors 0:fee70b6fe0e9 5 _sda.mode(PullNone);
Sissors 0:fee70b6fe0e9 6 _scl.mode(PullNone);
Sissors 0:fee70b6fe0e9 7 _sda.input();
Sissors 0:fee70b6fe0e9 8 _scl.input();
Sissors 0:fee70b6fe0e9 9 frequency(100000);
Sissors 0:fee70b6fe0e9 10
Sissors 0:fee70b6fe0e9 11 active = false;
Sissors 0:fee70b6fe0e9 12
Sissors 0:fee70b6fe0e9 13 }
Sissors 0:fee70b6fe0e9 14
Sissors 0:fee70b6fe0e9 15 void SoftI2C::frequency(int hz) {
Sissors 0:fee70b6fe0e9 16 delay_us = 1000000 / hz / 4; //delay is a quarter of the total period
Sissors 0:fee70b6fe0e9 17 }
Sissors 0:fee70b6fe0e9 18
Sissors 0:fee70b6fe0e9 19 int SoftI2C::read(int address, char *data, int length, bool repeated) {
Sissors 0:fee70b6fe0e9 20 start();
Sissors 0:fee70b6fe0e9 21
Sissors 0:fee70b6fe0e9 22 // Write address with LSB to one
Sissors 0:fee70b6fe0e9 23 if (write(address | 0x01) == 0) {
Sissors 0:fee70b6fe0e9 24 return 1;
Sissors 0:fee70b6fe0e9 25 }
Sissors 0:fee70b6fe0e9 26
Sissors 0:fee70b6fe0e9 27 // Read the data
Sissors 0:fee70b6fe0e9 28 for(int i = 0; i<length - 1; i++) {
Sissors 0:fee70b6fe0e9 29 data[i] = read(1);
Sissors 0:fee70b6fe0e9 30 }
Sissors 0:fee70b6fe0e9 31 data[length-1] = read(0);
Sissors 0:fee70b6fe0e9 32
Sissors 0:fee70b6fe0e9 33 if (repeated == false) {
Sissors 0:fee70b6fe0e9 34 stop();
Sissors 0:fee70b6fe0e9 35 }
Sissors 0:fee70b6fe0e9 36 return 0;
Sissors 0:fee70b6fe0e9 37 }
Sissors 0:fee70b6fe0e9 38
Sissors 0:fee70b6fe0e9 39 int SoftI2C::write(int address, const char *data, int length, bool repeated) {
Sissors 0:fee70b6fe0e9 40 start();
Sissors 0:fee70b6fe0e9 41
Sissors 0:fee70b6fe0e9 42 // Write address with LSB to zero
Sissors 0:fee70b6fe0e9 43 if (write(address & 0xFE) == 0) {
Sissors 0:fee70b6fe0e9 44 return 1;
Sissors 0:fee70b6fe0e9 45 }
Sissors 0:fee70b6fe0e9 46
Sissors 0:fee70b6fe0e9 47 // Write the data
Sissors 0:fee70b6fe0e9 48 for(int i = 0; i<length; i++) {
Sissors 0:fee70b6fe0e9 49 if(write(data[i]) == 0) {
Sissors 0:fee70b6fe0e9 50 return 1;
Sissors 0:fee70b6fe0e9 51 }
Sissors 0:fee70b6fe0e9 52 }
Sissors 0:fee70b6fe0e9 53
Sissors 0:fee70b6fe0e9 54 if (repeated == false) {
Sissors 0:fee70b6fe0e9 55 stop();
Sissors 0:fee70b6fe0e9 56 }
Sissors 0:fee70b6fe0e9 57 return 0;
Sissors 0:fee70b6fe0e9 58 }
Sissors 0:fee70b6fe0e9 59
Sissors 0:fee70b6fe0e9 60 int SoftI2C::read(int ack) {
Sissors 0:fee70b6fe0e9 61 int retval = 0;
Sissors 1:05473196d133 62 _scl.output();
Sissors 0:fee70b6fe0e9 63
Sissors 0:fee70b6fe0e9 64 // Shift the bits out, msb first
Sissors 0:fee70b6fe0e9 65 for (int i = 7; i>=0; i--) {
Sissors 0:fee70b6fe0e9 66 //SCL low
Sissors 0:fee70b6fe0e9 67 _scl.write(0);
Sissors 0:fee70b6fe0e9 68 _sda.input();
Sissors 0:fee70b6fe0e9 69 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 70
Sissors 0:fee70b6fe0e9 71 //read SDA
Sissors 0:fee70b6fe0e9 72 retval |= _sda.read() << i;
Sissors 0:fee70b6fe0e9 73 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 74
Sissors 0:fee70b6fe0e9 75 //SCL high again
Sissors 1:05473196d133 76 _scl.write(1);
Sissors 0:fee70b6fe0e9 77 wait_us(delay_us << 1); //wait two delays
Sissors 0:fee70b6fe0e9 78 }
Sissors 0:fee70b6fe0e9 79
Sissors 0:fee70b6fe0e9 80 // Last cycle to set the ACK
Sissors 0:fee70b6fe0e9 81 _scl.write(0);
Sissors 0:fee70b6fe0e9 82 if ( ack ) {
Sissors 0:fee70b6fe0e9 83 _sda.output();
Sissors 0:fee70b6fe0e9 84 _sda.write(0);
Sissors 0:fee70b6fe0e9 85 } else {
Sissors 0:fee70b6fe0e9 86 _sda.input();
Sissors 0:fee70b6fe0e9 87 }
Sissors 0:fee70b6fe0e9 88 wait_us(delay_us << 1);
Sissors 0:fee70b6fe0e9 89
Sissors 1:05473196d133 90 _scl.write(1);
Sissors 0:fee70b6fe0e9 91 wait_us(delay_us << 1);
Sissors 0:fee70b6fe0e9 92
Sissors 0:fee70b6fe0e9 93
Sissors 0:fee70b6fe0e9 94 return retval;
Sissors 0:fee70b6fe0e9 95 }
Sissors 0:fee70b6fe0e9 96
Sissors 0:fee70b6fe0e9 97 int SoftI2C::write(int data) {
Sissors 1:05473196d133 98 _scl.output();
Sissors 1:05473196d133 99
Sissors 0:fee70b6fe0e9 100 // Shift the bits out, msb first
Sissors 0:fee70b6fe0e9 101 for (int i = 7; i>=0; i--) {
Sissors 0:fee70b6fe0e9 102 //SCL low
Sissors 0:fee70b6fe0e9 103 _scl.write(0);
Sissors 0:fee70b6fe0e9 104 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 105
Sissors 0:fee70b6fe0e9 106 //Change SDA depending on the bit
Sissors 0:fee70b6fe0e9 107 if ( (data >> i) & 0x01 ) {
Sissors 0:fee70b6fe0e9 108 _sda.input();
Sissors 0:fee70b6fe0e9 109 } else {
Sissors 0:fee70b6fe0e9 110 _sda.output();
Sissors 0:fee70b6fe0e9 111 _sda.write(0);
Sissors 0:fee70b6fe0e9 112 }
Sissors 0:fee70b6fe0e9 113 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 114
Sissors 0:fee70b6fe0e9 115 //SCL high again
Sissors 1:05473196d133 116 _scl.write(1);
Sissors 0:fee70b6fe0e9 117 wait_us(delay_us << 1); //wait two delays
Sissors 0:fee70b6fe0e9 118 }
Sissors 0:fee70b6fe0e9 119
Sissors 0:fee70b6fe0e9 120 // Last cycle to get the ACK
Sissors 0:fee70b6fe0e9 121 _scl.write(0);
Sissors 0:fee70b6fe0e9 122 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 123
Sissors 0:fee70b6fe0e9 124 _sda.input();
Sissors 0:fee70b6fe0e9 125 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 126
Sissors 1:05473196d133 127 _scl.write(1);
Sissors 0:fee70b6fe0e9 128 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 129 int retval = ~_sda.read(); //Read the ack
Sissors 0:fee70b6fe0e9 130 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 131
Sissors 0:fee70b6fe0e9 132 return retval;
Sissors 0:fee70b6fe0e9 133 }
Sissors 0:fee70b6fe0e9 134
Sissors 0:fee70b6fe0e9 135 void SoftI2C::start(void) {
Sissors 0:fee70b6fe0e9 136 if (active) { //if repeated start
Sissors 0:fee70b6fe0e9 137 //Set SDA high, toggle scl
Sissors 0:fee70b6fe0e9 138 _sda.input();
Sissors 0:fee70b6fe0e9 139 _scl.output();
Sissors 0:fee70b6fe0e9 140 _scl.write(0);
Sissors 0:fee70b6fe0e9 141 wait_us(delay_us << 1);
Sissors 1:05473196d133 142 _scl.write(1);
Sissors 0:fee70b6fe0e9 143 wait_us(delay_us << 1);
Sissors 0:fee70b6fe0e9 144 }
Sissors 0:fee70b6fe0e9 145 // Pull SDA low
Sissors 0:fee70b6fe0e9 146 _sda.output();
Sissors 0:fee70b6fe0e9 147 _sda.write(0);
Sissors 0:fee70b6fe0e9 148 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 149 active = true;
Sissors 0:fee70b6fe0e9 150 }
Sissors 0:fee70b6fe0e9 151
Sissors 0:fee70b6fe0e9 152 void SoftI2C::stop(void) {
Sissors 0:fee70b6fe0e9 153 // Float SDA high
Sissors 0:fee70b6fe0e9 154 _scl.output();
Sissors 0:fee70b6fe0e9 155 _scl.write(0);
Sissors 0:fee70b6fe0e9 156 _sda.output();
Sissors 0:fee70b6fe0e9 157 _sda.write(0);
Sissors 0:fee70b6fe0e9 158 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 159 _scl.input();
Sissors 0:fee70b6fe0e9 160 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 161 _sda.input();
Sissors 0:fee70b6fe0e9 162 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 163
Sissors 0:fee70b6fe0e9 164 active = false;
Sissors 0:fee70b6fe0e9 165 }