How to Use i2cdetect and i2cget to Find a Sensor Address

One-line answer: On /dev/i2c-N nodes from i2c-dev, pick a bus with i2cdetect -l, scan addresses with i2cdetect, then read registers with i2cget.

This howto follows the kernel document Implementing I2C device drivers in userspace (Documentation/i2c/dev-interface.rst) and the i2c-tools manuals i2cdetect(8) / i2cget(8). It does not retell Device Tree authoring or libgpiod posts.

How Do You Choose the Bus Number?

One-line answer: Adapter numbers are assigned dynamically—use i2cdetect -l or /sys/class/i2c-dev/ for this boot, then pass that number (or name) to i2cdetect / i2cget.

The kernel notes that devices are usually driven in-kernel, but loading i2c-dev exposes a character device per adapter (/dev/i2c-0, /dev/i2c-1, …, major 89). Do not hard-code “bus 1 forever”; numbers can change across boots.

i2cdetect -l

# Example: scan standard addresses on bus 1 without the confirmation prompt
i2cdetect -y 1

Cell meanings from i2cdetect(8):

  • -- — probed, no response
  • UU — probe skipped because a kernel driver owns the address (strongly suggests a chip is there)
  • a hex value such as 2d — a responding chip was found

The default range is roughly 0x08–0x77. Probing uses SMBus quick write / receive byte, and the man page warns that this can confuse the bus or cause data loss. -q / -r force less-safe probe methods and are not recommended.

Once you have an address, a typical register read (i2cget(8)):

# bus 1, chip 0x2d, register 0x11 (byte read)
i2cget -y 1 0x2d 0x11

From C, open /dev/i2c-N, select the slave with ioctl(file, I2C_SLAVE, addr), then use i2c_smbus_* helpers (libi2c from i2c-tools) or I2C_RDWR. Because of inlines, compile with -O or similar (kernel docs IMPORTANT note).

What If You Lack Permissions?

One-line answer: You need read/write access to /dev/i2c-*—usually root, or membership in whatever group your distro’s udev rules assign (often i2c).

On EACCES, check the node’s owner/group/mode. i2cget -f forces access even when a kernel driver already claimed the device; the man page calls that dangerous, so it is not the default path. A UU cell means a driver is attached—clarify ownership before poking the same address from userspace.

-y skips the confirmation prompt; combined with the wrong bus number it increases risk in scripts.

How Does This Relate to Device Tree?

One-line answer: Device Tree tells the kernel which buses, slaves, and driver bindings a board needs; /dev/i2c-* plus i2c-tools are a userspace path onto adapters that already exist. One does not replace the other.

Practical boundary:

  • Devices that belong in-kernel: bind via DT (or ACPI, etc.) and use the dedicated driver interface.
  • Scanning, bring-up, or driver-less experiments: i2cdetect / i2cget and I2C_SLAVE ioctls are the documented userspace tools.
  • Adapter presence: the controller must be registered (often via DT/platform code) before /dev/i2c-N appears. Userspace scanning does not create the controller.

DT syntax and overlays are out of scope here; this post stays on userspace address discovery and register reads.

FAQ

Q. What is /dev/i2c-*?
A. Per-adapter character devices from i2c-dev. They are not per-slave nodes; you select the address with ioctl, then run transactions on that bus.

Q. Are plain read/write enough?
A. The kernel docs note that combined transactions (read and write in one stop-less transaction) are not supported via plain read/write, which is why userspace almost always uses I2C_RDWR or SMBus helpers.

References