I2C and the .NET Micro Framework

I2C and the .NET Micro Framework

It is well-known that increasing the number of pins on an integrated circuit (IC) increases its cost. To reduce the number of pins, several serial protocols have been developed to transfer data between IC's. One such protocol, I2C, uses only 2 bidirectional open-drain wires.

For a recent application, I needed to write a quick class to communicate to a Newhaven LCD display over the I2C bus. I'll demonstrate how simple it was to get up and running using the Micro Framework.

In a previous blog, I discussed how easy it is to use the .NET Micro Framework on an embedded target (such as the GHI Embedded Master). Microsoft has made the I2C bus very simple to access on an embedded device. All of this functionality can be accessed using the Microsoft.SPOT.Hardware.I2CDevice class.

The first step is to create our I2C class:


/// A class for writing text to an LCD Display over the I2C bus
public class I2CLCDDisplay
  private I2CDevice i2c;

  /// Initializes a new instance of the I2CLCDDisplay class.
  public I2CLCDDisplay()
    this.i2c = new I2CDevice(
      new I2CDevice.Configuration(0x50 >> 1, 100)

There's an important item to note here. From the data sheet of the display, the default I2C address of the device is 0x50. However, the I2C bus uses the least significant bit of the address byte to specify if the command is a read or write command. Thus, we must bit shift the address once to the right to account for this.

The next step is to write a public function to write text to the display:

/// Writes a string of text to the LCD.
/// Returns true if the write succeeds.
///<param name="strText">The text to display</param>
public bool WriteText(String strText)
  // First, convert the string of text into an array of bytes
  byte[] buffer = Encoding.UTF8.GetBytes(strText);

  // Create a write transaction with the text as our data
  I2CDevice.I2CTransaction transaction =

  // Create a list of transactions to execute.
  // In this case, there is only this one transaction.
  I2CDevice.I2CTransaction[] transationList =
    new I2CDevice.I2CTransaction[] { transaction };

  // Execute the transaction.
  // This call actually sends the data on the I2C bus.
  // We use a timeout of 100ms here, since the data
  // shouldn't take too long to transmit.
  int nSent = this.i2c.Execute(transationList, 100);

  // If the return parameter from "i2c.Execute()" call equals
  // the length of the data that we were trying to send, then
  // the data was sent successfully.
  return (nSent == transaction.Buffer.Length);

It's just that simple! Keep in mind that if your application required a number of commands to be sent in quick succession, you can build a transaction list (I2CDevice.I2CTransaction[]) of the commands, and the I2CDevice class will send them back to back in native code.

Learn more about DMC's embedded design and programming services.


Tim Long
Have you tried controlling two devices on the same bus (at different addresses)? The reason I ask is because I get an error as soon as I try to create a second device. It seems like the HAL is trying to reserve the output pins again which throws InvalidOperationException. So you'd have to dispose the I2CDevice instance (which releases the pins) and create a new instance for the second device. You would have to do this for each and every transaction, which makes for some pretty messy code and is very inefficient. Have you found a better way?
# Stargazer
Please note that you have an illegal call in your example:
I2CDevice.I2CTransaction transaction =

You cannot call CreateWriteTransaction using the reference. You need to use
I2CDevice.I2CTransaction transaction =

Post a comment

Name (required)

Email (required)

Enter the code shown above:

Related Blog Posts