Detailed Discussion on IIC Communication Protocol of FPGA
“IIC” and “I²C” are the same 2-wire serial bus. In an FPGA you typically implement it as a bit-accurate state machine plus open-drain bidirectional I/O control. Below is a detailed, practical discussion (master + slave), with the stuff that usually trips people up.
1) I²C fundamentals (what the bus really is)
Two wires, open-drain, “wired-AND”
-
SCL = clock
-
SDA = data
-
Devices never drive a ‘1’. They either:
-
drive low (0), or
-
release the line (Z) so an external pull-up resistor makes it high.
-
-
Because low is dominant, multiple devices can share the bus safely.
Start/Stop are special conditions (not “bytes”)
-
START (S): SDA goes 1→0 while SCL is high
-
STOP (P): SDA goes 0→1 while SCL is high
-
Repeated START (Sr): a START without a STOP in between (common for register reads)
Data validity rule (the golden rule)
-
SDA must be stable when SCL is high
-
SDA is allowed to change only when SCL is low
-
Receiver samples SDA on SCL rising edge (or while high, depending on implementation; rising edge is safest).
Frame format (7-bit addressing case)
-
ACK bit is the 9th clock: receiver pulls SDA low to acknowledge.
-
For reads, the master ACKs each byte except the last (NACK then STOP/Sr).
2) Electrical details you must respect on an FPGA board
Pull-up resistors matter (rise time is not “free”)
-
Rise time is set by Rpullup × bus capacitance.
-
Too weak pull-up (large R) → slow edges → timing violations at 400 kHz / 1 MHz.
-
Too strong (small R) → more current when low, may violate sink capability.
FPGA I/O must behave like open-drain
In RTL you typically control each pin with:
-
*_oe(output enable): 1 drives low, 0 releases -
The output value is usually hardwired to 0 when enabled.
Key rule: never actively drive ‘1’ on SDA/SCL.
3) FPGA implementation building blocks
A) Bidirectional pin control (open-drain style)
Conceptually:
-
sda_out_en = 1→ drive SDA low -
sda_out_en = 0→ SDA = Z (pull-up makes it high)
Same for SCL when you are master. When you are slave, you usually never drive SCL (except some special designs).
B) Synchronization & glitch filtering (critical)
SCL/SDA arrive asynchronous to your FPGA clock. You must:
-
2-FF synchronize both SCL and SDA
-
optionally add glitch filter (recommended), e.g. require a level to be stable for N cycles or use a majority filter across 3 samples
Why: without this, you get false START/STOP detection, random bit errors, or metastability-induced failures.
4) I²C Master in FPGA (how it works)
Master responsibilities
-
Generate SCL timing (100 kHz / 400 kHz / 1 MHz etc.)
-
Put SDA bits on the bus
-
Sample SDA (ACK/data)
-
Handle clock stretching (slave holds SCL low)
-
Optionally handle multi-master arbitration
Master bit timing (practical approach)
Use a quarter-cycle or half-cycle tick derived from your system clock.
For each bit:
-
SCL low phase: set SDA (drive low or release)
-
Release SCL high: if you generate SCL via open-drain, you release it and let pull-up raise it
-
Wait until SCL actually becomes high (clock stretching!)
-
Sample SDA when SCL is high (often mid-high)
-
Pull SCL low to finish the bit
ACK cycle (9th bit)
-
Master releases SDA
-
Slave drives SDA low for ACK
-
Master samples SDA during SCL high
Clock stretching support (must-have for robust master)
A slave may hold SCL low to slow the bus.
So when master “goes high,” it really:
-
releases SCL (Z)
-
waits until synchronized SCL reads high before continuing
If you skip this, some sensors/EEPROMs will randomly fail.
Master transaction examples
Write register:
Read register (repeated start):
5) I²C Slave in FPGA (how it works)
Slave is often used when FPGA is a peripheral (e.g., MCU configures FPGA registers).
Slave responsibilities
-
Detect START / STOP
-
Shift in address + R/W
-
Compare address (7-bit or 10-bit)
-
ACK appropriately
-
For write: receive data bytes and store into registers/FIFO
-
For read: put data bytes onto SDA (open-drain) and watch for master ACK/NACK
-
Support repeated starts
Slave edge usage (simple and reliable)
-
Detect START/STOP by monitoring SDA transitions while SCL is high.
-
Sample incoming bits on SCL rising edge
-
Drive outgoing bits during SCL low so they’re stable before SCL rises
ACK timing (common pitfall)
To ACK a received byte:
-
During the 8th→9th transition (while SCL low), set
sda_oe=1(drive low) -
Keep it low during the 9th clock high
-
Release SDA after the 9th clock
“Register map” slave model (very common)
A common convention:
-
First data byte after address is a register pointer
-
Subsequent bytes write data to consecutive registers
-
Reads return from the pointer and auto-increment
This matches how many MCU drivers expect I²C peripherals to behave.
6) Multi-master + arbitration (if you need it)
Many FPGA designs ignore multi-master, but here’s the rule:
-
While transmitting a ‘1’ (releasing SDA), if you read back a ‘0’, you lost arbitration (someone else pulled it low).
-
On arbitration loss: stop driving, switch to receiver, and wait for STOP (or bus idle).
Unless your system truly has multiple masters (rare in embedded products), you can often omit arbitration.
7) Common PCB/RTL mistakes (and fixes)
Mistake: Driving ‘1’ on SDA/SCL
-
Fix: open-drain control only; drive 0 or Z.
Mistake: No pull-ups (or wrong value)
-
Fix: add external pull-ups sized for your speed and capacitance.
Mistake: No clock stretching support (master)
-
Fix: when releasing SCL high, wait until SCL input actually reads high.
Mistake: No synchronizers / false START/STOP
-
Fix: 2-FF sync + simple deglitch filter.
Mistake: SDA changes when SCL high
-
Fix: update SDA only during SCL low sub-phase.
Mistake: ACK bit mis-timed
-
Fix: assert ACK (drive low) before the 9th rising edge; hold through the 9th high.
8) Verification and debug tips
Simulation
-
Build a testbench model of an I²C master/slave
-
Verify: START/STOP, ACK/NACK, repeated start, clock stretching, back-to-back bytes
On hardware
-
Use a scope/logic analyzer with I²C decode
-
If using FPGA ILA/SignalTap: probe internal synchronized SCL/SDA, FSM states,
sda_oe,scl_oe, bit counters
Bus recovery (“SDA stuck low”)
If a slave got wedged mid-byte, masters often do:
-
Toggle SCL up to 9 pulses (while releasing SDA)
-
Then generate STOP
You can implement that in an FPGA master for robustness.
9) Recommended FPGA architecture (clean and scalable)
Layered design:
-
Pin layer: open-drain IOBUF + synchronizers + glitch filter
-
Bit controller: generates SCL phases, START/STOP, samples SDA
-
Byte layer: shift register + ACK handling + counters
-
Command layer: “write N bytes”, “read N bytes”, repeated start sequences
-
Host interface: AXI-Lite / Wishbone / simple register file
This makes timing closure and feature additions much easier.

评论
发表评论