An I/O controller for virtual pinball machines: accelerometer nudge sensing, analog plunger input, button input encoding, LedWiz compatible output controls, and more.

Dependencies:   mbed FastIO FastPWM USBDevice

Fork of Pinscape_Controller by Mike R

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BitBangI2C.cpp Source File

BitBangI2C.cpp

00001 // Bit Bang BitBangI2C implementation for KL25Z
00002 //
00003 
00004 #include "mbed.h"
00005 #include "BitBangI2C.h"
00006 
00007 
00008 // --------------------------------------------------------------------------
00009 //
00010 // Debugging:
00011 //
00012 //   0  -> no debugging
00013 //   1  -> print (on console) error messages only
00014 //   2  -> print full diagnostics
00015 //
00016 // dprintf() = general debug diagnostics (printed only in case 2)
00017 // eprintf() = error diagnostics (printed in case 1 and above)
00018 //
00019 #define BBI2C_DEBUG 0
00020 #if BBI2C_DEBUG
00021 # define eprintf(...) printf(__VA_ARGS__)
00022 # if BBI2C_DEBUG >= 2
00023 #  define dprintf(...) printf(__VA_ARGS__)
00024 # else
00025 #  define dprintf(...)
00026 # endif
00027 static const char *dbgbytes(const uint8_t *bytes, size_t len)
00028 {
00029     static char buf[128];
00030     char *p = buf;
00031     for (int i = 0 ; i < len && p + 4 < buf + sizeof(buf) ; ++i)
00032     {
00033         if (i > 0) *p++ = ',';
00034         sprintf(p, "%02x", bytes[i]);
00035         p += 2;
00036     }
00037     *p = '\0';
00038     return buf;
00039 }
00040 #else
00041 # define dprintf(...)
00042 # define eprintf(...)
00043 #endif
00044 
00045 // --------------------------------------------------------------------------
00046 //
00047 // Bit-bang I2C implementation
00048 //
00049 BitBangI2C::BitBangI2C(PinName sda, PinName scl, bool internalPullup) :
00050     sdaPin(sda, internalPullup), sclPin(scl, internalPullup)
00051 {
00052     // set the default frequency to 100kHz
00053     frequency(100000);
00054     
00055     // we're initially in a stop
00056     inStop = true;
00057 }
00058 
00059 void BitBangI2C::frequency(uint32_t freq)
00060 {
00061     // figure the clock time per cycle
00062     clkPeriod_us = 1000000/freq;
00063 
00064     // Figure wait times according to frequency
00065     if (freq <= 100000)
00066     {
00067         // standard mode I2C bus - up to 100kHz
00068         
00069         // nanosecond parameters
00070         tLow = calcHiResWaitTime(4700);
00071         tHigh = calcHiResWaitTime(4000);
00072         tHdSta = calcHiResWaitTime(4000);
00073         tSuSta = calcHiResWaitTime(4700);
00074         tSuSto = calcHiResWaitTime(4000);
00075         tAck = calcHiResWaitTime(300);
00076         tSuDat = calcHiResWaitTime(250);
00077         tBuf = calcHiResWaitTime(4700);
00078     }
00079     else if (freq <= 400000)
00080     {
00081         // fast mode I2C - up to 400kHz
00082 
00083         // nanosecond parameters
00084         tLow = calcHiResWaitTime(1300);
00085         tHigh = calcHiResWaitTime(600);
00086         tHdSta = calcHiResWaitTime(600);
00087         tSuSta = calcHiResWaitTime(600);
00088         tSuSto = calcHiResWaitTime(600);
00089         tAck = calcHiResWaitTime(100);
00090         tSuDat = calcHiResWaitTime(100);
00091         tBuf = calcHiResWaitTime(1300);
00092     }
00093     else
00094     {
00095         // fast mode plus - up to 1MHz
00096 
00097         // nanosecond parameters
00098         tLow = calcHiResWaitTime(500);
00099         tHigh = calcHiResWaitTime(260);
00100         tHdSta = calcHiResWaitTime(260);
00101         tSuSta = calcHiResWaitTime(260);
00102         tSuSto = calcHiResWaitTime(260);
00103         tAck = calcHiResWaitTime(50);
00104         tSuDat = calcHiResWaitTime(50);
00105         tBuf = calcHiResWaitTime(500);
00106     }
00107 }
00108 
00109 void BitBangI2C::start() 
00110 {    
00111     // check to see if we're starting after a stop, or if this is a
00112     // repeated start
00113     if (inStop)
00114     {
00115         // in a stop - make sure we waited for the minimum hold time
00116         hiResWait(tBuf);
00117     }
00118     else
00119     {
00120         // repeated start - take data high
00121         sdaHi();
00122         hiResWait(tSuDat);
00123         
00124         // take clock high
00125         sclHi();
00126         
00127         // wait for the minimum setup period
00128         hiResWait(tSuSta);
00129     }
00130     
00131     // take data low
00132     sdaLo();
00133     
00134     // wait for the setup period and take clock low
00135     hiResWait(tHdSta);
00136     sclLo();
00137 
00138     // wait for the low period
00139     hiResWait(tLow);    
00140     
00141     // no longer in a stop
00142     inStop = false;
00143 }
00144 
00145 void BitBangI2C::stop() 
00146 {
00147     // if we're not in a stop, enter one
00148     if (!inStop)
00149     {
00150         // take SDA low
00151         sdaLo();
00152 
00153         // take SCL high
00154         sclHi();
00155         hiResWait(tSuSto);
00156 
00157         // take SDA high
00158         sdaHi();
00159         
00160         // we're in a stop
00161         inStop = true;
00162     }
00163 }
00164 
00165 bool BitBangI2C::wait(uint32_t timeout_us)
00166 {
00167     // set up a timer to monitor the timeout period    
00168     Timer t;
00169     t.start();
00170 
00171     // wait for an ACK
00172     for (;;)
00173     {
00174         // if SDA is low, it's an ACK
00175         if (!sdaPin.read())
00176             return true;
00177             
00178         // if we've reached the timeout, abort
00179         if (t.read_us() > timeout_us)
00180             return false;
00181     }
00182 }
00183 
00184 void BitBangI2C::reset() 
00185 {
00186     // write out 9 '1' bits
00187     for (int i = 0 ; i < 9 ; ++i)
00188         writeBit(1);
00189         
00190     // issue a start sequence
00191     start();
00192     
00193     // take the clock high
00194     sclHi();
00195     
00196     // wait for a few clock cycles
00197     wait_us(4*clkPeriod_us);
00198 }
00199 
00200 int BitBangI2C::write(uint8_t addr, const uint8_t *data, size_t len, bool repeated)
00201 {
00202     dprintf("i2c.write, addr=%02x [%s] %srepeat\r\n", 
00203         addr, dbgbytes(data, len), repeated ? "" : "no ");
00204     
00205     // send the start signal
00206     start();
00207     
00208     // send the address with the R/W bit set to WRITE (0)
00209     if (write(addr))
00210     {
00211         eprintf(". i2c.write, address write failed, addr=%02x [%s] %srepeat\r\n",
00212             addr, dbgbytes(data, len), repeated ? "": "no ");
00213         return -1;
00214     }
00215     
00216     // send the data bytes
00217     for (int i = 0 ; i < len ; ++i)
00218     {
00219         if (write(data[i]))
00220         {
00221             eprintf(". i2c.write, write failed at byte %d, addr=%02x [%s] %srepeat\r\n", 
00222                 i, addr, dbgbytes(data, len), repeated ? "" : "no ");
00223             return -2;
00224         }
00225     }
00226     
00227     // send the stop, unless the start is to be repeated
00228     if (!repeated)
00229         stop();
00230         
00231     // success
00232     return 0;
00233 }
00234 
00235 int BitBangI2C::read(uint8_t addr, uint8_t *data, size_t len, bool repeated)
00236 {
00237     dprintf("i2c.read, addr=%02x\r\n", addr);
00238     
00239     // send the start signal
00240     start();
00241     
00242     // send the address with the R/W bit set to READ (1)
00243     if (write(addr | 0x01))
00244     {
00245         eprintf(". i2c.read, read addr write failed, addr=%02x [%s] %srepeat\r\n",
00246             addr, dbgbytes(data, len), repeated ? "" : "no ");
00247         return -1;
00248     }
00249     
00250     // Read the data.  Send an ACK after each byte except the last,
00251     // where we send a NAK.
00252     for ( ; len != 0 ; --len, ++data)
00253         *data = read(len > 1);
00254         
00255     // send the stop signal, unless a repeated start is indicated
00256     if (!repeated)
00257         stop();
00258         
00259     // success
00260     return 0;
00261 }
00262 
00263 int BitBangI2C::write(uint8_t data) 
00264 {
00265     // write the bits, most significant first
00266     for (int i = 0 ; i < 8 ; ++i, data <<= 1)
00267         writeBit(data & 0x80);
00268         
00269     // release SDA so the device can control it
00270     sdaHi();
00271         
00272     // read the ACK bit
00273     int ack = readBit();
00274     
00275     // take SDA low again
00276     sdaLo();
00277             
00278     // return success if ACK was 0
00279     return ack;
00280 }
00281 
00282 int BitBangI2C::read(bool ack) 
00283 {
00284     // take SDA high before reading
00285     sdaHi();
00286 
00287     // read 8 bits, most significant first
00288     uint8_t data = 0;
00289     for (int i = 0 ; i < 8 ; ++i)
00290         data = (data << 1) | readBit();
00291 
00292     // switch to output mode and send the ACK bit
00293     writeBit(!ack);
00294 
00295     // release SDA
00296     sdaHi();
00297 
00298     // return the data byte we read
00299     return data;
00300 }
00301 
00302 int BitBangI2C::readBit() 
00303 {
00304     // take the clock high (actually, release it to the pull-up)
00305     sclHi();
00306     
00307     // Wait (within reason) for it to actually read as high.  The device
00308     // can intentionally pull the clock line low to tell us to wait while
00309     // it's working on preparing the data for us.
00310     int t = 0;
00311     do
00312     {
00313         // if the clock is high, we're ready to go
00314         if (sclPin.read())
00315         {
00316             // wait for the data setup time
00317             hiResWait(tSuDat);
00318             
00319             // read the bit    
00320             bool bit = sdaPin.read();
00321             
00322             // take the clock low again
00323             sclLo();
00324             hiResWait(tLow);
00325             
00326             // return the bit
00327             return bit;
00328         }
00329     }
00330     while (t++ < 100000);
00331 
00332     // we timed out
00333     eprintf("i2c.readBit, clock stretching timeout\r\n");
00334     return 0;
00335 }