Your application may require multiple I2C devices or you may need I2C slave then what would you do? What about if you need I2C to work on any of the pins not just what is defined by hardware?
You can use the one wire support from GHI that runs on any IO. There are one wire chips to do most the things I2C chips do and it only needs one wire! But let us assume you still want I2C.
The answer is, I2C software emulation. This will be much slower than using the real hardware to run I2C but in many applications, this is very well okay. Especially that most I2C slave chips are used to control simple things.
Here is a class to emulate I2C. I didn’t test it but I went I am 90% sure it will just work. I ran out of time and so I am asking if someone in this community would be interested in testing it or adding to it then posting it on fezzer…you still get the points for doing so
I have tested the code on C++ before so I only ported it to C#. The code came from here I²C - Wikipedia
Here is how it works
SoftwareI2C i2c = new SoftwareI2C(Cpu.Pin.GPIO_Pin0, Cpu.Pin.GPIO_Pin1, 100);
i2c.i2c_tx(true, false, 0x55);//send start and address
i2c.i2c_rx(true, true);//read a byte with nack then stop
Here you go
using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
namespace GHIElectronics.NETMF.Hardware.Emulation
{
class SoftwareI2C
{
TristatePort _SCL, _SDA;
int I2CSPEED = 100;///////////
public SoftwareI2C(Cpu.Pin SCL, Cpu.Pin SDA, int clock)
{
_SCL = new TristatePort(SCL, true, false, Port.ResistorMode.PullUp);
_SDA = new TristatePort(SDA, true, false, Port.ResistorMode.PullUp);
_SCL.Write(false);
_SDA.Write(false);
MakePinInput(_SCL);
MakePinInput(_SDA);
//I2CSPEED = clock/ 1111????????????????
}
private void MakePinOutput(TristatePort port)
{
if (port.Active == false)
port.Active = true;
}
private void MakePinInput(TristatePort port)
{
if (port.Active == true)
port.Active = false;
}
void I2CDELAY(int delay)
{
//add code for delay
}
void CLRSCL()
{
_SCL.Write(false);
MakePinOutput(_SCL);
}
void CLRSDA()
{
_SDA.Write(false);
MakePinOutput(_SDA);
}
bool READSCL()
{
MakePinInput(_SCL);
return _SCL.Read();
}
bool READSDA()
{
MakePinInput(_SDA);
return _SDA.Read();
}
private bool start = false;
bool read_bit()
{
bool bit;
/* lets the slave drive data */
READSDA();
I2CDELAY(I2CSPEED);
/* Clock stretching */
while (READSCL() == false) ;
/* SCL is high, now data is valid */
bit = _SDA.Read();
I2CDELAY(I2CSPEED);
CLRSCL();
return bit;
}
int write_bit(bool bit)
{
if (bit)
READSDA();
else
CLRSDA();
I2CDELAY(I2CSPEED);
/* Clock stretching */
while (READSCL() == false) ;
/* SCL is high, now data is valid */
/* check that nobody is driving SDA */
if (bit && READSDA() == false)
return 0;//lost arbitration
I2CDELAY(I2CSPEED);
CLRSCL();
return 1;
}
int start_cond()
{
if (start)
{
/* set SDA to 1 */
READSDA();
I2CDELAY(I2CSPEED);
/* Clock stretching */
while (READSCL() == false) ;
}
if (READSDA() == false)
return 0;
/* SCL is high, set SDA from 1 to 0 */
CLRSDA();
I2CDELAY(I2CSPEED);
CLRSCL();
start = true;
return 1;
}
int stop_cond()
{
/* set SDA to 0 */
CLRSDA();
I2CDELAY(I2CSPEED);
/* Clock stretching */
while (READSCL() == false) ;
/* SCL is high, set SDA from 0 to 1 */
if (READSDA() == false)
return 0;
I2CDELAY(I2CSPEED);
start = false;
return 1;
}
public bool i2c_tx(bool send_start, bool send_stop, byte d)
{
uint bit;
bool nack;
if (send_start)
start_cond();
for (bit = 0; bit < 8; bit++)
{
write_bit((d & 0x80) != 0);
d <<= 1;
}
nack = read_bit();
if (send_stop)
stop_cond();
return nack;
}
public byte i2c_rx(bool nak, bool send_stop)
{
byte d = 0;
uint bit;
for (bit = 0; bit < 8; bit++)
{
d <<= 1;
if (read_bit())
d |= 1;
}
write_bit(nak);
if (send_stop)
stop_cond();
return d;
}
}
}