[go: up one dir, main page]

0% found this document useful (0 votes)
106 views50 pages

I2c Advanced Concepts Toughest Interview Questions - 1

The document provides a comprehensive guide on the I2C protocol, detailing its communication structure, advantages, and disadvantages compared to other protocols like SPI and UART. It explains how I2C operates with a master-slave architecture, using only two wires to connect multiple devices, and outlines the steps involved in data transmission, including start and stop conditions, addressing, and data frames. Additionally, it covers advanced topics such as clock stretching and repeated start conditions, along with common interview questions related to I2C.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
106 views50 pages

I2c Advanced Concepts Toughest Interview Questions - 1

The document provides a comprehensive guide on the I2C protocol, detailing its communication structure, advantages, and disadvantages compared to other protocols like SPI and UART. It explains how I2C operates with a master-slave architecture, using only two wires to connect multiple devices, and outlines the steps involved in data transmission, including start and stop conditions, addressing, and data frames. Additionally, it covers advanced topics such as clock stretching and repeated start conditions, along with common interview questions related to I2C.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 50

VLSI

INTERVIEW
PREPARATION
I2C PROTOCOL
Your Complete Experience-Level Guide
By ProV Logic

I2C Communication
Why I2C ?
How I2C Works ?
Steps in I2C Data transmission
Protocol Basics
Advanced Protocol Topics
Tricky & Advanced Level Interview Questions
I2C COMMUNICATION
I2C combines the best features of SPI and UARTs.
With I2C, you can connect multiple slaves to a single master
(like SPI) and you can have multiple masters controlling
single, or multiple slaves.
This is really useful when you want to have more than one
microcontroller logging data to a single memory card or
displaying text to a single LCD.
Like UART communication, I2C only uses two wires to
transmit data between devices:

SDA (Serial Data) – The line for the master and slave to send
and receive data
SCL (Serial Clock) – The line that carries the clock signal.
I2C is a serial communication protocol, so data is transferred
bit by bit along a single wire (the SDA line).
Like SPI, I2C is synchronous, so the output of bits is
synchronized to the sampling of bits by a clock signal shared
between the master and the slave.
The clock signal is always controlled by the master.
WHY USE I2C?
Because serial ports are asynchronous (no clock data is
transmitted), devices using them must agree ahead of time
on a data rate.
The two devices must also have clocks that are close to the
same rate, and will remain so excessive differences between
clock rates on either end will cause garbled data.
Asynchronous serial ports require hardware overhead the
UART at either end is relatively complex and difficult to
accurately implement in software if necessary.
At least one start and stop bit is a part of each frame of
data, meaning that 10 bits of transmission time are required
for each 8 bits of data sent, which eats into the data rate.

Another core fault in asynchronous serial ports is that they


are inherently suited to communications between two, and
only two, devices.
While it is possible to connect multiple devices to a single
serial port, bus contention (where two devices attempt to
drive the same line at the same time) is always an issue and
must be dealt with carefully to prevent damage to the
devices in question, usually through external hardware.
WHAT'S WRONG WITH SPI?
The most obvious drawback of SPI is the number of pins
required.
Connecting a single controller a single peripheral with an SPI
bus requires four lines; each additional peripheral device
requires one additional chip select I/O pin on the controller.
The rapid proliferation of pin connections makes it
undesirable in situations where lots of devices must be
connected to one controller.
Also, the large number of connections for each device can
make routing signals more difficult in tight PCB layout
situations.
SPI only allows one controller on the bus, but it does support
an arbitrary number of peripherals (subject only to the drive
capability of the devices connected to the bus and the
number of chip select pins available).
SPI is good for high data rate full-duplex (simultaneous
sending and receiving of data) connections, supporting clock
rates upwards of 10MHz (and thus, 10 million bits per
second) for some devices, and the speed scales nicely.
I2C - THE BEST OF BOTH WORLDS!
I2C requires a mere two wires, like asynchronous serial, but
those two wires can support up to 1008 peripheral devices.
Also, unlike SPI, I2C can support a multi-controller system,
allowing more than one controller to communicate with all
peripheral devices on the bus (although the controller devices
can't talk to each other over the bus and must take turns
using the bus lines).
Data rates fall between asynchronous serial and SPI; most I2C
devices can communicate at 100kHz or 400kHz.
There is some overhead with I2C; for every 8 bits of data to
be sent, one extra bit of meta data (the "ACK/NACK" bit,
which we'll discuss later) must be transmitted.
The hardware required to implement I2C is more complex
than SPI, but less than asynchronous serial. It can be fairly
trivially implemented in software.
HOW I2C WORKS
With I2C, data is transferred in messages.
Messages are broken up into frames of data.
Each message has an address frame that contains the binary
address of the slave, and one or more data frames that
contain the data being transmitted.
The message also includes start and stop conditions,
read/write bits, and ACK/NACK bits between each data
frame:

Start Condition: The SDA line switches from a high voltage


level to a low voltage level before the SCL line switches from
high to low.
Stop Condition: The SDA line switches from a low voltage
level to a high voltage level after the SCL line switches from
low to high.
Address Frame: A 7 or 10 bit sequence unique to each slave
that identifies the slave when the master wants to talk to it.
Read/Write Bit: A single bit specifying whether the master is
sending data to the slave (low voltage level) or requesting
data from it (high voltage level).
ACK/NACK Bit: Each frame in a message is followed by an
acknowledge/no-acknowledge bit.
If an address frame or data frame was successfully received,
an ACK bit is returned to the sender from the receiving
device.

ADDRESSING
I2C doesn’t have slave select lines like SPI, so it needs
another way to let the slave know that data is being sent to
it, and not another slave.
It does this by addressing. The address frame is always the
first frame after the start bit in a new message.
The master sends the address of the slave it wants to
communicate with to every slave connected to it.
Each slave then compares the address sent from the master
to its own address.
If the address matches, it sends a low voltage ACK bit back
to the master. If the address doesn’t match, the slave does
nothing and the SDA line remains high.

READ/WRITE BIT
The address frame includes a single bit at the end that
informs the slave whether the master wants to write data to
it or receive data from it.
If the master wants to send data to the slave, the read/write
bit is a low voltage level.
If the master is requesting data from the slave, the bit is a
high voltage level.
THE DATA FRAME
After the master detects the ACK bit from the slave, the first
data frame is ready to be sent.
The data frame is always 8 bits long, and sent with the most
significant bit first.
Each data frame is immediately followed by an ACK/NACK
bit to verify that the frame has been received successfully.
The ACK bit must be received by either the master or the
slave (depending on who is sending the data) before the next
data frame can be sent.
After all of the data frames have been sent, the master can
send a stop condition to the slave to halt the transmission.
The stop condition is a voltage transition from low to high
on the SDA line after a low to high transition on the SCL line,
with the SCL line remaining high.

STEPS IN I2C DATA TRANSMISSION


STEP 1:
The master sends the start condition to every connected
slave by switching the SDA line from a high voltage level to a
low voltage level before switching the SCL line from high to
low:
STEP 2:
The master sends each slave the 7 or 10 bit address of the
slave it wants to communicate with, along with the
read/write bit:
STEP 3:
Each slave compares the address sent from the master to its
own address.
If the address matches, the slave returns an ACK bit by
pulling the SDA line low for one bit.
If the address from the master does not match the slave’s
own address, the slave leaves the SDA line high.

STEP 4:
The master sends or receives the data frame:
STEP 6:
To stop the data transmission, the master sends a stop
condition to the slave by switching SCL high before switching
SDA high:
SINGLE MASTER WITH MULTIPLE SLAVES
Because I2C uses addressing, multiple slaves can be
controlled from a single master.
With a 7 bit address, 128 (27) unique address are available.
Using 10 bit addresses is uncommon, but provides 1,024 (210)
unique addresses.
To connect multiple slaves to a single master, wire them like
this, with 4.7K Ohm pull-up resistors connecting the SDA and
SCL lines to Vcc:

MULTIPLE MASTER WITH MULTIPLE SLAVES


Multiple masters can be connected to a single slave or
multiple slaves.
The problem with multiple masters in the same system
comes when two masters try to send or receive data at the
same time over the SDA line.
To solve this problem, each master needs to detect if the
SDA line is low or high before transmitting a message.
If the SDA line is low, this means that another master has
control of the bus, and the master should wait to send the
message.
If the SDA line is high, then it’s safe to transmit the
message.
To connect multiple masters to multiple slaves, use the
following diagram, with 4.7K Ohm pull-up resistors
connecting the SDA and SCL lines to Vcc:
PROTOCOL BASICS
Communication via I2C is more complex than with a UART or
SPI solution.
The signalling must adhere to a certain protocol for the
devices on the bus to recognize it as valid I2C
communications.
Fortunately, most devices take care of all the fiddly details
for you, allowing you to concentrate on the data you wish to
exchange.

Messages are broken up into two types of frame: an address


frame, where the controller indicates the peripheral to which
the message is being sent, and one or more data frames,
which are 8-bit data messages passed from controller to
peripheral or vice versa.
Data is placed on the SDA line after SCL goes low, and is
sampled after the SCL line goes high.
The time between clock edge and data read/write is defined
by the devices on the bus and will vary from chip to chip.
START CONDITION
To initiate the address frame, the controller device leaves
SCL high and pulls SDA low.
This puts all peripheral devices on notice that a transmission
is about to start.
If two controllers wish to take ownership of the bus at one
time, whichever device pulls SDA low first wins the race and
gains control of the bus.
It is possible to issue repeated starts, initiating a new
communication sequence without relinquishing control of the
bus to other controller(s).

ADDRESS FRAME
The address frame is always first in any new communication
sequence.
For a 7-bit address, the address is clocked out most
significant bit (MSB) first, followed by a R/W bit indicating
whether this is a read (1) or write (0) operation.
The 9th bit of the frame is the NACK/ACK bit.
This is the case for all frames (data or address).
Once the first 8 bits of the frame are sent, the receiving
device is given control over SDA.
If the receiving device does not pull the SDA line low before
the 9th clock pulse, it can be inferred that the receiving
device either did not receive the data or did not know how
to parse the message.
In that case, the exchange halts, and it's up to the controller
of the system to decide how to proceed.
DATA FRAMES
After the address frame has been sent, data can begin being
transmitted.
The controller will simply continue generating clock pulses at
a regular interval, and the data will be placed on SDA by
either the controller or the peripheral, depending on whether
the R/W bit indicated a read or write operation.
The number of data frames is arbitrary, and most peripheral
devices will auto-increment the internal register, meaning
that subsequent reads or writes will come from the next
register in line.

STOP CONDITION
Once all the data frames have been sent, the controller will
generate a stop condition.
Stop conditions are defined by a 0->1 (low to high) transition
on SDA after a 0->1 transition on SCL, with SCL remaining
high.
During normal data writing operation, the value on SDA
should not change when SCL is high, to avoid false stop
conditions.
ADVANCED PROTOCOL TOPICS
10-BIT ADDRESSES
In a 10-bit addressing system, two frames are required to
transmit the peripheral address.
The first frame will consist of the code b11110xyz, where 'x'
is the MSB of the peripheral address, y is bit 8 of the
peripheral address, and z is the read/write bit as described
above.
The first frame's ACK bit will be asserted by all peripherals
which match the first two bits of the address.

As with a normal 7-bit transfer, another transfer begins


immediately, and this transfer contains bits 7:0 of the
address.
At this point, the addressed peripheral should respond with
an ACK bit. If it doesn't, the failure mode is the same as a 7-
bit system.
Note that 10-bit address devices can coexist with 7-bit
address devices, since the leading '11110' part of the address
is not a part of any valid 7-bit addresses.
REPEATED START CONDITIONS
Sometimes, it is important that a controller be allowed to
exchange several messages in one go, without allowing other
controllers on the bus to interfere.
For this reason, the repeated start condition has been
defined.

To perform a repeated start, SDA is allowed to go high while


SCL is low, SCL is allowed to go high, and then SDA is
brought low again while SCL is high.
Because there was no stop condition on the bus, the previous
communication wasn't truly completed and the current
controller maintains control of the bus.
At this point, the next message can begin transmission.
The syntax of this new message is the same as any other
message--an address frame followed by data frames.
Any number of repeated starts is allowed, and the controller
will maintain control of the bus until it issues a stop
condition.
CLOCK STRETCHING
At times, the controller's data rate will exceed the
peripheral's ability to provide that data.
This can be because the data isn't ready yet (for instance,
the peripheral hasn't completed an analog-to-digital
conversion yet) or because a previous operation hasn't yet
completed (say, an EEPROM which hasn't completed writing
to non-volatile memory yet and needs to finish that before it
can service other requests).

In this case, some peripheral devices will execute what is


referred to as "clock stretching".
Nominally, all clocking is driven by the controller peripherals
simply put data on the bus or take data off the bus in
response to the controller's clock pulses.
At any point in the data transfer process, an addressed
peripheral can hold the SCL line low after the controller
releases it.
The controller is required to refrain from additional clock
pulses or data transfer until such time as the peripheral
releases the SCL line.
ADVANTAGES
Only uses two wires
Supports multiple masters and multiple slaves
ACK/NACK bit gives confirmation that each frame is
transferred successfully
Hardware is less complicated than with UARTs
Well known and widely used protocol

DISADVANTAGES
Slower data transfer rate than SPI
The size of the data frame is limited to 8 bits
More complicated hardware needed to implement than SPI
TRICKY INTERVIEW QUESTIONS & SOLUTIONS
1. What are the different operating speeds of I2C, and how
does the clock stretching mechanism work?
I2C supports multiple speed modes:
Standard Mode: 100 kHz
Fast Mode: 400 kHz
Fast Mode Plus: 1 MHz
High-Speed Mode: 3.4 MHz
Ultra-Fast Mode: 5 MHz

CLOCK STRETCHING MECHANISM:


The slave device can pull the SCL (Serial Clock Line) low if it
needs more time to process data, preventing the master
from generating the next clock pulse until it's ready.
The master must monitor SCL and wait for it to be released
before continuing communication.

2. How does arbitration work in I2C, and what happens if two


masters start communication simultaneously?
I2C uses a wired-AND configuration on the SDA (Serial Data Line),
meaning if multiple masters attempt to transmit simultaneously:
1. Each master starts transmitting its address.
2. If a master writes ‘1’ but reads ‘0’ (another master pulling
SDA low), it loses arbitration and stops transmission.
3. The master that keeps transmitting wins the arbitration.
Arbitration ensures only one master controls the bus at any
given time without corrupting the data.
3. In a multi-master system, how does the master know when
the bus is free to initiate communication?
A master first checks both SDA and SCL:
If both are HIGH, the bus is idle and ready for
communication.
If SDA is LOW while SCL is HIGH, the bus is in an ongoing
transfer.
If SCL is LOW, another master is controlling the clock, and
the bus is busy.
Before starting communication, the master must confirm bus
availability to avoid collisions.
4. What is clock stretching, and how can it cause bus
deadlock?
Clock stretching allows a slave to hold the SCL line LOW when it
needs more time. However, deadlock can occur if:
A master also attempts clock stretching, expecting the slave
to release SCL.
A slave device holds SCL LOW indefinitely due to an error,
locking the bus.
Proper error-handling mechanisms should be in place to
reset the bus if such a situation occurs.
5. Why does the I2C protocol use an open-drain (open-
collector) configuration instead of push-pull?
I2C uses open-drain outputs to allow multiple devices to share
the bus without conflict. Benefits include:
Prevents bus contention since multiple devices can only pull
the line LOW, never drive it HIGH.
Enables arbitration, where a dominant LOW can override a
HIGH signal without damage.
Allows devices with different voltage levels to communicate
using a pull-up resistor.
Push-pull configurations could cause high-current conflicts,
leading to bus failure.
6. How can you detect and recover from an I2C bus hang
condition?
DETECTION:
Check if SDA is stuck LOW, indicating an incomplete
transmission.
Monitor the SCL line for clock stretching beyond expected
limits.
RECOVERY:
Send 9 dummy clock pulses on SCL to force a slave to
release SDA.
If the bus remains stuck, issue a software/hardware reset.
Reinitialize the I2C peripheral and restart communication.
7. How is ACK/NACK handled in I2C, and how does a master
interpret missing ACKs?
After each byte transfer, the receiver sends an ACK (0) if
data is received successfully.
If the receiver sends a NACK (1), it indicates:
The slave address was incorrect.
The slave is not ready.
The master requested more data than the slave can
provide.
The master should retry communication or terminate the
transfer based on the NACK response.
8. Why does I2C require pull-up resistors, and how do you
determine the correct resistor value?
Pull-up resistors are needed because I2C uses an open-drain
configuration, meaning devices only pull the line LOW and
require an external resistor to pull it HIGH.
Choosing the right resistor value:
Too high → Slow rising edges, reduced speed.
Too low → High power consumption, excessive current draw.
Rpull− up ​= Vcc−VOL​
Isink
Typically, 4.7kΩ to 10kΩ is used for standard speeds, while
2.2kΩ to 4.7kΩ is preferred for fast-mode operations.

9. Can an I2C slave initiate communication with a master? If


not, how can a slave notify the master?
No, an I2C slave cannot initiate communication; only the master
can start a transaction.
SLAVE NOTIFICATION METHODS:
Interrupt Line: The slave can use a separate GPIO interrupt
line to signal the master.
Clock Stretching: The slave can hold the SCL line LOW to
indicate it needs attention.
Polling: The master periodically checks the slave’s status
through I2C.
10. Implement a fully dynamic I2C bus that supports real-time
master-slave role switching.
module i2c_dynamic_bus (
input wire clk, // System Clock
input wire rst_n, // Active-low Reset
inout wire sda, // Serial Data Line (Bidirectional)
inout wire scl, // Serial Clock Line (Bidirectional)
input wire request_master // Request to become master
);

reg sda_out, scl_out;


wire sda_in, scl_in;

assign sda = (sda_out) ? 1'bz : 1'b0;


assign scl = (scl_out) ? 1'bz : 1'b0;
assign sda_in = sda;
assign scl_in = scl;

reg is_master;
reg lost_arbitration;

always @(posedge clk or negedge rst_n) begin


if (!rst_n) begin
is_master <= 1'b0;
lost_arbitration <= 1'b0;
end else begin
if (is_master) begin
// Check for arbitration loss
if (sda_out == 1'b1 && sda_in == 1'b0) begin
lost_arbitration <= 1'b1;
is_master <= 1'b0; // Switch to slave mode
end
end else if (request_master && scl_in == 1'b1 && sda_in
== 1'b1) begin
// Bus is idle, allow role switch
is_master <= 1'b1;
lost_arbitration <= 1'b0;
end
end
end

always @(posedge clk) begin


if (is_master) begin
// Master behavior: Generate SCL/SDA signals
sda_out <= 1'b0; // Start condition
scl_out <= 1'b0; // Control SCL
end else begin
// Slave behavior: Release SCL/SDA
sda_out <= 1'b1;
scl_out <= 1'b1;
end
end

endmodule
HOW IT WORKS:
1. Master Arbitration:
When two devices attempt to transmit simultaneously,
the one detecting a mismatch on SDA loses arbitration
and switches to slave mode.
2. Slave Requests Master Role:
If a slave detects SDA and SCL both HIGH (bus idle), it
can request master mode.
3. Dynamic Switching:
A master losing arbitration automatically becomes a
slave.
A slave can become a master when the bus is idle.

11. Design an I2C controller that can automatically detect and


recover from bus deadlocks.
module i2c_deadlock_recovery (
input wire clk, // System Clock
input wire rst_n, // Active-low Reset
inout wire sda, // Serial Data Line (Bidirectional)
inout wire scl, // Serial Clock Line (Bidirectional)
output reg bus_reset // Indicates Bus Reset
);
reg sda_out, scl_out;
wire sda_in, scl_in;

assign sda = (sda_out) ? 1'bz : 1'b0;


assign scl = (scl_out) ? 1'bz : 1'b0;
assign sda_in = sda;
assign scl_in = scl;
reg [15:0] deadlock_timer;
reg [3:0] recovery_counter;
reg recovery_mode;

always @(posedge clk or negedge rst_n) begin


if (!rst_n) begin
deadlock_timer <= 16'd0;
recovery_mode <= 1'b0;
recovery_counter <= 4'd0;
bus_reset <= 1'b0;
end else begin
// Monitor SDA and SCL for deadlock conditions
if (sda_in == 1'b0 && scl_in == 1'b0) begin
deadlock_timer <= deadlock_timer + 1;
end else begin
deadlock_timer <= 16'd0;
end

// Trigger recovery if deadlock detected


if (deadlock_timer > 16'd50000) begin
recovery_mode <= 1'b1;
recovery_counter <= 4'd0;
end

// Recovery mechanism
if (recovery_mode) begin
if (recovery_counter < 4'd9) begin
scl_out <= ~scl_out; // Generate clock pulses
recovery_counter <= recovery_counter + 1;
end else begin
recovery_mode <= 1'b0;
bus_reset <= 1'b1; // Signal bus reset
end
end else begin
bus_reset <= 1'b0;
scl_out <= 1'b1; // Default state
end
end
end
endmodule

HOW IT WORKS:
1. Detects Deadlocks:
Monitors SDA and SCL continuously.
If both SDA = 0 and SCL = 0 for an extended period, a
deadlock is detected.
2. Recovers Automatically:
Generates 9 clock pulses to free any stuck slave device.
If the deadlock persists, bus reset is triggered.
3. Ensures Robust I2C Communication:
Prevents hanging devices from stalling the system.
Supports multi-master arbitration with recovery.
12. Develop an I2C arbitration system that handles multiple
masters sending conflicting data.
module i2c_arbitration (
input wire clk, // System Clock
input wire rst_n, // Active-low Reset
inout wire sda, // Serial Data Line (Bidirectional)
inout wire scl, // Serial Clock Line (Bidirectional)
input wire start_tx, // Start Transmission Request
input wire [7:0] data_in, // Data Byte to Transmit
output reg arbitration_lost // Indicates Arbitration Loss
);

reg sda_out, scl_out;


wire sda_in, scl_in;

assign sda = (sda_out) ? 1'bz : 1'b0;


assign scl = (scl_out) ? 1'bz : 1'b0;
assign sda_in = sda;
assign scl_in = scl;

reg is_master;
reg [3:0] bit_counter;
reg [7:0] shift_reg;

always @(posedge clk or negedge rst_n) begin


if (!rst_n) begin
is_master <= 1'b0;
arbitration_lost <= 1'b0;
bit_counter <= 4'd0;
shift_reg <= 8'd0;
end else begin
if (start_tx) begin
is_master <= 1'b1;
shift_reg <= data_in;
bit_counter <= 4'd0;
arbitration_lost <= 1'b0;
end

if (is_master) begin
if (bit_counter < 8) begin
sda_out <= shift_reg[7]; // Send MSB first

// Check for arbitration loss


if (sda_out == 1'b1 && sda_in == 1'b0) begin
arbitration_lost <= 1'b1;
is_master <= 1'b0; // Switch to slave mode
end else begin
shift_reg <= shift_reg << 1;
bit_counter <= bit_counter + 1;
end
end
end
end
end
endmodule
HOW IT WORKS:
1. Master Starts Transmission:
Loads the 8-bit data into a shift register.
Begins bit-wise transmission (MSB first).
2. Arbitration Handling:
Each master monitors SDA while transmitting.
If a master sends ‘1’ but reads ‘0’, it loses arbitration
and switches to slave mode.
The master sending ‘0’ wins (dominant bit).
3. Smooth Role Switching:
Losing master immediately stops transmitting.
Ensures bus integrity without data corruption.

13. Create an ultra-low-latency I2C controller optimized for


realtime embedded systems.
module i2c_ultra_low_latency (
input wire clk, // System Clock
input wire rst_n, // Active-low Reset
inout wire sda, // Serial Data Line (Bidirectional)
inout wire scl, // Serial Clock Line (Bidirectional)
input wire start_tx, // Start Transmission Request
input wire [7:0] data_in, // Data Byte to Transmit
output reg ack_received, // Acknowledgment Received
Flag
output reg done // Transmission Completed Flag
);
reg sda_out, scl_out;
wire sda_in, scl_in;
assign sda = (sda_out) ? 1'bz : 1'b0;
assign scl = (scl_out) ? 1'bz : 1'b0;
assign sda_in = sda;
assign scl_in = scl;

reg [3:0] bit_counter;


reg [7:0] shift_reg;
reg state;

localparam IDLE = 1'b0, TRANSMIT = 1'b1;

always @(posedge clk or negedge rst_n) begin


if (!rst_n) begin
bit_counter <= 4'd0;
shift_reg <= 8'd0;
state <= IDLE;
done <= 1'b0;
ack_received <= 1'b0;
end else begin
case (state)
IDLE: begin
if (start_tx) begin
shift_reg <= data_in;
bit_counter <= 4'd0;
state <= TRANSMIT;
done <= 1'b0;
end
end
TRANSMIT: begin
if (bit_counter < 8) begin
sda_out <= shift_reg[7]; // Send MSB first
shift_reg <= shift_reg << 1;
bit_counter <= bit_counter + 1;
end else begin
sda_out <= 1'b1; // Release SDA for ACK
detection
if (sda_in == 1'b0) begin
ack_received <= 1'b1;
end
state <= IDLE;
done <= 1'b1;
end
end
endcase
end
end
endmodule
HOW IT ACHIEVES ULTRA-LOW LATENCY:
1. Optimized State Machine:
Uses only 2 states (IDLE, TRANSMIT) to minimize
processing time.
2. Immediate ACK Detection:
No extra wait cycles for acknowledgment.
ACK is captured instantly in the same cycle.
14. Implement a secure I2C authentication mechanism to
prevent unauthorized device communication
module i2c_secure_auth (
input wire clk, // System Clock
input wire rst_n, // Active-low Reset
inout wire sda, // Serial Data Line (Bidirectional)
inout wire scl, // Serial Clock Line (Bidirectional)
input wire start_auth, // Start Authentication
input wire [7:0] device_id, // Unique Device ID
output reg auth_success, // Authentication Successful
output reg auth_fail // Authentication Failed
);

reg sda_out, scl_out;


wire sda_in, scl_in;

assign sda = (sda_out) ? 1'bz : 1'b0;


assign scl = (scl_out) ? 1'bz : 1'b0;
assign sda_in = sda;
assign scl_in = scl;

reg [7:0] challenge; // Random Challenge


reg [7:0] expected_resp; // Expected Response
reg [7:0] received_resp; // Received Response
reg [3:0] state;

localparam IDLE = 0, SEND_CHALLENGE = 1, WAIT_RESPONSE


= 2, VERIFY = 3;
// Pseudo-random challenge generator (LFSR)
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
challenge <= 8'hA3; // Initial seed
end else begin
challenge <= {challenge[6:0], challenge[7] ^
challenge[5]};
end
end

// Expected response calculation (Simple XOR-based HMAC)


always @(posedge clk) begin
expected_resp <= challenge ^ device_id;
end

always @(posedge clk or negedge rst_n) begin


if (!rst_n) begin
state <= IDLE;
auth_success <= 1'b0;
auth_fail <= 1'b0;
end else begin
case (state)
IDLE: begin
if (start_auth) begin
state <= SEND_CHALLENGE;
end
end
SEND_CHALLENGE: begin
sda_out <= challenge[7]; // Transmit challenge
MSB first
state <= WAIT_RESPONSE;
end
WAIT_RESPONSE: begin
received_resp <= sda_in; // Read response
state <= VERIFY;
end
VERIFY: begin
if (received_resp == expected_resp) begin
auth_success <= 1'b1;
auth_fail <= 1'b0;
end else begin
auth_success <= 1'b0;
auth_fail <= 1'b1;
end
state <= IDLE;
end
endcase
end
end
endmodule

HOW IT WORKS:
1. Challenge Generation:
2. A pseudo-random challenge (8-bit LFSR) is sent to the device.
3. Expected Response Calculation:
15. Design a high-reliability I2C system that detects and
corrects clock stretching failures
module i2c_high_reliability (
input wire clk, // System Clock
input wire rst_n, // Active-low Reset
inout wire sda, // Serial Data Line (Bidirectional)
inout wire scl, // Serial Clock Line (Bidirectional)
output reg clock_stretch_fail, // Flag for clock stretching
failure
output reg bus_recovered // Flag indicating successful
recovery
);

reg sda_out, scl_out;


wire sda_in, scl_in;

assign sda = (sda_out) ? 1'bz : 1'b0;


assign scl = (scl_out) ? 1'bz : 1'b0;
assign sda_in = sda;
assign scl_in = scl;

reg [15:0] stretch_timer;


reg [2:0] state;

localparam IDLE = 0, CHECK_SCL = 1, TIMEOUT = 2, RECOVER


= 3;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
stretch_timer <= 16'd0;
clock_stretch_fail <= 1'b0;
bus_recovered <= 1'b0;
state <= IDLE;
end else begin
case (state)
IDLE: begin
if (!scl_in) begin
state <= CHECK_SCL;
stretch_timer <= 16'd0;
end
end

CHECK_SCL: begin
if (!scl_in) begin
stretch_timer <= stretch_timer + 1;
if (stretch_timer > 16'd50000) begin //
Timeout threshold
clock_stretch_fail <= 1'b1;
state <= TIMEOUT;
end
end else begin
state <= IDLE;
end
end
TIMEOUT: begin
sda_out <= 1'b0; // Send STOP condition
scl_out <= 1'b0;
state <= RECOVER;
end

RECOVER: begin
sda_out <= 1'b1; // Release bus
scl_out <= 1'b1;
bus_recovered <= 1'b1;
clock_stretch_fail <= 1'b0;
state <= IDLE;
end
endcase
end
end
endmodule

HOW IT DETECTS AND CORRECTS CLOCK STRETCHING FAILURES:


1. Monitors SCL Line:
If SCL stays low for too long, the system detects a
possible failure.
2. Implements Timeout Mechanism:
A stretch timer counts how long SCL remains low.
If the threshold is exceeded, a clock stretching failure is
flagged.
3. Automatic Recovery:
A STOP condition is sent to release the bus.
The controller resets the SCL line to restore operation.
16. Develop an I2C-to-UART bridge that translates
communication protocols seamlessly.
module i2c_uart_bridge (
input wire clk, // System Clock
input wire rst_n, // Active-low Reset
inout wire sda, // I2C Data Line
inout wire scl, // I2C Clock Line
input wire uart_rx, // UART Receive Line
output wire uart_tx // UART Transmit Line
);

// I2C Module Signals


reg [7:0] i2c_data_in;
reg [7:0] i2c_data_out;
reg i2c_data_valid;
reg i2c_ready;

// UART Module Signals


reg [7:0] uart_data_in;
reg [7:0] uart_data_out;
reg uart_tx_start;
wire uart_tx_done;
wire uart_rx_ready;

// FIFO Buffer for Data Storage


reg [7:0] fifo [15:0]; // 16-byte buffer
integer write_ptr, read_ptr;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
write_ptr <= 0;
read_ptr <= 0;
i2c_ready <= 1;
uart_tx_start <= 0;
end else begin
// I2C to UART Data Transfer
if (i2c_data_valid) begin
fifo[write_ptr] <= i2c_data_in; // Store data in FIFO
write_ptr <= (write_ptr + 1) % 16;
i2c_ready <= 1; // Ready for next byte
end

// UART Transmission
if (write_ptr != read_ptr && !uart_tx_start) begin
uart_data_out <= fifo[read_ptr]; // Read data from
FIFO
read_ptr <= (read_ptr + 1) % 16;
uart_tx_start <= 1;
end

// Reset UART start flag when transmission is done


if (uart_tx_done)
uart_tx_start <= 0;
end
end
// Instantiate I2C and UART Modules
i2c_slave i2c_inst (
.clk(clk),
.rst_n(rst_n),
.sda(sda),
.scl(scl),
.data_out(i2c_data_in),
.data_valid(i2c_data_valid),
.ready(i2c_ready)
);
uart_tx uart_tx_inst (
.clk(clk),
.rst_n(rst_n),
.data_in(uart_data_out),
.start(uart_tx_start),
.tx_done(uart_tx_done),
.tx(uart_tx)
);
uart_rx uart_rx_inst (
.clk(clk),
.rst_n(rst_n),
.rx(uart_rx),
.data_out(uart_data_in),
.data_ready(uart_rx_ready)
);
endmodule
HOW IT WORKS:
1. I2C Slave Receives Data:
The bridge receives I2C data and stores it in a FIFO
buffer.
2. UART Transmission:
The data in the FIFO is transmitted serially over UART
when available.
3. UART Reception:
Incoming UART data is buffered and sent back over I2C.
4. Flow Control & Error Handling:
FIFO prevents overflow and ensures data
synchronization.
Transmission flags ensure correct data flow.

17. Implement a multi-level I2C address filtering system to


manage hundreds of devices
module i2c_address_filter (
input wire clk, // System Clock
input wire rst_n, // Active-low Reset
input wire [7:0] i2c_addr, // Incoming I2C Address
input wire valid, // Address Valid Signal
output reg match // Match Found Signal
);
// Address Filtering Levels
reg [7:0] device_type_filter; // Level 1: Device Type
reg [7:0] group_id_filter; // Level 2: Group ID
reg [7:0] exact_addr_filter; // Level 3: Specific Address
reg [7:0] mask; // Address Mask for Ranges
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
match <= 0;
end else if (valid) begin
// Level 1: Device Type Filtering
if ((i2c_addr & mask) == (device_type_filter & mask))
begin
// Level 2: Group ID Filtering
if ((i2c_addr & mask) == (group_id_filter & mask))
begin
// Level 3: Specific Address Filtering
if ((i2c_addr & mask) == (exact_addr_filter &
mask)) begin
match <= 1; // Address Match Found
end else begin
match <= 0;
end
end else begin
match <= 0;
end
end else begin
match <= 0;
end
end
end
endmodule
HOW IT WORKS:
1. Incoming I2C Address Check:
The system receives an I2C address and validates it
against the filtering levels.
2. Three-Level Filtering:
Level 1 - Device Type → Checks if the address belongs to
a specific category.
Level 2 - Group ID → Ensures communication within a
predefined group.
Level 3 - Exact Address → Matches with the specific
device address.
3. Masking for Dynamic Filtering:
The system applies a mask to enable address ranges and
wildcard addressing.
4. Efficient Address Matching:
The filtering process happens in one clock cycle, ensuring
minimal latency.
18. Design an I2C slave device that can autonomously switch
between standard and high-speed modes.
module i2c_slave_auto_speed (
input wire clk, // System Clock
input wire rst_n, // Active-low Reset
input wire scl, // I2C Clock Line
input wire sda, // I2C Data Line
output reg [7:0] data_out // Received Data
);
reg [15:0] clk_counter; // Counts cycles between SCL pulses
reg [7:0] shift_reg; // Shift register for receiving data
reg speed_mode; // 0 = Standard (100 kHz), 1 = High-
Speed (3.4 MHz)
reg [3:0] bit_count; // Bit counter for byte reception

// Clock Frequency Detector


always @(posedge scl or negedge rst_n) begin
if (!rst_n) begin
clk_counter <= 16'd0;
speed_mode <= 0;
end else begin
clk_counter <= 16'd0; // Reset counter on SCL edge

// Determine mode based on SCL pulse width


if (clk_counter < 16'd500)
speed_mode <= 1; // High-Speed Mode (3.4 MHz)
else
speed_mode <= 0; // Standard Mode (100 kHz)
end
end

// I2C Data Reception Logic


always @(negedge scl or negedge rst_n) begin
if (!rst_n) begin
shift_reg <= 8'd0;
bit_count <= 4'd0;
data_out <= 8'd0;
end else begin
shift_reg <= {shift_reg[6:0], sda}; // Shift in SDA bit
bit_count <= bit_count + 1;

if (bit_count == 4'd7) begin


data_out <= shift_reg; // Store received byte
bit_count <= 4'd0;
end
end
end

endmodule

19. How does a slave handle an out-of-order STOP condition?

If a master sends a STOP condition unexpectedly, the slave


should:
Reset its internal state machine to avoid data corruption.
Release the SDA line to indicate it's no longer engaged in
communication.
Ignore any incomplete transactions and wait for a new
START condition.
This prevents undefined behavior when the master improperly
terminates a transaction.
20. Why does an I2C bus sometimes experience bus
contention, and how can it be prevented?
Bus contention occurs when multiple devices attempt to drive
the SDA line at the same time. Since I2C uses an open-drain
configuration, only LOW signals dominate.
CAUSES OF CONTENTION:
Two masters trying to initiate communication
simultaneously.
A faulty slave not releasing the SDA line.
Incorrect pull-up resistor values causing unstable bus
behavior.
PREVENTION:
Implement proper arbitration in a multi-master environment.
Use a timeout mechanism to detect stuck SDA conditions.
Monitor the bus using hardware debugging tools like
oscilloscopes and logic analyzers.
Excellence in World class
VLSI Training & Placements

Do follow for updates & enquires

+91- 9182280927

You might also like