Prof Greg Egan I2C code, prevents I2C freeze when using interrupt in

Dependents:   A-Quad

Revision:
0:1c722325e933
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyI2C.cpp	Tue Aug 27 09:31:56 2013 +0000
@@ -0,0 +1,207 @@
+#include "MyI2C.h"
+ 
+const uint8_t mbed1768Pins[32] = { // Maping of mbed pins to LPC 1768 "port" pins
+    255,255,255,255,255,9,8,7,6,0,
+    1,18,17,15,16,23,24,25,26,62,
+    63,69,68,67,66,65,64,11,10,5,
+    4,255
+};
+ 
+#define I2C0SDASet (1<<mbed1768Pins[28&0x1f]) // 28
+#define I2C0SDAPort (mbed1768Pins[28&0x0f]>>5)
+PortInOut I2C0SDA(Port0, I2C0SDASet );
+ 
+#define I2C0SCLSet (1<<mbed1768Pins[27&0x1f]) // 27
+#define I2C0SCLPort (mbed1768Pins[27&0x0f]>>5)
+PortInOut I2C0SCL(Port0, I2C0SCLSet );
+ 
+MyI2C I2C0;
+ 
+bool I2C0AddressResponds(uint8_t);
+ 
+uint16_t I2CError[256];
+ 
+void SDelay(uint16_t d) 
+{ // 1.25 + 0.0475 * n uS ~0.05uS per click
+    volatile int16_t v;
+    for (v = 0; v < d ; v++ ) {};
+}  // SDelay
+ 
+#define SCLLowStartT SDelay(10)
+#define DataLowPadT SDelay(16) // 10
+#define SCLLowPadT SDelay(6)
+#define SCLHighT SDelay(10)
+ 
+#define I2CSDALow {I2C0SDA.write(0);I2C0SDA.output();SCLLowPadT;}
+#define I2CSDAFloat {I2C0SDA.input();SCLLowPadT;}
+#define I2CSCLLow {I2C0SCL.write(0);I2C0SCL.output();}
+#define I2CSCLFloat {I2C0SCL.input();SCLHighT;}
+ 
+void MyI2C::start(void)
+{
+    I2CSDAFloat;
+    bool r = waitclock();
+    I2CSDALow;
+    SCLLowStartT;
+    I2CSCLLow;
+} // start
+ 
+void MyI2C::stop(void)
+{
+    I2CSDALow;
+    bool r = waitclock();
+    I2CSDAFloat;
+    SCLLowStartT;
+} // stop
+ 
+bool MyI2C::waitclock(void)
+{
+    static uint32_t s;
+    I2CSCLFloat;        // set SCL to input, output a high
+    s = 0;
+    while ( I2C0SCL.read() == 0 )
+    {
+        if ( ++s > 16000 ) 
+        { // ~1mS
+            I2CError[0]++;
+            // possible add SCL cycles here to attempt to force device reset
+            //Stats[I2CFailS]++;
+            return (false);
+        }
+    }
+    return( true );
+} // waitclock
+ 
+uint8_t MyI2C::read(uint8_t ack) 
+{
+    static uint8_t s, d;
+    I2CSDAFloat;
+    d = 0;
+    s = 8;
+    do 
+    {
+        if ( waitclock() ) 
+        {
+            d <<= 1;
+            if ( I2C0SDA.read() ) 
+            {
+                d |= 1;
+                I2CSCLLow;
+                DataLowPadT;
+            }
+            else 
+            {
+                I2CSCLLow;
+                SDelay(10);//DataLowPadT;
+            }
+        } 
+        else
+        {
+            return( 0 );
+        }
+    } while ( --s );
+    if ( ack == I2C_NACK )
+    {
+        I2C0SDA.write(0xffff); // Port write with mask selecting SDA - messy
+    }
+    else
+    {
+        I2C0SDA.write(0);
+    }
+    I2C0SDA.output();
+    SCLLowPadT;
+    if ( waitclock() ) 
+    {
+        I2CSCLLow;
+        return( d );
+    } 
+    else
+    {
+        return( 0 );
+    }
+} // read
+ 
+uint8_t MyI2C::write(uint8_t d) 
+{
+    static uint8_t s, r;
+    for ( s = 0; s < 8; s++) 
+    {
+        if ( d & 0x80 ) 
+        {
+            I2CSDAFloat;
+        } 
+        else 
+        {
+            I2CSDALow;
+        }
+ 
+        if ( waitclock() ) 
+        {
+            I2CSCLLow;
+            d <<= 1;
+        } 
+        else
+        {
+            return(I2C_NACK);
+        }
+    }
+ 
+    I2CSDAFloat;
+    if ( waitclock() ) {
+        if ( I2C0SDA.read() )
+            r = I2C_NACK;
+        else
+            r = I2C_ACK;
+        I2CSDALow;// kill runt pulses
+        I2CSCLLow;
+        return ( r );
+    } 
+    else
+    {
+//   I2CSCLLow;
+        return(I2C_NACK);
+    }
+ 
+} // write
+ 
+uint8_t MyI2C::blockread(uint8_t a, char* S, uint8_t l)
+{
+    static uint8_t b;
+    static bool err;
+ 
+    I2C0.start();
+    err = I2C0.write(a|1) != I2C_ACK;
+    for (b = 0; b < (l - 1); b++)
+        S[b] = I2C0.read(I2C_ACK);
+    S[l-1] = I2C0.read(I2C_NACK);
+    I2C0.stop();
+ 
+    return( err );
+} // blockread
+ 
+bool MyI2C::blockwrite(uint8_t a, const char* S, uint8_t l)
+{
+    static uint8_t b;
+ 
+    I2C0.start();
+    if ( I2C0.write(a) != I2C_ACK ) goto BlockWriteError; // use this?
+    for ( b = 0; b < l; b++ )
+        if ( I2C0.write(S[b]) != I2C_ACK ) goto BlockWriteError;
+    I2C0.stop();
+ 
+    return(false);
+ 
+BlockWriteError:
+    I2C0.stop();
+ 
+    return(true);
+ 
+} // blockwrite
+ 
+bool I2C0AddressResponds(uint8_t s) {
+    static bool r;
+    I2C0.start();
+    r = I2C0.write(s) == I2C_ACK;
+    I2C0.stop();
+    return (r);
+} // I2C0AddressResponds
\ No newline at end of file