Bird
Raised Fist0
Embedded Cprogramming~20 mins

Reading data from I2C device in Embedded C - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
I2C Reading Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
What is the output of this I2C read function?

Consider this embedded C function that reads a byte from an I2C device register. What value does data hold after calling read_i2c_register(0x50, 0x10) if the device returns 0xAB at register 0x10?

Embedded C
uint8_t read_i2c_register(uint8_t device_addr, uint8_t reg_addr) {
    uint8_t data = 0;
    i2c_start();
    i2c_write(device_addr << 1); // Write mode
    i2c_write(reg_addr);
    i2c_start();
    i2c_write((device_addr << 1) | 1); // Read mode
    data = i2c_read_nack();
    i2c_stop();
    return data;
}

uint8_t data = read_i2c_register(0x50, 0x10);
A0x10
B0x00
C0xAB
D0x50
Attempts:
2 left
💡 Hint

Remember that the function reads the byte from the device register after sending the register address.

🧠 Conceptual
intermediate
1:30remaining
Which step is missing in this I2C read sequence?

This code snippet tries to read a byte from an I2C device but misses a critical step. Which step is missing?

Embedded C
i2c_start();
i2c_write(device_addr << 1); // Write mode
// Missing step here
i2c_start();
i2c_write((device_addr << 1) | 1); // Read mode
uint8_t data = i2c_read_nack();
i2c_stop();
ASending a stop condition before restart
BWriting the register address to read from
CReading with ACK instead of NACK
DDelaying between start and write
Attempts:
2 left
💡 Hint

Think about how the device knows which register you want to read.

🔧 Debug
advanced
2:30remaining
Why does this I2C read code cause a bus hang?

This code snippet causes the I2C bus to hang during reading. Identify the cause.

Embedded C
i2c_start();
i2c_write(device_addr << 1); // Write mode
i2c_write(reg_addr);
i2c_start();
i2c_write((device_addr << 1) | 1); // Read mode
uint8_t data = i2c_read_ack();
i2c_stop();
ANot shifting device address by 1 bit
BMissing <code>i2c_stop()</code> after first write
CNot sending register address before restart
DUsing <code>i2c_read_ack()</code> instead of <code>i2c_read_nack()</code> for the last byte
Attempts:
2 left
💡 Hint

Think about how the master signals the end of reading bytes.

📝 Syntax
advanced
1:30remaining
Which option fixes the syntax error in this I2C read code?

Identify the option that fixes the syntax error in this code snippet.

Embedded C
uint8_t read_byte(uint8_t device_addr, uint8_t reg_addr) {
    uint8_t data;
    i2c_start();
    i2c_write(device_addr << 1);
    i2c_write(reg_addr);
    i2c_start();
    i2c_write((device_addr << 1) | 1);
    data = i2c_read_nack();
    i2c_stop();
    return data;
}
AAdd semicolon after <code>i2c_start()</code> on line 3
BChange <code>i2c_write(device_addr << 1)</code> to <code>i2c_write(device_addr >> 1)</code>
CDeclare <code>data</code> as <code>int</code> instead of <code>uint8_t</code>
DRemove <code>return data;</code> line
Attempts:
2 left
💡 Hint

Look carefully at the line endings for missing punctuation.

🚀 Application
expert
3:00remaining
How many bytes are read by this I2C multi-byte read function?

This function reads multiple bytes from an I2C device starting at a register. How many bytes does it read?

Embedded C
void read_i2c_bytes(uint8_t device_addr, uint8_t start_reg, uint8_t *buffer, uint8_t length) {
    i2c_start();
    i2c_write(device_addr << 1); // Write mode
    i2c_write(start_reg);
    i2c_start();
    i2c_write((device_addr << 1) | 1); // Read mode
    for (uint8_t i = 0; i < length; i++) {
        if (i < length - 1) {
            buffer[i] = i2c_read_ack();
        } else {
            buffer[i] = i2c_read_nack();
        }
    }
    i2c_stop();
}

uint8_t data_buffer[5];
read_i2c_bytes(0x50, 0x20, data_buffer, 5);
A5 bytes
B4 bytes
C6 bytes
D1 byte
Attempts:
2 left
💡 Hint

Check the loop and the length parameter passed.

Practice

(1/5)
1. What is the main purpose of reading data from an I2C device in embedded C?
easy
A. To send commands to the device only
B. To get sensor or hardware information from the device
C. To reset the device hardware
D. To format the device memory

Solution

  1. Step 1: Understand I2C device communication

    I2C devices often provide sensor or hardware data that the program needs to read.
  2. Step 2: Identify the purpose of reading data

    Reading data means fetching information like sensor values, not sending commands or resetting.
  3. Final Answer:

    To get sensor or hardware information from the device -> Option B
  4. Quick Check:

    Reading I2C = Getting device data [OK]
Hint: Reading I2C means fetching data from device [OK]
Common Mistakes:
  • Confusing reading with sending commands
  • Thinking reading resets the device
  • Assuming reading formats memory
2. Which of the following is the correct way to declare a buffer to read 4 bytes from an I2C device in embedded C?
easy
A. int buffer[1];
B. int buffer = 4;
C. char buffer;
D. char buffer[4];

Solution

  1. Step 1: Understand buffer declaration for byte storage

    To store multiple bytes, we need an array of chars (bytes) of size 4.
  2. Step 2: Check each option

    char buffer[4]; declares a char array of size 4, suitable for 4 bytes. Others are either single variables or wrong types.
  3. Final Answer:

    char buffer[4]; -> Option D
  4. Quick Check:

    Buffer for 4 bytes = char array size 4 [OK]
Hint: Use char array for byte buffers [OK]
Common Mistakes:
  • Using single char instead of array
  • Using int for byte buffer
  • Declaring wrong array size
3. Given this code snippet, what will be the value of result after reading 2 bytes from the I2C device?
uint8_t buffer[2];
int result = i2c_read(device_addr, reg_addr, buffer, 2);
Assume i2c_read returns 0 on success and -1 on failure.
medium
A. 0
B. -1
C. 2
D. Undefined

Solution

  1. Step 1: Understand i2c_read return values

    The function returns 0 if the read was successful, -1 if it failed.
  2. Step 2: Analyze the code snippet

    The code reads 2 bytes and stores in buffer. If successful, result = 0.
  3. Final Answer:

    0 -> Option A
  4. Quick Check:

    Success return = 0 [OK]
Hint: i2c_read returns 0 on success [OK]
Common Mistakes:
  • Assuming return is number of bytes read
  • Confusing success with failure codes
  • Ignoring return value meaning
4. Identify the error in this code snippet for reading 1 byte from an I2C device:
uint8_t data;
int status = i2c_read(device_addr, reg_addr, &data, 1);
if (status = 0) {
    process(data);
}
medium
A. Using assignment (=) instead of comparison (==) in if condition
B. Incorrect buffer type for reading data
C. Missing initialization of device_addr
D. Wrong number of bytes requested

Solution

  1. Step 1: Check the if condition syntax

    The condition uses single '=' which assigns 0 instead of comparing.
  2. Step 2: Understand effect of assignment in if

    Assignment returns 0 (false), so process(data) never runs even on success.
  3. Final Answer:

    Using assignment (=) instead of comparison (==) in if condition -> Option A
  4. Quick Check:

    Use '==' for comparison in if [OK]
Hint: Use '==' to compare, not '=' in conditions [OK]
Common Mistakes:
  • Confusing '=' and '==' in if statements
  • Ignoring return status check
  • Not using address-of operator for buffer
5. You want to read 3 bytes from an I2C device register and combine them into a 24-bit integer. Which code snippet correctly reads and combines the data?
uint8_t buf[3];
int status = i2c_read(device_addr, reg_addr, buf, 3);
uint32_t value = ???;
hard
A. value = buf[0] | (buf[1] << 8) | (buf[2] << 16);
B. value = (buf[2] << 16) | (buf[1] << 8) | buf[0];
C. value = (buf[0] << 16) | (buf[1] << 8) | buf[2];
D. value = buf[0] + buf[1] + buf[2];

Solution

  1. Step 1: Understand byte order for 24-bit integer

    Assuming buf[0] is most significant byte, shift it left by 16 bits.
  2. Step 2: Combine bytes with bitwise OR

    Shift buf[1] by 8 bits, add buf[2] as least significant byte.
  3. Step 3: Check each option

    value = (buf[0] << 16) | (buf[1] << 8) | buf[2]; correctly combines bytes in big-endian order. Others mix order or sum bytes incorrectly.
  4. Final Answer:

    value = (buf[0] << 16) | (buf[1] << 8) | buf[2]; -> Option C
  5. Quick Check:

    Shift and OR bytes for 24-bit value [OK]
Hint: Shift bytes by 16, 8, 0 bits and OR [OK]
Common Mistakes:
  • Mixing byte order
  • Adding bytes instead of bitwise OR
  • Not shifting bytes correctly
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard