Addressing circuits

Each device supporting I2C is programmed with a unique address and only responds to transmissions the master sends to that address. Every slave must have an address and it will be used on every transmission, even if the bus contains only a single slave.

We already saw these addresses when we looked at the back of the Rainbow HAT in Chapter 2, The Rainbow HAT. The I2C devices had them specified there:

  • BMP280: I2C1, 0x77
  • HT16K33L I2C1, 0x70

Those are precisely the addresses of the slaves. It is common for I2C-enabled components to have a base address and allow the last bits of it to be configured via hardware (address pins) so more than one device of the same type can be connected to the same I2C bus.

Screenshot from pcf8575 spec sheet where we see the address composition
The I2C bus has the same value on both Android Things developer kits: I2C1.

The Raspberry Pi and the iMX7D have the same value for the I2C bus. We can still have it as part of BoardDefaults, but it is reasonably safe to have it as a constant.

val i2cBus: String
get() = when (Build.DEVICE) {
DEVICE_RPI3 -> "I2C1"
DEVICE_IMX7D_PICO -> "I2C1"
else -> throw IllegalStateException("Unknown Build.DEVICE ${Build.DEVICE}")
}

In any case, you can always find the default I2C bus of a board via the PeripheralManager in the following way:

fun getI2CBus(): String {
val peripheralManager = PeripheralManager.getInstance()
val deviceList = peripheralManager.i2cBusList
if (!deviceList.isEmpty()) {
return deviceList[0]
}
return "I2C1"
}

In general, drivers abstract us from the use of the peripheral manager and we just need to build an instance of the object or call open, depending of the flavor. Most of the existing drivers have multiple variants of the open method/constructors; one of them usually that has no parameters and takes the default I2C bus and the default base address of the component, to make connecting to those devices easy.

However, if at any time you need to find out the address of an I2C peripheral manually, there is a simple method to do so:

fun scanAvailableAddresses(i2cName: String): List<Int> {
val pm = PeripheralManager.getInstance()
val availableAddresses = mutableListOf<Int>()
for (address in 0..127) {
val device = pm.openI2cDevice(i2cName, address)
try {
device.write(ByteArray(1), 1)
availableAddresses.add(address)
} catch (e: IOException) {
// Not available, not adding it
} finally {
device.close()
}
}
return availableAddresses
}

This function will loop for each address and try to write a byte to it. If it succeeds, then it means a device is connected. The function will return a list of detected device addresses.

And as always, remember that you need to have the USE_PERIPHERAL_IO permission declared on your manifest:

<uses-permission android:name="com.google.android.things.permission.USE_PERIPHERAL_IO"/>

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.25.74