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

Dependents:   A-Quad

Files at this revision

API Documentation at this revision

Comitter:
KarimAzzouz
Date:
Tue Aug 27 09:31:56 2013 +0000
Commit message:
Prof Greg Egan I2C code, initial commit

Changed in this revision

MyI2C.cpp Show annotated file Show diff for this revision Revisions of this file
MyI2C.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 1c722325e933 MyI2C.cpp
--- /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
diff -r 000000000000 -r 1c722325e933 MyI2C.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyI2C.h	Tue Aug 27 09:31:56 2013 +0000
@@ -0,0 +1,28 @@
+#ifndef MyI2C_H
+#define MyI2C_H
+
+#include "mbed.h"
+ 
+#define I2C_ACK  true
+#define I2C_NACK false
+ 
+#define I2C_WRITE 0
+#define I2C_READ 1
+ 
+extern bool I2C0AddressResponds(uint8_t);
+ 
+class MyI2C 
+{
+private:
+    bool waitclock(void);
+public:
+    //void frequency(uint32_t f);
+    void start(void);
+    void stop(void);
+    uint8_t blockread(uint8_t r, char* b, uint8_t);
+    uint8_t read(uint8_t r);
+    bool blockwrite(uint8_t a, const char* b, uint8_t l);
+    uint8_t write(uint8_t d);
+};
+ 
+#endif
\ No newline at end of file