Fork of SoftI2C. Added clock stretching support.

Fork of SoftI2C by Erik -

Committer:
ninensei
Date:
Wed Sep 13 22:36:30 2017 +0000
Revision:
2:b174177b2bf2
Parent:
1:05473196d133
Added clocks stretching support

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 0:fee70b6fe0e9 62
Sissors 0:fee70b6fe0e9 63 // Shift the bits out, msb first
Sissors 0:fee70b6fe0e9 64 for (int i = 7; i>=0; i--) {
Sissors 0:fee70b6fe0e9 65 //SCL low
ninensei 2:b174177b2bf2 66 _scl.output();
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
ninensei 2:b174177b2bf2 76 _scl.input();
ninensei 2:b174177b2bf2 77 while (!_scl.read());
Sissors 0:fee70b6fe0e9 78 wait_us(delay_us << 1); //wait two delays
Sissors 0:fee70b6fe0e9 79 }
Sissors 0:fee70b6fe0e9 80
Sissors 0:fee70b6fe0e9 81 // Last cycle to set the ACK
ninensei 2:b174177b2bf2 82 _scl.output();
Sissors 0:fee70b6fe0e9 83 _scl.write(0);
Sissors 0:fee70b6fe0e9 84 if ( ack ) {
Sissors 0:fee70b6fe0e9 85 _sda.output();
Sissors 0:fee70b6fe0e9 86 _sda.write(0);
Sissors 0:fee70b6fe0e9 87 } else {
Sissors 0:fee70b6fe0e9 88 _sda.input();
Sissors 0:fee70b6fe0e9 89 }
Sissors 0:fee70b6fe0e9 90 wait_us(delay_us << 1);
Sissors 0:fee70b6fe0e9 91
ninensei 2:b174177b2bf2 92 _scl.input();
ninensei 2:b174177b2bf2 93 while (!_scl.read());
Sissors 0:fee70b6fe0e9 94 wait_us(delay_us << 1);
Sissors 0:fee70b6fe0e9 95
Sissors 0:fee70b6fe0e9 96 return retval;
Sissors 0:fee70b6fe0e9 97 }
Sissors 0:fee70b6fe0e9 98
Sissors 0:fee70b6fe0e9 99 int SoftI2C::write(int data) {
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
ninensei 2:b174177b2bf2 103 _scl.output();
Sissors 0:fee70b6fe0e9 104 _scl.write(0);
Sissors 0:fee70b6fe0e9 105 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 106
Sissors 0:fee70b6fe0e9 107 //Change SDA depending on the bit
Sissors 0:fee70b6fe0e9 108 if ( (data >> i) & 0x01 ) {
Sissors 0:fee70b6fe0e9 109 _sda.input();
Sissors 0:fee70b6fe0e9 110 } else {
Sissors 0:fee70b6fe0e9 111 _sda.output();
Sissors 0:fee70b6fe0e9 112 _sda.write(0);
Sissors 0:fee70b6fe0e9 113 }
Sissors 0:fee70b6fe0e9 114 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 115
Sissors 0:fee70b6fe0e9 116 //SCL high again
ninensei 2:b174177b2bf2 117 _scl.input();
ninensei 2:b174177b2bf2 118 while (!_scl.read());
Sissors 0:fee70b6fe0e9 119 wait_us(delay_us << 1); //wait two delays
Sissors 0:fee70b6fe0e9 120 }
Sissors 0:fee70b6fe0e9 121
Sissors 0:fee70b6fe0e9 122 // Last cycle to get the ACK
ninensei 2:b174177b2bf2 123 _scl.output();
Sissors 0:fee70b6fe0e9 124 _scl.write(0);
Sissors 0:fee70b6fe0e9 125 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 126
Sissors 0:fee70b6fe0e9 127 _sda.input();
Sissors 0:fee70b6fe0e9 128 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 129
ninensei 2:b174177b2bf2 130 _scl.input();
ninensei 2:b174177b2bf2 131 while (!_scl.read());
Sissors 0:fee70b6fe0e9 132 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 133 int retval = ~_sda.read(); //Read the ack
Sissors 0:fee70b6fe0e9 134 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 135
Sissors 0:fee70b6fe0e9 136 return retval;
Sissors 0:fee70b6fe0e9 137 }
Sissors 0:fee70b6fe0e9 138
Sissors 0:fee70b6fe0e9 139 void SoftI2C::start(void) {
Sissors 0:fee70b6fe0e9 140 if (active) { //if repeated start
Sissors 0:fee70b6fe0e9 141 //Set SDA high, toggle scl
Sissors 0:fee70b6fe0e9 142 _sda.input();
Sissors 0:fee70b6fe0e9 143 _scl.output();
Sissors 0:fee70b6fe0e9 144 _scl.write(0);
Sissors 0:fee70b6fe0e9 145 wait_us(delay_us << 1);
ninensei 2:b174177b2bf2 146 _scl.input();
ninensei 2:b174177b2bf2 147 while (!_scl.read());
Sissors 0:fee70b6fe0e9 148 wait_us(delay_us << 1);
Sissors 0:fee70b6fe0e9 149 }
Sissors 0:fee70b6fe0e9 150 // Pull SDA low
Sissors 0:fee70b6fe0e9 151 _sda.output();
Sissors 0:fee70b6fe0e9 152 _sda.write(0);
Sissors 0:fee70b6fe0e9 153 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 154 active = true;
Sissors 0:fee70b6fe0e9 155 }
Sissors 0:fee70b6fe0e9 156
Sissors 0:fee70b6fe0e9 157 void SoftI2C::stop(void) {
Sissors 0:fee70b6fe0e9 158 // Float SDA high
Sissors 0:fee70b6fe0e9 159 _scl.output();
Sissors 0:fee70b6fe0e9 160 _scl.write(0);
Sissors 0:fee70b6fe0e9 161 _sda.output();
Sissors 0:fee70b6fe0e9 162 _sda.write(0);
Sissors 0:fee70b6fe0e9 163 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 164 _scl.input();
ninensei 2:b174177b2bf2 165 while (!_scl.read());
Sissors 0:fee70b6fe0e9 166 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 167 _sda.input();
Sissors 0:fee70b6fe0e9 168 wait_us(delay_us);
Sissors 0:fee70b6fe0e9 169
Sissors 0:fee70b6fe0e9 170 active = false;
Sissors 0:fee70b6fe0e9 171 }