Skip to content

Most visited

Recently visited



The Inter-Integrated Circuit (IIC or I2C) bus connects simple peripheral devices with small data payloads. Sensors and actuators are common use cases for I2C. Examples include accelerometers, thermometers, LCD displays, and motor drivers.

I2C is a synchronous serial interface, which means it relies on a shared clock signal to synchronize data transfer between devices. The device in control of triggering the clock signal is known as the master. All other connected peripherals are known as slaves. Each device is connected to the same set of data signals to form a bus.

I2C devices connect using a 3-Wire interface consisting of:


Because all data is transferred over one wire, I2C only supports half-duplex communication. All communication is initiated by the master device, and the slave must respond once the master's transmission is complete.

I2C supports multiple slave devices connected along the same bus. Unlike SPI, slave devices are addressed using the I2C software protocol. Each device is programmed with a unique address and only responds to transmissions the master sends to that address. Every slave device must have an address, even if the bus contains only a single slave.

Managing the slave device connection

In order to open a connection to a particular I2C slave, you need to know the unique name of the bus. During the initial stages of development, or when porting an app to new hardware, it's helpful to discover all the available device names from PeripheralManagerService using getI2cBusList():

PeripheralManagerService manager = new PeripheralManagerService();
List<String> deviceList = manager.getI2cBusList();
if (deviceList.isEmpty()) {
    Log.i(TAG, "No I2C bus available on this device.");
} else {
    Log.i(TAG, "List of available devices: " + deviceList);

Once you know the target device name, use PeripheralManagerService to connect to that device. When you are done communicating with the peripheral device, close the connection to free up resources. Additionally, you cannot open a new connection to the device until the existing connection is closed. To close the connection, use the device's close() method.

public class HomeActivity extends Activity {
    // I2C Device Name
    private static final String I2C_DEVICE_NAME = ...;
    // I2C Slave Address
    private static final int I2C_ADDRESS = ...;

    private I2cDevice mDevice;

    protected void onCreate(Bundle savedInstanceState) {
        // Attempt to access the I2C device
        try {
            PeripheralManagerService manager = new PeripheralManagerService();
            mDevice = manager.openI2cDevice(I2C_DEVICE_NAME, I2C_ADDRESS);
        } catch (IOException e) {
            Log.w(TAG, "Unable to access I2C device", e);

    protected void onDestroy() {

        if (mDevice != null) {
            try {
                mDevice = null;
            } catch (IOException e) {
                Log.w(TAG, "Unable to close I2C device", e);

Interacting with registers

I2C slave devices organize their contents into either readable or writable registers (individual bytes of data referenced by an address value):

A common protocol implementation known as System Management Bus (SMBus) exists on top of I2C to interact with register data in a standard way. SMBus commands consist of two I2C transactions as follows:


The first transaction identifies the register address to access, and the second reads or writes the data at that address. Logical data on a slave device may often take up multiple bytes, and thus encompass multiple register addresses. The register address provided to the API is always the first register to reference.

Peripheral I/O provides three types of SMBus commands for accessing register data:

// Modify the contents of a single register
public void setRegisterFlag(I2cDevice device, int address) throws IOException {
    // Read one register from slave
    byte value = device.readRegByte(address);
    // Set bit 6
    value |= 0x40;
    // Write the updated value back to slave
    device.writeRegByte(address, value);

// Read a register block
public byte[] readCalibration(I2cDevice device, int startAddress) throws IOException {
    // Read three consecutive register values
    byte[] data = new byte[3];
    device.readRegBuffer(startAddress, data, data.length);
    return data;

Transferring raw data

When interacting with an I2C peripheral that defines its registers differently than SMBus -- or perhaps doesn't use registers at all -- use the raw read() and write() methods for full control over the data bytes transmitted across the wire. These methods will execute a single I2C transaction as follows:


With raw transfers, the device will send a single start condition before the transfer and a single stop condition after. It is not possible to combine multiple transactions with a "repeated start" condition.

The following code sample show you how to construct a raw byte buffer and write it to an I2C slave:

public void writeBuffer(I2cDevice device, byte[] buffer) throws IOException {
    int count = device.write(buffer, buffer.length);
    Log.d(TAG, "Wrote " + count + " bytes over I2C.");
This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields


Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)