Skip to main content

I2C

I²C (pronounced eye-squared-cee or eye-two-cee) was originally developed by Philips as a synchronous serial bus for communication between integrated circuits. A single master shares two wires with one or more slaves. Instead of dedicating a chip-select line to each slave (like SPI does), I²C selects the target by sending its address on the bus — saving one I/O pin per slave.

A transfer starts with a start condition from the master, followed by the slave's 7-bit address and a single bit indicating whether the master will send or receive data. The addressed slave acknowledges, the data transfer happens, and the master ends the exchange with a stop condition.

The two wires are:

  • SDA — Serial Data
  • SCL — Serial Clock
note

Common I²C bus speeds are 100 kbit/s (standard mode) and 400 kbit/s (fast mode).

Two APIs

TinyCLR offers two I²C APIs that coexist on the same hardware. Both namespaces ship in a single NuGet package — install one and you have both.

  • .NET IoT API — Microsoft's standard System.Device.I2c namespace. Use this for new code and for portability with desktop .NET IoT applications.
  • TinyCLR API — the original GHIElectronics.TinyCLR.Devices.I2c namespace. Keeps v2 code working without changes.

NuGet packages:

  • GHIElectronics.TinyCLR.Devices.I2c — contains both the System.Device.I2c (.NET IoT) and GHIElectronics.TinyCLR.Devices.I2c (TinyCLR) namespaces.
  • GHIElectronics.TinyCLR.Pins — pin name constants for SITCore boards.
tip

.NET IoT bus numbering: the busId argument to I2cConnectionSettings is the controller number minus one — I2c1busId: 0, I2c3busId: 2.

I²C master

The master is the host that initiates every transfer. A TinyCLR board is the master in this mode.

using System.Device.I2c;
using GHIElectronics.TinyCLR.Pins;

var settings = new I2cConnectionSettings(FEZBit.I2cBus.EdgeBusId, 0x1D);

using I2cDevice device = I2cDevice.Create(settings);

device.Write(new byte[] { 1, 2 }); // Send-only.
device.WriteRead(write, read); // Good for reading registers (write address, then read).

I²C slave

In slave mode, the board responds to a master initiating transfers — used when the board needs to look like an I²C peripheral to a host.

note

I²C slave mode is a TinyCLR API extension — it's not part of the Microsoft .NET IoT standard, which assumes you're always the master.

using System.Diagnostics;
using GHIElectronics.TinyCLR.Devices.I2c;
using GHIElectronics.TinyCLR.Pins;

var i2cController = I2cController.FromName(FEZBit.I2cBus.Edge);

i2cController.ReadBufferSize = 1024; // Default 256
i2cController.WriteBufferSize = 1024; // Default 256

i2cController.ClearReadBuffer();
i2cController.ClearWriteBuffer();

var i2cSettings = new I2cConnectionSettings(0x48, I2cMode.Slave);
i2cSettings.EnableClockStretching = true;

var i2cDevice = i2cController.GetDevice(i2cSettings);

i2cDevice.ErrorReceived += (sender, args) => Debug.WriteLine("Error received " + args.Error);

i2cDevice.FrameReceived += (sender, args) => {
switch (args.Event)
{
case I2cTransaction.MasterWrite:
Debug.WriteLine("Master is writing");
break;

case I2cTransaction.MasterRead:
Debug.WriteLine("Master is reading");
sender.Write(data);
break;

case I2cTransaction.MasterStop:
Debug.WriteLine("Done a frame!");
break;
}
};

Software I²C

You can drive ("bit-bang") an I²C bus in software on any GPIO pins, regardless of which ones the hardware controllers can use.

note

Software I²C is a TinyCLR API extension.

using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.I2c;
using GHIElectronics.TinyCLR.Pins;

var sda = GpioController.GetDefault().OpenPin(FEZBit.GpioPin.P0);
var scl = GpioController.GetDefault().OpenPin(FEZBit.GpioPin.P1);

var controller = I2cController.FromName(FEZBit.I2cBus.Software, sda, scl);

The internal pull-ups on the SDA and SCL pins can be enabled with a fourth argument. This is usually enough, but external 2.2 kΩ pull-ups are better for reliable operation.

var controller = I2cController.FromName(FEZBit.I2cBus.Software, sda, scl, true);
tip

Software-driven buses are slower than hardware I²C and use more CPU time, but they free you from the pin restrictions of the hardware controllers.

API reference

NamespaceDescription
GHIElectronics.TinyCLR.Devices.I2cTinyCLR I²C controller and device classes
System.Device.I2c.NET IoT standard I²C API (included in the same NuGet)