Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
BitBangI2C/BitBangI2C.cpp@86:e30a1f60f783, 2017-04-21 (annotated)
- Committer:
- mjr
- Date:
- Fri Apr 21 18:50:37 2017 +0000
- Revision:
- 86:e30a1f60f783
- Parent:
- 82:4f6209cb5c33
- Child:
- 87:8d35c74403af
Capture a bunch of alternative bar code decoder tests, mostly unsuccessful
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mjr | 86:e30a1f60f783 | 1 | // Bit Bang BitBangI2C implementation for KL25Z |
mjr | 82:4f6209cb5c33 | 2 | // |
mjr | 82:4f6209cb5c33 | 3 | |
mjr | 82:4f6209cb5c33 | 4 | #include "mbed.h" |
mjr | 82:4f6209cb5c33 | 5 | #include "BitBangI2C.h" |
mjr | 82:4f6209cb5c33 | 6 | |
mjr | 86:e30a1f60f783 | 7 | |
mjr | 82:4f6209cb5c33 | 8 | // -------------------------------------------------------------------------- |
mjr | 82:4f6209cb5c33 | 9 | // |
mjr | 82:4f6209cb5c33 | 10 | // Debugging: |
mjr | 82:4f6209cb5c33 | 11 | // |
mjr | 82:4f6209cb5c33 | 12 | // 0 -> no debugging |
mjr | 82:4f6209cb5c33 | 13 | // 1 -> print (on console) error messages only |
mjr | 82:4f6209cb5c33 | 14 | // 2 -> print full diagnostics |
mjr | 82:4f6209cb5c33 | 15 | // |
mjr | 82:4f6209cb5c33 | 16 | // dprintf() = general debug diagnostics (printed only in case 2) |
mjr | 82:4f6209cb5c33 | 17 | // eprintf() = error diagnostics (printed in case 1 and above) |
mjr | 82:4f6209cb5c33 | 18 | // |
mjr | 82:4f6209cb5c33 | 19 | #define BBI2C_DEBUG 1 |
mjr | 82:4f6209cb5c33 | 20 | #if BBI2C_DEBUG |
mjr | 82:4f6209cb5c33 | 21 | # define eprintf(...) printf(__VA_ARGS__) |
mjr | 82:4f6209cb5c33 | 22 | # if BBI2C_DEBUG >= 2 |
mjr | 82:4f6209cb5c33 | 23 | # define dprintf(...) printf(__VA_ARGS__) |
mjr | 82:4f6209cb5c33 | 24 | # else |
mjr | 82:4f6209cb5c33 | 25 | # define dprintf(...) |
mjr | 82:4f6209cb5c33 | 26 | # endif |
mjr | 82:4f6209cb5c33 | 27 | static const char *dbgbytes(const uint8_t *bytes, size_t len) |
mjr | 82:4f6209cb5c33 | 28 | { |
mjr | 82:4f6209cb5c33 | 29 | static char buf[128]; |
mjr | 82:4f6209cb5c33 | 30 | char *p = buf; |
mjr | 82:4f6209cb5c33 | 31 | for (int i = 0 ; i < len && p + 4 < buf + sizeof(buf) ; ++i) |
mjr | 82:4f6209cb5c33 | 32 | { |
mjr | 82:4f6209cb5c33 | 33 | if (i > 0) *p++ = ','; |
mjr | 82:4f6209cb5c33 | 34 | sprintf(p, "%02x", bytes[i]); |
mjr | 82:4f6209cb5c33 | 35 | p += 2; |
mjr | 82:4f6209cb5c33 | 36 | } |
mjr | 82:4f6209cb5c33 | 37 | *p = '\0'; |
mjr | 82:4f6209cb5c33 | 38 | return buf; |
mjr | 82:4f6209cb5c33 | 39 | } |
mjr | 82:4f6209cb5c33 | 40 | #else |
mjr | 82:4f6209cb5c33 | 41 | # define dprintf(...) |
mjr | 86:e30a1f60f783 | 42 | # define eprintf(...) |
mjr | 82:4f6209cb5c33 | 43 | #endif |
mjr | 82:4f6209cb5c33 | 44 | |
mjr | 82:4f6209cb5c33 | 45 | // -------------------------------------------------------------------------- |
mjr | 82:4f6209cb5c33 | 46 | // |
mjr | 82:4f6209cb5c33 | 47 | // Bit-bang I2C implementation |
mjr | 82:4f6209cb5c33 | 48 | // |
mjr | 82:4f6209cb5c33 | 49 | BitBangI2C::BitBangI2C(PinName sda, PinName scl) : |
mjr | 82:4f6209cb5c33 | 50 | sclPin(scl), sdaPin(sda) |
mjr | 82:4f6209cb5c33 | 51 | { |
mjr | 82:4f6209cb5c33 | 52 | // set the default frequency to 100kHz |
mjr | 86:e30a1f60f783 | 53 | frequency(100000); |
mjr | 82:4f6209cb5c33 | 54 | } |
mjr | 82:4f6209cb5c33 | 55 | |
mjr | 86:e30a1f60f783 | 56 | void BitBangI2C::frequency(uint32_t freq) |
mjr | 82:4f6209cb5c33 | 57 | { |
mjr | 86:e30a1f60f783 | 58 | // figure the clock time per cycle |
mjr | 86:e30a1f60f783 | 59 | clkPeriod_us = 1000000/freq; |
mjr | 86:e30a1f60f783 | 60 | |
mjr | 86:e30a1f60f783 | 61 | // Figure wait times according to frequency |
mjr | 86:e30a1f60f783 | 62 | if (freq <= 100000) |
mjr | 86:e30a1f60f783 | 63 | { |
mjr | 86:e30a1f60f783 | 64 | // standard mode I2C bus - up to 100kHz |
mjr | 86:e30a1f60f783 | 65 | tLow = calcHiResWaitTime(4700); |
mjr | 86:e30a1f60f783 | 66 | tHigh = calcHiResWaitTime(4000); |
mjr | 86:e30a1f60f783 | 67 | tBuf = calcHiResWaitTime(4700); |
mjr | 86:e30a1f60f783 | 68 | tHdSta = calcHiResWaitTime(4000); |
mjr | 86:e30a1f60f783 | 69 | tSuSta = calcHiResWaitTime(4700); |
mjr | 86:e30a1f60f783 | 70 | tSuSto = calcHiResWaitTime(4000); |
mjr | 86:e30a1f60f783 | 71 | tAck = calcHiResWaitTime(300); |
mjr | 86:e30a1f60f783 | 72 | tData = calcHiResWaitTime(300); |
mjr | 86:e30a1f60f783 | 73 | tSuDat = calcHiResWaitTime(250); |
mjr | 86:e30a1f60f783 | 74 | } |
mjr | 86:e30a1f60f783 | 75 | else if (freq <= 400000) |
mjr | 86:e30a1f60f783 | 76 | { |
mjr | 86:e30a1f60f783 | 77 | // fast mode I2C - up to 400kHz |
mjr | 86:e30a1f60f783 | 78 | tLow = calcHiResWaitTime(1300); |
mjr | 86:e30a1f60f783 | 79 | tHigh = calcHiResWaitTime(600); |
mjr | 86:e30a1f60f783 | 80 | tBuf = calcHiResWaitTime(1300); |
mjr | 86:e30a1f60f783 | 81 | tHdSta = calcHiResWaitTime(600); |
mjr | 86:e30a1f60f783 | 82 | tSuSta = calcHiResWaitTime(600); |
mjr | 86:e30a1f60f783 | 83 | tSuSto = calcHiResWaitTime(600); |
mjr | 86:e30a1f60f783 | 84 | tAck = calcHiResWaitTime(100); |
mjr | 86:e30a1f60f783 | 85 | tData = calcHiResWaitTime(100); |
mjr | 86:e30a1f60f783 | 86 | tSuDat = calcHiResWaitTime(100); |
mjr | 86:e30a1f60f783 | 87 | } |
mjr | 86:e30a1f60f783 | 88 | else |
mjr | 86:e30a1f60f783 | 89 | { |
mjr | 86:e30a1f60f783 | 90 | // fast mode plus - up to 1MHz |
mjr | 86:e30a1f60f783 | 91 | tLow = calcHiResWaitTime(500); |
mjr | 86:e30a1f60f783 | 92 | tHigh = calcHiResWaitTime(260); |
mjr | 86:e30a1f60f783 | 93 | tBuf = calcHiResWaitTime(500); |
mjr | 86:e30a1f60f783 | 94 | tHdSta = calcHiResWaitTime(260); |
mjr | 86:e30a1f60f783 | 95 | tSuSta = calcHiResWaitTime(260); |
mjr | 86:e30a1f60f783 | 96 | tSuSto = calcHiResWaitTime(260); |
mjr | 86:e30a1f60f783 | 97 | tAck = calcHiResWaitTime(50); |
mjr | 86:e30a1f60f783 | 98 | tData = calcHiResWaitTime(50); |
mjr | 86:e30a1f60f783 | 99 | tSuDat = calcHiResWaitTime(50); |
mjr | 86:e30a1f60f783 | 100 | } |
mjr | 82:4f6209cb5c33 | 101 | } |
mjr | 82:4f6209cb5c33 | 102 | |
mjr | 82:4f6209cb5c33 | 103 | void BitBangI2C::start() |
mjr | 82:4f6209cb5c33 | 104 | { |
mjr | 86:e30a1f60f783 | 105 | // take clock and data high |
mjr | 86:e30a1f60f783 | 106 | sclHi(); |
mjr | 86:e30a1f60f783 | 107 | sdaHi(); |
mjr | 86:e30a1f60f783 | 108 | hiResWait(tBuf); |
mjr | 82:4f6209cb5c33 | 109 | |
mjr | 82:4f6209cb5c33 | 110 | // take data low |
mjr | 86:e30a1f60f783 | 111 | sdaLo(); |
mjr | 86:e30a1f60f783 | 112 | hiResWait(tHdSta); |
mjr | 82:4f6209cb5c33 | 113 | |
mjr | 82:4f6209cb5c33 | 114 | // take clock low |
mjr | 86:e30a1f60f783 | 115 | sclLo(); |
mjr | 86:e30a1f60f783 | 116 | hiResWait(tLow); |
mjr | 82:4f6209cb5c33 | 117 | } |
mjr | 82:4f6209cb5c33 | 118 | |
mjr | 82:4f6209cb5c33 | 119 | void BitBangI2C::stop() |
mjr | 82:4f6209cb5c33 | 120 | { |
mjr | 86:e30a1f60f783 | 121 | // take SDA low |
mjr | 86:e30a1f60f783 | 122 | sdaLo(); |
mjr | 86:e30a1f60f783 | 123 | |
mjr | 82:4f6209cb5c33 | 124 | // take SCL high |
mjr | 86:e30a1f60f783 | 125 | sclHi(); |
mjr | 86:e30a1f60f783 | 126 | hiResWait(tSuSto); |
mjr | 82:4f6209cb5c33 | 127 | |
mjr | 82:4f6209cb5c33 | 128 | // take SDA high |
mjr | 86:e30a1f60f783 | 129 | sdaHi(); |
mjr | 86:e30a1f60f783 | 130 | hiResWait(tBuf); |
mjr | 82:4f6209cb5c33 | 131 | } |
mjr | 82:4f6209cb5c33 | 132 | |
mjr | 82:4f6209cb5c33 | 133 | bool BitBangI2C::wait(uint32_t timeout_us) |
mjr | 82:4f6209cb5c33 | 134 | { |
mjr | 82:4f6209cb5c33 | 135 | // set up a timer to monitor the timeout period |
mjr | 82:4f6209cb5c33 | 136 | Timer t; |
mjr | 82:4f6209cb5c33 | 137 | t.start(); |
mjr | 82:4f6209cb5c33 | 138 | |
mjr | 82:4f6209cb5c33 | 139 | // wait for an ACK |
mjr | 82:4f6209cb5c33 | 140 | for (;;) |
mjr | 82:4f6209cb5c33 | 141 | { |
mjr | 82:4f6209cb5c33 | 142 | // if SDA is low, it's an ACK |
mjr | 82:4f6209cb5c33 | 143 | if (!sdaPin.read()) |
mjr | 82:4f6209cb5c33 | 144 | return true; |
mjr | 82:4f6209cb5c33 | 145 | |
mjr | 82:4f6209cb5c33 | 146 | // if we've reached the timeout, abort |
mjr | 82:4f6209cb5c33 | 147 | if (t.read_us() > timeout_us) |
mjr | 82:4f6209cb5c33 | 148 | return false; |
mjr | 82:4f6209cb5c33 | 149 | } |
mjr | 82:4f6209cb5c33 | 150 | } |
mjr | 82:4f6209cb5c33 | 151 | |
mjr | 82:4f6209cb5c33 | 152 | void BitBangI2C::reset() |
mjr | 82:4f6209cb5c33 | 153 | { |
mjr | 82:4f6209cb5c33 | 154 | // write out 9 '1' bits |
mjr | 82:4f6209cb5c33 | 155 | for (int i = 0 ; i < 9 ; ++i) |
mjr | 82:4f6209cb5c33 | 156 | writeBit(1); |
mjr | 82:4f6209cb5c33 | 157 | |
mjr | 82:4f6209cb5c33 | 158 | // issue a start sequence |
mjr | 82:4f6209cb5c33 | 159 | start(); |
mjr | 82:4f6209cb5c33 | 160 | |
mjr | 82:4f6209cb5c33 | 161 | // take the clock high |
mjr | 86:e30a1f60f783 | 162 | sclHi(); |
mjr | 86:e30a1f60f783 | 163 | |
mjr | 86:e30a1f60f783 | 164 | // wait for a few clock cycles |
mjr | 86:e30a1f60f783 | 165 | wait_us(4*clkPeriod_us); |
mjr | 82:4f6209cb5c33 | 166 | } |
mjr | 82:4f6209cb5c33 | 167 | |
mjr | 82:4f6209cb5c33 | 168 | int BitBangI2C::write(uint8_t addr, const uint8_t *data, size_t len, bool repeated) |
mjr | 82:4f6209cb5c33 | 169 | { |
mjr | 82:4f6209cb5c33 | 170 | dprintf("i2c.write, addr=%02x [%s] %srepeat\r\n", |
mjr | 82:4f6209cb5c33 | 171 | addr, dbgbytes(data, len), repeated ? "" : "no "); |
mjr | 82:4f6209cb5c33 | 172 | |
mjr | 82:4f6209cb5c33 | 173 | // send the start signal |
mjr | 82:4f6209cb5c33 | 174 | start(); |
mjr | 82:4f6209cb5c33 | 175 | |
mjr | 82:4f6209cb5c33 | 176 | // send the address with the R/W bit set to WRITE (0) |
mjr | 82:4f6209cb5c33 | 177 | if (write(addr)) |
mjr | 82:4f6209cb5c33 | 178 | { |
mjr | 82:4f6209cb5c33 | 179 | eprintf(". i2c.write, address write failed, addr=%02x [%s] %srepeat\r\n", |
mjr | 82:4f6209cb5c33 | 180 | addr, dbgbytes(data, len), repeated ? "": "no "); |
mjr | 82:4f6209cb5c33 | 181 | return -1; |
mjr | 82:4f6209cb5c33 | 182 | } |
mjr | 82:4f6209cb5c33 | 183 | |
mjr | 82:4f6209cb5c33 | 184 | // send the data bytes |
mjr | 82:4f6209cb5c33 | 185 | for (int i = 0 ; i < len ; ++i) |
mjr | 82:4f6209cb5c33 | 186 | { |
mjr | 82:4f6209cb5c33 | 187 | if (write(data[i])) |
mjr | 82:4f6209cb5c33 | 188 | { |
mjr | 82:4f6209cb5c33 | 189 | eprintf(". i2c.write, write failed at byte %d, addr=%02x [%s] %srepeat\r\n", |
mjr | 82:4f6209cb5c33 | 190 | i, addr, dbgbytes(data, len), repeated ? "" : "no "); |
mjr | 82:4f6209cb5c33 | 191 | return -2; |
mjr | 82:4f6209cb5c33 | 192 | } |
mjr | 82:4f6209cb5c33 | 193 | } |
mjr | 82:4f6209cb5c33 | 194 | |
mjr | 82:4f6209cb5c33 | 195 | // send the stop, unless the start is to be repeated |
mjr | 82:4f6209cb5c33 | 196 | if (!repeated) |
mjr | 82:4f6209cb5c33 | 197 | stop(); |
mjr | 82:4f6209cb5c33 | 198 | |
mjr | 82:4f6209cb5c33 | 199 | // success |
mjr | 82:4f6209cb5c33 | 200 | return 0; |
mjr | 82:4f6209cb5c33 | 201 | } |
mjr | 82:4f6209cb5c33 | 202 | |
mjr | 82:4f6209cb5c33 | 203 | int BitBangI2C::read(uint8_t addr, uint8_t *data, size_t len, bool repeated) |
mjr | 82:4f6209cb5c33 | 204 | { |
mjr | 82:4f6209cb5c33 | 205 | dprintf("i2c.read, addr=%02x\r\n", addr); |
mjr | 82:4f6209cb5c33 | 206 | |
mjr | 82:4f6209cb5c33 | 207 | // send the start signal |
mjr | 82:4f6209cb5c33 | 208 | start(); |
mjr | 82:4f6209cb5c33 | 209 | |
mjr | 82:4f6209cb5c33 | 210 | // send the address with the R/W bit set to READ (1) |
mjr | 82:4f6209cb5c33 | 211 | if (write(addr | 0x01)) |
mjr | 82:4f6209cb5c33 | 212 | { |
mjr | 82:4f6209cb5c33 | 213 | eprintf(". i2c.read, read addr write failed, addr=%02x [%s] %srepeat\r\n", |
mjr | 82:4f6209cb5c33 | 214 | addr, dbgbytes(data, len), repeated ? "" : "no "); |
mjr | 82:4f6209cb5c33 | 215 | return -1; |
mjr | 82:4f6209cb5c33 | 216 | } |
mjr | 82:4f6209cb5c33 | 217 | |
mjr | 82:4f6209cb5c33 | 218 | // Read the data. Send an ACK after each byte except the last, |
mjr | 82:4f6209cb5c33 | 219 | // where we send a NAK. |
mjr | 82:4f6209cb5c33 | 220 | for ( ; len != 0 ; --len, ++data) |
mjr | 82:4f6209cb5c33 | 221 | *data = read(len > 1); |
mjr | 82:4f6209cb5c33 | 222 | |
mjr | 82:4f6209cb5c33 | 223 | // send the stop signal, unless a repeated start is indicated |
mjr | 82:4f6209cb5c33 | 224 | if (!repeated) |
mjr | 82:4f6209cb5c33 | 225 | stop(); |
mjr | 82:4f6209cb5c33 | 226 | |
mjr | 82:4f6209cb5c33 | 227 | // success |
mjr | 82:4f6209cb5c33 | 228 | return 0; |
mjr | 82:4f6209cb5c33 | 229 | } |
mjr | 82:4f6209cb5c33 | 230 | |
mjr | 82:4f6209cb5c33 | 231 | int BitBangI2C::write(uint8_t data) |
mjr | 82:4f6209cb5c33 | 232 | { |
mjr | 82:4f6209cb5c33 | 233 | // write the bits, most significant first |
mjr | 82:4f6209cb5c33 | 234 | for (int i = 0 ; i < 8 ; ++i, data <<= 1) |
mjr | 82:4f6209cb5c33 | 235 | writeBit(data & 0x80); |
mjr | 82:4f6209cb5c33 | 236 | |
mjr | 82:4f6209cb5c33 | 237 | // read and return the ACK bit |
mjr | 82:4f6209cb5c33 | 238 | return readBit(); |
mjr | 82:4f6209cb5c33 | 239 | } |
mjr | 82:4f6209cb5c33 | 240 | |
mjr | 82:4f6209cb5c33 | 241 | int BitBangI2C::read(bool ack) |
mjr | 82:4f6209cb5c33 | 242 | { |
mjr | 82:4f6209cb5c33 | 243 | // read 8 bits, most significant first |
mjr | 82:4f6209cb5c33 | 244 | uint8_t data = 0; |
mjr | 82:4f6209cb5c33 | 245 | for (int i = 0 ; i < 8 ; ++i) |
mjr | 82:4f6209cb5c33 | 246 | data = (data << 1) | readBit(); |
mjr | 82:4f6209cb5c33 | 247 | |
mjr | 82:4f6209cb5c33 | 248 | // switch to output mode and send the ACK bit |
mjr | 82:4f6209cb5c33 | 249 | writeBit(!ack); |
mjr | 82:4f6209cb5c33 | 250 | |
mjr | 82:4f6209cb5c33 | 251 | // return the data byte we read |
mjr | 82:4f6209cb5c33 | 252 | return data; |
mjr | 82:4f6209cb5c33 | 253 | } |
mjr | 82:4f6209cb5c33 | 254 | |
mjr | 82:4f6209cb5c33 | 255 | int BitBangI2C::readBit() |
mjr | 82:4f6209cb5c33 | 256 | { |
mjr | 82:4f6209cb5c33 | 257 | // take the clock high (actually, release it to the pull-up) |
mjr | 86:e30a1f60f783 | 258 | sclHi(); |
mjr | 82:4f6209cb5c33 | 259 | |
mjr | 82:4f6209cb5c33 | 260 | // Wait (within reason) for it to actually read as high. The device |
mjr | 82:4f6209cb5c33 | 261 | // can intentionally pull the clock line low to tell us to wait while |
mjr | 82:4f6209cb5c33 | 262 | // it's working on preparing the data for us. |
mjr | 82:4f6209cb5c33 | 263 | Timer t; |
mjr | 82:4f6209cb5c33 | 264 | t.start(); |
mjr | 82:4f6209cb5c33 | 265 | while (sclPin.read() == 0 && t.read_us() < 500000) ; |
mjr | 82:4f6209cb5c33 | 266 | |
mjr | 82:4f6209cb5c33 | 267 | // if the clock isn't high, we timed out |
mjr | 82:4f6209cb5c33 | 268 | if (sclPin.read() == 0) |
mjr | 82:4f6209cb5c33 | 269 | { |
mjr | 82:4f6209cb5c33 | 270 | eprintf("i2c.readBit, clock stretching timeout\r\n"); |
mjr | 82:4f6209cb5c33 | 271 | return 0; |
mjr | 82:4f6209cb5c33 | 272 | } |
mjr | 82:4f6209cb5c33 | 273 | |
mjr | 82:4f6209cb5c33 | 274 | // wait until the clock interval is up |
mjr | 82:4f6209cb5c33 | 275 | while (t.read_us() < clkPeriod_us); |
mjr | 82:4f6209cb5c33 | 276 | |
mjr | 82:4f6209cb5c33 | 277 | // read the bit |
mjr | 82:4f6209cb5c33 | 278 | bool bit = sdaPin.read(); |
mjr | 82:4f6209cb5c33 | 279 | |
mjr | 82:4f6209cb5c33 | 280 | // take the clock low again |
mjr | 86:e30a1f60f783 | 281 | sclLo(); |
mjr | 86:e30a1f60f783 | 282 | hiResWait(tLow); |
mjr | 82:4f6209cb5c33 | 283 | |
mjr | 82:4f6209cb5c33 | 284 | // return the bit |
mjr | 82:4f6209cb5c33 | 285 | return bit; |
mjr | 82:4f6209cb5c33 | 286 | } |