The i2c bus, also referred to as 2-Wire, allows multiple devices to be connected to a microcontroller using two wires for communication (the devices will require two additional wires for power and ground). Each device is addressed with a 7-bit value, and based on the protocol details, listens for it's address to know when to respond to a master device. This theoretically allows for 128 devices, but there are reserved address spaces that limit the total number of allowable addresses to 112. The specification also includes a 10-bit address scheme extending the total number of devices.
The goal of this article is not to explain the details of i2c, but to focus on discovering devices. If you need some background on i2c, there are numerous, well written articles all over the Internet. Here are a few links.
If you are not familiar with i2c, stop here and check out a few of these links.
Communicating With DevicesWhen communicating with an i2c device connected from withing the Raspberry Pi (focusing on Windows 10 IoT Core and C#), you would start by retrieving a device selector from the operating system. Next you would use the device selector to enumerator the i2c controllers. Finally you would create a device settings object and then retrieve an andle to your device. The code below shows the typical sequence of events for initializing an i2c device.
// ***
// *** Get a selector string that will return
// *** all I2C controllers on the system
// ***
string aqs = I2cDevice.GetDeviceSelector();
// ***
// *** Find the I2C bus controller device
// *** with our selector string
// ***
var dis = await DeviceInformation.FindAllAsync(aqs).AsTask();
// ***
// *** Create the settings and specify the device address.
// ***
var settings = new I2cConnectionSettings(0x26);
// ***
// *** Create an I2cDevice with our selected
// *** bus controller and I2C settings.
// ***
var device = await I2cDevice.FromIdAsync(dis[0].Id, settings);
In this code snippet, the last object, device, is used to communicate with the i2c hardware device in your circuit. At this point, you would simply call the Read, Write or WriteRead methods to communicate with your hardware.
See https://developer.microsoft.com/en-us/windows/iot/samples/i2caccelerometer for a full sample on how to use an i2c device with C# on Windows 10 IoT Core. An additional sample can be found at https://developer.microsoft.com/en-us/windows/iot/samples/i2cportexpander.
In the above code, the address of the device is known. In most cases, you will know the address of your device from the datasheet, however, there are many devices that have configurable addresses. When circuits contain many i2c devices, it can become difficult to keep track of all those device addresses. In addition, hard coding the device address into the code can limit flexibility. Your specific scenario may require the ablity add and remove devices in the field.
Discovering Devicesit is possible, under Windows 10 IoT Core and C# to discover the devices on the i2c bus. The method below can be called within your code to get a list of device addresses that have been discovered.
public static async Task<IEnumerable<byte>> FindDevicesAsync()
{
IList<byte> returnValue = new List<byte>();
// ***
// *** Get a selector string that will return all I2C controllers on the system
// ***
string aqs = I2cDevice.GetDeviceSelector();
// ***
// *** Find the I2C bus controller device with our selector string
// ***
var dis = await DeviceInformation.FindAllAsync(aqs).AsTask();
if (dis.Count > 0)
{
const int minimumAddress = 0x08;
const int maximumAddress = 0x77;
for (byte address = minimumAddress; address <= maximumAddress; address++)
{
var settings = new I2cConnectionSettings(address);
settings.BusSpeed = I2cBusSpeed.FastMode;
settings.SharingMode = I2cSharingMode.Shared;
// ***
// *** Create an I2cDevice with our selected bus controller and I2C settings
// ***
using (I2cDevice device = await I2cDevice.FromIdAsync(dis[0].Id, settings))
{
if (device != null)
{
try
{
byte[] writeBuffer = new byte[1] { 0 };
device.Write(writeBuffer);
// ***
// *** If no exception is thrown, there is
// *** a device at this address.
// ***
returnValue.Add(address);
}
catch
{
// ***
// *** If the address is invalid, an exception will be thrown.
// ***
}
}
}
}
}
return returnValue;
}
The FindDevicesAsync method starts by initializing the i2c controller in the same manner as the previous code sample. It differs in that, after the initialization, it loops through a set of addresses while initializing a device for each address. The lnie of code that creates the device will not fail though, so we need to actually attempt communication with the device. To do this, a call to Write is made sending a single zero byte to the device. If the device does not respond, an exception is thrown. When the exception is thrown, it is caught and ignored. If the Write operation succeeds, the address is assumed valid and it is added to the list.
Based on the specification, the address space used here is 0x08 to 0x77 (119). If this code is going to be used with 10-bit addressing, the scheme can be expanded as needed. Of course, if addresses outside of this space need to be scanned, the code can be easily adjusted.
Refining the SearchIn one of my projects, I had the need to discover a specific device while ignoring all other devices on the bus. This can be easily done if the device has a way of identifying itself (note the specification has support of for a device ID, but not all devices support this). The particular device I was using had a device ID that could be read. I added code after the statement to read the ID. If it matched what I was looking for, I added the device to the list, otherwise I ignored it. The additional code, added after the device.Write() statement, is shown below.
byte[] readBuffer = new byte[1];
device.Read(readBuffer);
if (readBuffer[0] == 0x2D)
{
returnValue.Add(address);
}
The code above could be customized for any type of device ID or could include multiple checks. You can get creative here and customize the search to suit your own specific design.
Working with the CodeThis article assumes you are already familiar with using i2c devices, but if your not, don't worry, there are plenty of examples around. Check out the Microsoft samples at www.windowsondevices.com. Of course, there are a lot of great sample projects right here on Hackster!
Comments
Please log in or sign up to comment.