Bird
Raised Fist0
Embedded Cprogramming~20 mins

I2C acknowledge and NACK behavior in Embedded C - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
πŸŽ–οΈ
I2C ACK/NACK Mastery
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
I2C Master Transmit: What happens after sending address?
Consider this embedded C code snippet for an I2C master transmitting a slave address. What is the expected behavior if the slave acknowledges (ACK) the address?

i2c_start();
i2c_send_address(0x50, I2C_WRITE);
if (i2c_check_ack()) {
    // Slave acknowledged
    i2c_send_data(0xA5);
} else {
    // Slave did not acknowledge
    i2c_stop();
}

What happens after i2c_send_address if the slave sends an ACK?
Embedded C
i2c_start();
i2c_send_address(0x50, I2C_WRITE);
if (i2c_check_ack()) {
    i2c_send_data(0xA5);
} else {
    i2c_stop();
}
AThe master immediately sends a stop condition without sending data.
BThe master sends the data byte 0xA5 to the slave.
CThe master waits indefinitely for a NACK from the slave.
DThe master resets the I2C bus due to error.
Attempts:
2 left
πŸ’‘ Hint
Remember, an ACK means the slave is ready to receive data.
❓ Predict Output
intermediate
2:00remaining
I2C Slave Receive: What does NACK indicate?
In an I2C slave device, after receiving a data byte from the master, the slave sends an ACK or NACK. What does it mean if the slave sends a NACK after a data byte?

Choose the correct interpretation.
AThe slave is signaling it cannot accept more data or an error occurred.
BThe slave is requesting the master to resend the last byte.
CThe slave is initiating a bus reset.
DThe slave is ready to receive more data bytes.
Attempts:
2 left
πŸ’‘ Hint
NACK usually means stop or error in communication.
πŸ”§ Debug
advanced
3:00remaining
Why does this I2C master code hang after sending data?
Examine this I2C master code snippet. The code hangs after sending the first data byte. Identify the cause.

i2c_start();
i2c_send_address(0x68, I2C_WRITE);
if (!i2c_check_ack()) {
    i2c_stop();
    return;
}
i2c_send_data(0x12);
while (!i2c_check_ack()) {
    // wait for ACK
}
i2c_send_data(0x34);
i2c_stop();
AThe master waits for an ACK after sending the first data byte, but the slave never sends it, causing an infinite loop.
BThe start condition is not sent properly, so the slave never responds.
CThe stop condition is sent too early, causing bus reset.
DThe address sent is incorrect, so the slave ignores data bytes.
Attempts:
2 left
πŸ’‘ Hint
Check the loop waiting for ACK after sending data.
🧠 Conceptual
advanced
2:30remaining
I2C NACK on last byte: What is the master’s role?
In an I2C read operation, the master reads multiple bytes from the slave. According to the I2C protocol, the master must send an ACK after each byte except the last one, after which it sends a NACK.

Why does the master send a NACK after the last byte?
ATo reset the I2C bus for the next communication.
BTo request the slave to resend the last byte.
CTo indicate the master wants to end the read operation.
DTo signal the slave to continue sending more data bytes.
Attempts:
2 left
πŸ’‘ Hint
Think about how the master tells the slave it is done reading.
❓ Predict Output
expert
3:00remaining
What is the output of this I2C slave ACK/NACK simulation code?
This embedded C code simulates an I2C slave device sending ACK or NACK based on received data. What is the output?

#include <stdio.h>

int i2c_slave_receive_byte(int byte) {
    if (byte == 0xFF) {
        // Invalid data, send NACK
        return 0; // NACK
    } else {
        // Valid data, send ACK
        return 1; // ACK
    }
}

int main() {
    int data[] = {0x10, 0x20, 0xFF, 0x30};
    for (int i = 0; i < 4; i++) {
        int ack = i2c_slave_receive_byte(data[i]);
        if (ack) {
            printf("ACK ");
        } else {
            printf("NACK ");
        }
    }
    return 0;
}
Embedded C
#include <stdio.h>

int i2c_slave_receive_byte(int byte) {
    if (byte == 0xFF) {
        return 0; // NACK
    } else {
        return 1; // ACK
    }
}

int main() {
    int data[] = {0x10, 0x20, 0xFF, 0x30};
    for (int i = 0; i < 4; i++) {
        int ack = i2c_slave_receive_byte(data[i]);
        if (ack) {
            printf("ACK ");
        } else {
            printf("NACK ");
        }
    }
    return 0;
}
AACK NACK ACK ACK
BNACK ACK ACK NACK
CNACK NACK NACK NACK
DACK ACK NACK ACK
Attempts:
2 left
πŸ’‘ Hint
Check which byte triggers NACK in the function.

Practice

(1/5)
1. What does an ACK (Acknowledge) signal mean in I2C communication?
easy
A. The sender is requesting to resend the data
B. The receiver wants to stop communication immediately
C. The communication line is idle
D. The receiver successfully received data and is ready for more

Solution

  1. Step 1: Understand ACK meaning in I2C

    ACK means the receiver signals it has received the data correctly and is ready to continue.
  2. Step 2: Compare options with ACK meaning

    Only The receiver successfully received data and is ready for more matches this meaning; others describe stop or errors.
  3. Final Answer:

    The receiver successfully received data and is ready for more -> Option D
  4. Quick Check:

    ACK = Ready for more data [OK]
Hint: ACK means receiver says 'send more' [OK]
Common Mistakes:
  • Confusing ACK with NACK meaning
  • Thinking ACK means stop communication
  • Assuming ACK means error occurred
2. Which of the following code snippets correctly sends a NACK after reading the last byte in I2C using embedded C?
easy
A. i2c_read_byte(I2C1, ACK);
B. i2c_read_byte(I2C1, NACK);
C. i2c_write_byte(I2C1, NACK);
D. i2c_send_ack(I2C1);

Solution

  1. Step 1: Identify correct function to read with NACK

    To signal no more data is needed, the read function must be called with NACK.
  2. Step 2: Check options for correct usage

    i2c_read_byte(I2C1, NACK); uses i2c_read_byte with NACK, which is correct. Others either send ACK or write instead of read.
  3. Final Answer:

    i2c_read_byte(I2C1, NACK); -> Option B
  4. Quick Check:

    Read last byte with NACK to stop [OK]
Hint: Use read with NACK to stop reading last byte [OK]
Common Mistakes:
  • Using ACK instead of NACK after last byte
  • Calling write instead of read for NACK
  • Confusing function names for ACK/NACK
3. Consider this code snippet reading 3 bytes from an I2C device:
for (int i = 0; i < 3; i++) {
  data[i] = (i < 2) ? i2c_read_byte(I2C1, ACK) : i2c_read_byte(I2C1, NACK);
}
What is the purpose of sending NACK on the last byte?
medium
A. To request the device to resend the last byte
B. To acknowledge the last byte and continue reading
C. To indicate the master will stop reading after this byte
D. To reset the I2C bus immediately

Solution

  1. Step 1: Analyze the loop and ACK/NACK usage

    The loop reads 3 bytes; for first two bytes it sends ACK, for last byte it sends NACK.
  2. Step 2: Understand NACK meaning on last byte

    NACK signals the master will stop reading after this byte, telling the slave no more data is needed.
  3. Final Answer:

    To indicate the master will stop reading after this byte -> Option C
  4. Quick Check:

    NACK on last byte = stop reading [OK]
Hint: NACK on last byte means stop reading [OK]
Common Mistakes:
  • Thinking NACK requests resend
  • Assuming NACK resets bus
  • Confusing ACK and NACK roles
4. You wrote this code to read bytes from I2C but the slave device never stops sending data:
for (int i = 0; i < 4; i++) {
  data[i] = i2c_read_byte(I2C1, ACK);
}
What is the likely problem?
medium
A. You never sent NACK after the last byte to stop reading
B. You should use i2c_write_byte instead of i2c_read_byte
C. The loop should run 5 times instead of 4
D. You need to send a STOP condition before reading

Solution

  1. Step 1: Check ACK/NACK usage in the loop

    The code sends ACK for every byte read, never sending NACK to signal stop.
  2. Step 2: Understand effect of missing NACK

    Without NACK after last byte, slave keeps sending data, causing endless transmission.
  3. Final Answer:

    You never sent NACK after the last byte to stop reading -> Option A
  4. Quick Check:

    Missing NACK means no stop signal [OK]
Hint: Send NACK after last byte to stop slave [OK]
Common Mistakes:
  • Using ACK for all bytes including last
  • Confusing read and write functions
  • Ignoring need for STOP condition after read
5. You want to write a function that reads a variable number of bytes from an I2C device and properly sends ACK for all bytes except the last one, which should send NACK. Which code snippet correctly implements this behavior?
hard
A. for (int i = 0; i < length - 1; i++) { data[i] = i2c_read_byte(I2C1, ACK); } data[length - 1] = i2c_read_byte(I2C1, NACK);
B. for (int i = 0; i < length; i++) { data[i] = i2c_read_byte(I2C1, ACK); }
C. for (int i = 0; i < length; i++) { data[i] = i2c_read_byte(I2C1, NACK); }
D. data[0] = i2c_read_byte(I2C1, NACK); for (int i = 1; i < length; i++) { data[i] = i2c_read_byte(I2C1, ACK); }

Solution

  1. Step 1: Understand ACK/NACK pattern for multiple bytes

    All bytes except last must be read with ACK; last byte with NACK to stop.
  2. Step 2: Analyze each option

    for (int i = 0; i < length - 1; i++) { data[i] = i2c_read_byte(I2C1, ACK); } data[length - 1] = i2c_read_byte(I2C1, NACK); reads all but last byte with ACK, then last byte with NACK, correctly signaling stop. Others send wrong signals or in wrong order.
  3. Final Answer:

    for (int i = 0; i < length - 1; i++) { data[i] = i2c_read_byte(I2C1, ACK); } data[length - 1] = i2c_read_byte(I2C1, NACK); -> Option A
  4. Quick Check:

    ACK all but last, NACK last byte [OK]
Hint: Send NACK only on last byte read [OK]
Common Mistakes:
  • Sending NACK on all bytes
  • Sending ACK on last byte
  • Reading last byte first with NACK
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