Bird
Raised Fist0
Embedded Cprogramming~10 mins

I2C addressing (7-bit and 10-bit) in Embedded C - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - I2C addressing (7-bit and 10-bit)
Start Condition
↓
Send Address
↓
7-bit Address?
Yes→Send 7-bit + R/W bit
↓
Wait for ACK
↓
Data Transfer
↓
10-bit Address?
Yes→Send first 7 bits + 11110 + R/W bit
↓
Wait for ACK
↓
Send last 8 bits
↓
Wait for ACK
↓
Data Transfer
↓
Stop Condition
The I2C master starts communication by sending a start condition, then sends either a 7-bit or 10-bit address with a read/write bit, waits for acknowledgment, and proceeds with data transfer before sending a stop condition.
Execution Sample
Embedded C
uint16_t address = 0x305; // 10-bit address
uint8_t addr_high = (address >> 7) & 0x06 | 0xF0 | (rw & 0x01);
uint8_t addr_low = address & 0xFF;
// Send addr_high, wait ACK
// Send addr_low, wait ACK
// Proceed with data transfer
This code prepares the two parts of a 10-bit I2C address and shows the steps to send them with acknowledgment before data transfer.
Execution Table
StepActionAddress Bits SentR/W BitACK ReceivedNext Step
1Start Condition sent---Send address bits
2Check address length0x305 (10-bit)--Send first address byte
3Send first byte (addr_high)Bits 9-8 + 111100 (write)YesSend second address byte
4Send second byte (addr_low)Bits 7-0-YesData transfer
5Data transfer---Stop condition
6Stop Condition sent---Communication ends
💡 Stop condition sent, communication ends
Variable Tracker
VariableStartAfter Step 3After Step 4Final
address0x3050x3050x3050x305
addr_highN/A0xF40xF40xF4
addr_lowN/AN/A0x050x05
ACKN/AYesYesN/A
Key Moments - 3 Insights
Why do we send two bytes for a 10-bit address but only one for a 7-bit address?
Because 7-bit addresses fit in one byte with the R/W bit, but 10-bit addresses are longer and require sending the first 7 bits with a special prefix, then the remaining 8 bits separately, as shown in steps 3 and 4 of the execution_table.
What does the R/W bit represent and where is it placed?
The R/W bit tells if the master wants to read or write. It is the least significant bit of the first byte sent, combined with the address bits, as shown in step 3.
What happens if the slave does not send an ACK after the address?
The master will stop communication or retry because the slave did not acknowledge, which means no device responded at that address. This is implied after step 3 or 4 if ACK is not received.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the value of addr_high after step 3?
A0xF4
B0x05
C0x305
D0x00
💡 Hint
Check variable_tracker row for addr_high after step 3
At which step does the master send the lower 8 bits of the 10-bit address?
AStep 2
BStep 3
CStep 4
DStep 5
💡 Hint
Look at execution_table action descriptions for step 4
If the slave does not acknowledge at step 3, what should happen next?
AProceed to data transfer
BSend stop condition and end communication
CSend second address byte anyway
DIgnore and continue
💡 Hint
Refer to key_moments explanation about missing ACK after address
Concept Snapshot
I2C addressing uses 7-bit or 10-bit addresses.
7-bit address: sent in one byte + R/W bit.
10-bit address: sent in two parts; first byte has prefix + bits 9-8 + R/W.
Slave must ACK after each address byte.
Communication ends with stop condition.
Full Transcript
This visual execution shows how I2C addressing works for 7-bit and 10-bit addresses. The master starts communication by sending a start condition, then sends the address. For 7-bit addresses, one byte is sent with the read/write bit. For 10-bit addresses, the first byte contains a special prefix plus the two most significant bits of the address and the R/W bit, followed by the second byte with the remaining 8 bits. After each byte, the slave must acknowledge. If acknowledged, data transfer proceeds. Finally, the master sends a stop condition to end communication. Variables like addr_high and addr_low hold parts of the 10-bit address. The execution table traces each step, showing actions, bits sent, and acknowledgments. Key moments clarify common confusions about address length, R/W bit placement, and handling missing acknowledgments. The quiz tests understanding of variable values and protocol flow. This helps beginners see exactly how I2C addressing happens step-by-step.

Practice

(1/5)
1.

What is the size of the standard I2C address used to identify devices?

easy
A. 7 bits
B. 8 bits
C. 10 bits
D. 16 bits

Solution

  1. Step 1: Understand I2C addressing basics

    I2C commonly uses 7-bit addresses to identify devices on the bus.
  2. Step 2: Recall standard address size

    The standard I2C address size is 7 bits, while 10-bit is an extended mode.
  3. Final Answer:

    7 bits -> Option A
  4. Quick Check:

    Standard I2C address = 7 bits [OK]
Hint: Remember standard I2C uses 7-bit addresses [OK]
Common Mistakes:
  • Confusing 7-bit with 8-bit addresses
  • Thinking 10-bit is the default
  • Assuming 16-bit addresses exist in I2C
2.

Which of the following is the correct way to prepare a 7-bit I2C address for a write operation in embedded C?

uint8_t address = 0x3C; // 7-bit address
uint8_t write_address = ?;
easy
A. write_address = address << 2;
B. write_address = (address >> 1) | 1;
C. write_address = address | 0x80;
D. write_address = (address << 1) | 0;

Solution

  1. Step 1: Shift 7-bit address left by 1

    The 7-bit address must be shifted left by 1 to make room for the read/write bit.
  2. Step 2: Set read/write bit for write operation

    For write, the least significant bit is 0, so OR with 0.
  3. Final Answer:

    write_address = (address << 1) | 0; -> Option D
  4. Quick Check:

    Shift left 1 + write bit 0 = correct address [OK]
Hint: Shift left by 1, OR with 0 for write [OK]
Common Mistakes:
  • Shifting right instead of left
  • Setting read/write bit incorrectly
  • Using wrong bitwise OR values
3.

Given the following code snippet, what is the value of header for a 10-bit I2C address 0x305?

uint16_t addr = 0x305;
uint8_t header = 0xF0 | ((addr >> 7) & 0x06) | 0x00; // write operation
medium
A. 0xF6
B. 0xF0
C. 0xF2
D. 0xF4

Solution

  1. Step 1: Analyze addr = 0x305

    Binary 0b1100000101 (bits 9-0: bit9=1, bit8=1, bit7=0). Shift right 7: 0b110 (6).
  2. Step 2: Mask and compute header

    (6 & 0x06) = 0x06. Then 0xF0 | 0x06 | 0x00 = 0xF6.
  3. Final Answer:

    0xF6 -> Option A
  4. Quick Check:

    0xF0 | ((0x305 >> 7) & 0x06) = 0xF6 [OK]
Hint: Shift address right 7, mask with 0x06, OR with 0xF0 [OK]
Common Mistakes:
  • Not shifting address before masking
  • Incorrect mask value
  • Confusing read/write bit in header
4.

Identify the error in this code snippet for sending a 10-bit I2C address:

uint16_t addr = 0x3FF;
uint8_t header = 0xF0 | ((addr >> 7) & 0x06) | 0x01; // read operation
uint8_t low_addr = addr & 0xFF;
// send header and low_addr over I2C
medium
A. The read/write bit in header should be 0 for read
B. The low_addr should be shifted left by 1 before sending
C. The header calculation is correct; no error
D. The mask 0x06 should be 0x07 to include all bits

Solution

  1. Step 1: Check read/write bit in header

    For read operation, the last bit is set to 1, which matches the code.
  2. Step 2: Verify mask and low address

    Mask 0x06 correctly extracts bits 7 and 8; low_addr is the lower 8 bits, no shift needed.
  3. Final Answer:

    The header calculation is correct; no error -> Option C
  4. Quick Check:

    Header and low_addr correct for 10-bit read [OK]
Hint: Check read/write bit and mask carefully [OK]
Common Mistakes:
  • Confusing read/write bit value
  • Incorrect mask for bits 7 and 8
  • Shifting low address unnecessarily
5.

You need to write a function in embedded C that takes a 10-bit I2C address and returns the two bytes to send: the header byte and the low address byte for a write operation. Which of the following implementations is correct?

void get_i2c_10bit_bytes(uint16_t addr, uint8_t *header, uint8_t *low_addr) {
    // ?
}
hard
A. header = 0xF0 | ((addr >> 7) & 0x06) | 0x00; low_addr = addr & 0xFF;
B. *header = 0xF0 | ((addr >> 7) & 0x06) | 0x00; *low_addr = addr & 0xFF;
C. *header = 0xF0 | ((addr << 7) & 0x06) | 0x00; *low_addr = addr >> 8;
D. header = 0xF0 | ((addr >> 7) & 0x07) | 0x01; low_addr = addr & 0xFF;

Solution

  1. Step 1: Use pointers to assign output values

    The function parameters header and low_addr are pointers, so use * to assign values.
  2. Step 2: Calculate header and low_addr correctly

    Header is 0xF0 ORed with bits 7 and 8 of addr shifted right 7, and OR 0 for write; low_addr is lower 8 bits.
  3. Final Answer:

    *header = 0xF0 | ((addr >> 7) & 0x06) | 0x00; *low_addr = addr & 0xFF; -> Option B
  4. Quick Check:

    Pointer dereference + correct bit ops = correct function [OK]
Hint: Use * to assign pointer outputs, shift right 7 bits [OK]
Common Mistakes:
  • Not using * to assign pointer values
  • Shifting bits incorrectly
  • Setting read/write bit wrong
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