I am not sure how I do a library, so I will just post here what works for me.
#include "mbed.h"
#ifndef MyI2C_H
#define MyI2C_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
#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[9&0x1f]) // 9
#define I2C0SDAPort (mbed1768Pins[9&0x0f]>>5)
PortInOut I2C0SDA(Port0, I2C0SDASet );
#define I2C0SCLSet (1<<mbed1768Pins[10&0x1f]) // 10
#define I2C0SCLPort (mbed1768Pins[10&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
#include "MyI2C.h"
extern MyI2C I2C0;
...
#define ACCADDR (0x53<<1)
char buf[20];
bool initAcc()
{
//Start sampling
buf[0]=0x2D;
buf[1]=0x08;
//Set range 2G
buf[2]=0x31;
buf[3]=0x0B;
return I2C0.blockwrite(ACCADDR, buf, 2) || I2C0.blockwrite(ACCADDR, &buf[2], 2);
}
...
It would be nice to have it written up in a published library of some sort. But im not sure how its done.
I'm not sure yet, but i think that in some situations my mbed is getting stuck inside the i2c read or write. Does anybody had the same problem?
Does anybody knows a "timeout solution" for this problem?
Thanks.