5.5.5Embedded Systems & Real-Time Software

Communication interfaces — UART, SPI, I2C (master - slave), CAN bus

2,769 words13 min readdifficulty · medium

The 4 interfaces at a glance

Interface Wires Clock? Topology Typical speed Killer feature
UART 2 (TX, RX) ❌ async point-to-point ~115.2 kbps dead simple, no clock
SPI 4 (MOSI, MISO, SCLK, SS) 1 master, many slaves (SS per slave) 10s of Mbps fastest, full-duplex
I2C 2 (SDA, SCL) multi-master, addressed 100k/400k/3.4M only 2 wires for many devices
CAN 2 (CANH, CANL diff) ❌ (self-clocking) multi-master bus 1 Mbps (classic) noise-immune, prioritised, automotive

1. UART — Universal Asynchronous Receiver/Transmitter

Frame anatomy (HOW one byte travels):

idle(HIGH) | START(0) | D0 D1 D2 D3 D4 D5 D6 D7 | [PARITY] | STOP(1) | idle
  • Line idles HIGH. A falling edge (START=0) wakes the receiver.
  • Receiver waits 1.5 bit-times, then samples every 1 bit-time → lands mid-bit (robust to slight clock error).
  • LSB first.

2. SPI — Serial Peripheral Interface

4 wires: MOSI (Master Out Slave In), MISO (Master In Slave Out), SCLK, SS.

CPOL/CPHA (the famous 4 modes):

  • CPOL = idle clock level (0 = idle low, 1 = idle high).
  • CPHA = which edge samples (0 = sample on first edge, 1 = sample on second edge).
Mode CPOL CPHA Sample edge
0 0 0 rising
1 0 1 falling
2 1 0 falling
3 1 1 rising

3. I2C — Inter-Integrated Circuit

Protocol grammar (HOW a transfer is framed):

  • START: SDA falls while SCL is HIGH (a unique illegal-during-data event).
  • STOP: SDA rises while SCL is HIGH.
  • Data changes only while SCL is LOW; is valid/sampled while SCL is HIGH.
  • After every 8 bits the receiver pulls SDA low for 1 clock = ACK (HIGH = NACK).
  • First byte = [7-bit address][R/W bit].

4. CAN — Controller Area Network

Bitwise arbitration (HOW collisions are resolved without retransmit):

  • Bus is wired-AND: dominant (0) overrides recessive (1) (like I2C's wired-AND).
  • Every transmitter sends its ID and listens to the bus simultaneously.
  • If a node sends recessive(1) but reads dominant(0), it lost → backs off instantly, keeps listening.
  • The node with the numerically lowest ID (most leading dominant bits) wins and continues without any corruption. This is non-destructive arbitration — the winning message is never re-sent.

Flashcards

UART stands for and why "asynchronous"?
Universal Asynchronous Receiver/Transmitter; no shared clock wire — both sides pre-agree on baud and use start bit + timing.
What marks the start of a UART frame and why?
A START bit (line goes LOW from idle HIGH); it's the "starting gun" so the receiver knows when to begin its bit-timing.
Approx UART clock tolerance and why ~5%?
±~5.3%; from 9.5εtbit<0.5tbit9.5\varepsilon t_{bit}<0.5 t_{bit} — error accumulates over up to 9.5 bit-times before the last sample.
Name SPI's 4 lines.
MOSI, MISO, SCLK, SS (chip select, active low).
Why does SPI need one SS line per slave?
SPI has no addressing; the master selects a device only by pulling that device's SS low.
What do CPOL and CPHA control?
CPOL = idle clock polarity; CPHA = which clock edge samples data (first vs second).
Why is SPI full-duplex?
Master and slave shift registers form a ring — each clock edge sends one bit out (MOSI) and receives one in (MISO) simultaneously.
Why must I2C lines be open-drain with pull-ups?
Many devices share one wire; open-drain can only pull LOW or float, so two drivers never short — wired-AND, LOW always wins.
What is the I2C first byte?
7-bit slave address + 1 R/W bit; receiver ACKs by pulling SDA low for one clock.
How do you size an I2C pull-up resistor?
Upper bound Rp<tr,max/(0.85Cb)R_p<t_{r,max}/(0.85 C_b) for fast enough rise; lower bound Rp>(VccVOL)/IOLR_p>(V_{cc}-V_{OL})/I_{OL} to pull low enough.
What is a CAN dominant vs recessive bit?
Dominant = 0 (overrides), recessive = 1; wired-AND so dominant always wins.
How does CAN resolve simultaneous transmissions without retransmission?
Bitwise non-destructive arbitration: a node sending recessive but reading dominant loses and drops out; lowest ID (highest priority) wins intact.
Why is CAN bus length limited at high bit rate?
A node must hear the bus round-trip within one bit time to detect arbitration loss: tbit2L/vt_{bit}\ge 2L/v.
Why is CAN noise-immune?
Differential signaling — common-mode noise hits both wires equally and cancels in VCANHVCANLV_{CANH}-V_{CANL}.

Recall Feynman: explain to a 12-year-old

Imagine chips passing notes. UART: two friends, no shared clock — they agree "read one letter every second," one taps the desk to say "starting now." SPI: one boss with a metronome; whoever the boss points at (SS) trades a note with the boss every tick — super fast but the boss needs a separate finger to point at each friend. I2C: a class on a party line — everyone whispers their name first ("address"), only the matching kid answers, and the rule is "if anyone says quiet (LOW), it's quiet." CAN: kids in a noisy room shouting numbers; the kid with the smallest number always wins and finishes their sentence, and because they all whisper through two cups, the room noise cancels out.

Connections

  • Serial vs Parallel communication
  • Open-drain vs Push-pull outputs
  • Shift registers (core of SPI)
  • Differential signaling & noise immunity
  • Bit stuffing & CRC in CAN frames
  • Interrupts vs Polling (how MCUs service these peripherals)
  • Baud rate & clock generation (timers/PLL)
  • Wired-AND logic (shared by I2C and CAN arbitration)

Concept Map

needs agreement on

defines

defines

defines

instance

instance

instance

instance

no clock, uses

sample mid-bit gives

byte in

trait

trait

trait

Voltage high/low on wire

Protocol rules

Timing / clock

Wire count

Addressing / arbitration

UART async 2-wire

SPI clocked 4-wire

I2C 2-wire addressed

CAN diff bus

Start bit + baud

~5% clock tolerance

Start-Data-Stop frame

Fastest, full-duplex

Many devices, 2 wires

Noise-immune, prioritised

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho beta, sabse pehle core baat samajh lo — kisi bhi chip ke beech data bhejne ke liye wire pe sirf ek cheez travel karti hai: voltage jo high ya low hoti hai time ke saath. Bas itna hi. Toh ye saare protocols — UART, SPI, I2C, CAN — koi jaadu nahi hai, ye sirf ek "agreement" hai do chips ke beech ki: bit kab shuru hoti hai kab khatam (timing ya clock), kitne wire use karenge, aur kiski baari hai bolne ki (addressing). Jab tum ye samajh loge, toh poora subject easy lagega, kyunki har protocol bas in teen sawaalon ka alag jawab hai.

Ab har protocol apna trade-off leke aata hai. Jaise UART — ismein clock wire hi nahi hoti (asynchronous), dono side pehle se baud rate pe agree kar lete hain, phir ek "start bit" starting gun ki tarah kaam karti hai aur receiver stopwatch ki tarah har bit ke beech mein sample karta hai. Isiliye ye ~5% clock error tolerate kar leta hai — bahut simple, bas 2 wire. Wahin SPI super fast aur full-duplex hai kyunki do shift registers ek ring mein jude hote hain, har clock edge pe ek bit MOSI se bahar jaati hai aur ek MISO se andar aati hai — 8 clocks mein poora byte swap ho jaata hai, koi overhead nahi. I2C sirf 2 wire mein bahut saare devices handle karta hai (addressing se), aur CAN noise-immune hai isliye cars mein use hota hai.

Ye matter isliye karta hai kyunki real embedded systems mein tumhe choose karna padta hai — agar speed chahiye toh SPI, agar pins bachane hain toh I2C, agar simple point-to-point link chahiye toh UART, aur noisy automotive environment mein CAN. Interview aur real projects dono mein ye decision aata hai. Aur ek chhoti si important baat: jaise UART example mein dekha, start/stop bits bhi time lete hain, toh effective throughput hamesha baud rate se kam hoga — ye "overhead" wali soch tumhe practical calculations mein bachayegi.

Go deeper — visual, from zero

Test yourself — Embedded Systems & Real-Time Software

Connections