0
0
Power-electronicsHow-ToBeginner · 3 min read

How to Scan I2C Bus for Devices in Embedded C

To scan the I2C bus for devices in embedded C, you try to communicate with each possible device address by sending a start condition and checking for an acknowledgment (ACK). If a device responds with an ACK, it means a device is present at that address. This process is repeated for all valid 7-bit addresses (0x03 to 0x77).
📐

Syntax

To scan the I2C bus, you typically use these steps in embedded C:

  • start_condition(): Begin communication on the bus.
  • send_address(address): Send the 7-bit device address with the write bit.
  • check_ack(): Check if the device acknowledges (ACK) the address.
  • stop_condition(): End communication.

You repeat this for each address from 0x03 to 0x77 (valid 7-bit I2C addresses).

c
for (uint8_t address = 0x03; address <= 0x77; address++) {
    start_condition();
    send_address(address << 1); // Shift left for 7-bit address + write bit
    if (check_ack()) {
        // Device found at this address
    }
    stop_condition();
}
💻

Example

This example scans the I2C bus and prints found device addresses via a debug print function.

c
#include <stdint.h>
#include <stdio.h>

// Mock functions for I2C hardware interface
void start_condition() {
    // Start I2C communication
}

void stop_condition() {
    // Stop I2C communication
}

void send_address(uint8_t address) {
    // Send address on I2C bus
}

int check_ack() {
    // Return 1 if device ACKs, 0 otherwise
    // For demo, simulate devices at 0x50 and 0x68
    static uint8_t devices[] = {0x50, 0x68};
    for (int i = 0; i < 2; i++) {
        if ((devices[i] << 1) == address) {
            return 1;
        }
    }
    return 0;
}

void scan_i2c_bus() {
    printf("Scanning I2C bus for devices...\n");
    for (uint8_t addr = 0x03; addr <= 0x77; addr++) {
        start_condition();
        send_address(addr << 1); // 7-bit address + write bit
        if (check_ack()) {
            printf("Device found at 0x%02X\n", addr);
        }
        stop_condition();
    }
    printf("Scan complete.\n");
}

int main() {
    scan_i2c_bus();
    return 0;
}
Output
Scanning I2C bus for devices... Device found at 0x50 Device found at 0x68 Scan complete.
⚠️

Common Pitfalls

Common mistakes when scanning I2C bus include:

  • Not shifting the 7-bit address left by 1 before sending (the least significant bit is the read/write bit).
  • Ignoring the need to send a start and stop condition for each address attempt.
  • Not checking for ACK properly, leading to false positives or missed devices.
  • Scanning reserved addresses (0x00-0x02 and 0x78-0x7F) which should be avoided.
c
/* Wrong: Not shifting address and missing stop condition */
for (uint8_t addr = 0x03; addr <= 0x77; addr++) {
    start_condition();
    send_address(addr); // Missing shift
    if (check_ack()) {
        // Might not detect devices correctly
    }
    // Missing stop_condition();
}

/* Correct: Shift address and send stop condition */
for (uint8_t addr = 0x03; addr <= 0x77; addr++) {
    start_condition();
    send_address(addr << 1); // Shift left
    if (check_ack()) {
        // Device detected
    }
    stop_condition();
}
📊

Quick Reference

  • Scan addresses from 0x03 to 0x77 only.
  • Always send start and stop conditions for each address.
  • Shift 7-bit address left by 1 before sending.
  • Check for ACK to confirm device presence.
  • Avoid reserved addresses and bus errors.

Key Takeaways

Scan all valid 7-bit I2C addresses (0x03 to 0x77) by sending start, address, and stop signals.
Shift the device address left by 1 bit before sending to include the read/write bit.
Check for an acknowledgment (ACK) after sending the address to detect devices.
Always send start and stop conditions for each address attempt to avoid bus errors.
Avoid scanning reserved addresses and handle bus errors gracefully.