5.5.5 · D4Embedded Systems & Real-Time Software

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

3,506 words16 min readBack to topic

Before you start, one reminder of the symbols we reuse everywhere below:


L1 — Recognition

Before the L1 problems, here is the wiring picture for all four interfaces side by side — the "shape" of each bus is itself a recognition cue. Notice: UART crosses TX↔RX; SPI fans out one SS per slave; I2C shares two wires through pull-ups; CAN is a single differential pair with terminators.

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

Problem 1.1 (L1)

Four situations. For each, name the best interface (UART / SPI / I2C / CAN) and one word why. (a) One microcontroller talks to one GPS module over a 2-wire cable, no clock line available. (b) You must read a fast 20 MHz ADC, full-duplex, one chip only. (c) Twelve tiny temperature sensors must hang off just two shared wires. (d) A car engine bay: sparks everywhere, many controllers, need message priority.

Recall Solution 1.1

Map each clue to a column of the wiring figure above. (a) UART — asynchronous, only 2 signal wires (TX, RX) plus a shared ground, no clock line needed. (b) SPI — fastest (10s of Mbps), full-duplex, and one slave means the "one SS per slave" cost is tiny. (c) I2C — 2 signal wires (SDA, SCL) plus ground, shared by many addressed devices; no per-device select line. (d) CAN — differential (noise-immune, barely cares about ground) + message IDs that double as priority.

Problem 1.2 (L1)

On an idle UART line, is the voltage HIGH or LOW? What single event wakes the receiver?

Recall Solution 1.2

Idle = HIGH. The wake event is the START bit: a falling edge (HIGH→LOW). This is the "starting gun" for the receiver's stopwatch. (Remember: "HIGH" means high relative to the shared ground both chips connect to.) In the wiring figure, this is the falling edge that first appears on the TX→RX line.

Problem 1.3 (L1)

In I2C, both SDA and SCL are open-drain. In the "released" state (no chip pulling), what level does the wire sit at, and what makes it sit there?

Recall Solution 1.3

"Released" = HIGH, made high by the pull-up resistor (the two resistors drawn on the I2C column of the figure). A chip can only pull LOW or let go; letting go = the resistor wins = HIGH. This is Wired-AND logic: LOW always beats HIGH.


L2 — Application

Problem 2.1 (L2)

A UART runs at 19200 baud, 8N1 (1 start, 8 data, no parity, 1 stop). How long, in milliseconds, does it take to send the 5-character string "Hello"?

Recall Solution 2.1

WHAT: count bits, multiply by bit time. WHY: start/stop bits are on the wire too, so they count toward total time.

  • Bits per character (8N1) .
  • .
  • Per char .
  • 5 chars .

Problem 2.2 (L2)

Same as above but 8E1 (8 data + 1 even parity + 1 stop). Total time for "Hello" now?

Recall Solution 2.2

Now bits/char .

  • Per char .
  • 5 chars . Why longer? One extra overhead bit per character — the parity bit costs time even though it carries no message data.

Problem 2.3 (L2)

An I2C bus at 400 kHz has total capacitance . The spec caps the rise time at . Using , find the largest allowed pull-up .

Recall Solution 2.3

WHAT: solve the rise-time bound for . WHY: too big a resistor → slow charging → the "let go = HIGH" edge is too lazy to reach threshold in time. . So pick . What the figure below shows: three RC charging curves for the same but three different pull-ups. The orange curve () crosses the dashed HIGH threshold well before the dotted deadline; the violet curve () just barely makes the deadline (that's our answer, the limit); the magenta curve () is still climbing past the deadline — too slow, the bus would fail at 400 kHz. Watching where each curve meets the dotted line is the derivation.

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

Problem 2.4 (L2)

An SPI slave needs one SS line each. If a master must talk to 6 SPI slaves (no daisy-chain), how many total wires leave the master? (Count MOSI, MISO, SCLK shared, plus one SS per slave.)

Recall Solution 2.4

WHY MOSI + MISO + SCLK are shared (count once): these three carry data out, data in, and the clock. Every slave listens to the same clock and the same data lines — only the selected slave actually responds — so all slaves can hang off one copy of each. Sharing them costs nothing, so we count total. WHY one SS per slave (count ): SPI has no addressing. The only way the master says "I mean YOU" is by pulling that slave's own Slave Select line low. If two slaves shared an SS line, both would drive MISO at once and collide. So each slave needs its own dedicated SS → select lines for slaves. Shared: MOSI + MISO + SCLK . Selects: per slave . Total wires (plus a common ground, implied). General rule: wires for slaves.


L3 — Analysis

Problem 3.1 (L3)

A UART receiver samples the STOP bit after 9.5 bit-times (8N1). One side's clock is fast by a constant fraction per bit. What is the maximum (as a percentage) before the last sample drifts past the half-bit margin?

Recall Solution 3.1

WHAT: the worst sample is the last one, where error has piled up most. WHY: each bit adds of drift; after bits the drift is , and it must stay under half a bit (). That is why "±5% clock tolerance" is the folklore number for UART.

Problem 3.2 (L3)

Two I2C masters both start at (almost) the same instant. Master A sends address bits 1 0 1 1 0 0 1, master B sends 1 0 1 0 1 1 0 (MSB first). At which bit does the collision resolve, and who wins? Explain using wired-AND.

Recall Solution 3.2

Line up the bits and remember: dominant/LOW (0) always wins on a wired-AND bus, and a master that sends 1 but reads 0 has lost. To avoid confusion, here are both counting conventions side by side. "Position number" counts from 1 (human order, left to right); "index" counts from 0 (programmer order).

position:  1  2  3  4  5  6  7
index   :  0  1  2  3  4  5  6
A       :  1  0  1  1  ...
B       :  1  0  1  0  ...
bus     :  1  0  1  0   <- diverges here

Positions 1–3 (indices 0–2) match. At position 4 = index 3, A sends 1 (recessive), B sends 0 (dominant). The bus reads 0. A sees it sent 1 but read 0A loses and backs off. B wins and continues uncorrupted. Why lowest value wins: the earliest 0 (dominant) drags the shared line down; sending a 1 there is the losing move. Same non-destructive idea as CAN arbitration.

Problem 3.3 (L3)

A CAN bus must run at 1 Mbps. Signal speed on the wire is . Using , find the maximum bus length .

Recall Solution 3.3

WHY the factor 2: a dominant bit from the far node must reach the near node and let the far node hear the result within the same bit time — round-trip-worth of margin. This is why classic CAN at 1 Mbps is limited to roughly 40–100 m depending on margins.


L4 — Synthesis

Problem 4.1 (L4)

Design check: an I2C bus, , must sink enough current that any device can hold a valid LOW at with . It also has and must meet (standard mode 100 kHz). Give the allowed range of .

Recall Solution 4.1

Lower bound (current the chip must sink): Upper bound (rise time): Allowed range: . Check the common pick: is inside the window? ✓ — yes, sits comfortably between both fences (about above the lower bound and below the upper), so it is a safe standard choice. Why both bounds: too small starves the pull-down margin; too big starves the pull-up speed. The design lives inside the window. What the figure below shows: a number line of values. The magenta vertical line marks the lower fence (, "sink enough current"); the violet line marks the upper fence (, "rise fast enough"); the shaded orange band between them is the allowed window; the navy dot at shows our chosen value landing safely inside it.

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

Problem 4.2 (L4)

You must move a 1 KB (1024-byte) block from a flash chip. Compare wall-clock transfer time on: (a) SPI mode 0 at 8 MHz (8 clocks per byte, no framing overhead), vs (b) UART 8N1 at 115200 baud (10 bits per byte). Which is faster and by what factor (round to 1 decimal)?

Recall Solution 4.2

SPI: each byte = 8 clock cycles; clock period . Time . UART: each byte = 10 bits; . Time . Ratio faster on SPI. Why so lopsided: SPI has no start/stop/parity framing and a far higher clock — serial speed is set by clock rate, not wire count.


L5 — Mastery

Problem 5.1 (L5)

Prove the general UART clock-tolerance formula for an -data-bit, 1 stop frame where the last-sampled bit centre is at bit-times from the start edge. Show , then evaluate for and .

Recall Solution 5.1

Setup. After the start edge, the receiver waits to hit the centre of bit 0, then per subsequent bit. The centre of the last (stop-region) sample sits at Drift. With per-bit clock error fraction , accumulated timing error at is . Margin condition. To still land inside the half-bit window: Evaluate : Evaluate : Why fewer data bits tolerate more error: less drift accumulates over a shorter frame. Longer frames demand tighter clocks. This is exactly why UART frames are kept short.

Problem 5.2 (L5)

Design + justify. You must connect three identical sensor chips to one microcontroller. Each chip supports both SPI and I2C. The cable run is short, you want the fewest wires and all three must be individually reachable. Choose the interface, state the wire count, and name the one feature that makes >2 devices possible on that choice.

Recall Solution 5.2

Choice: I2C. Wire count signal wires (SDA + SCL), plus a shared ground, regardless of how many chips you add. Why not SPI: SPI needs one SS per slave → signal wires, and no addressing. I2C reaches each chip by its 7-bit address, so all three share the same two wires. Enabling feature: open-drain outputs + pull-up resistors implementing Wired-AND logic — every device can safely share one wire because it can only pull LOW or release, never fight another driver. Contrast with push-pull, which would short if two chips disagreed. Caveat (mastery detail): three identical chips may share the same fixed address → collision. Real designs need address-select pins or an I2C mux. (If the chips can't be re-addressed, fall back to SPI's per-chip SS.)

Problem 5.3 (L5)

CAN sanity: a network must span . With and the round-trip rule , what is the maximum bit rate (in kbps), and why can't you just crank the speed higher?

Recall Solution 5.3

Step 1 — minimum bit time for this length. Arbitration needs a full round trip to fit inside one bit: Step 2 — convert to bit rate. Bit rate is just the reciprocal of bit time: Why you can't go faster: if dropped below , a losing node would not yet have heard the far node's dominant bit come back before its own bit ended. It couldn't detect that it lost arbitration in time, two transmitters would keep driving, and the frame would corrupt. Distance and speed trade off: at a fixed length you cannot raise the bit rate past this ceiling without shortening the bus.


Recall Self-test summary (cloze)

UART idle level ::: HIGH Event that wakes a UART receiver ::: the START bit (falling edge) Wire count for N SPI slaves (no daisy-chain) ::: 3 + N (plus a shared ground) Hidden wire every single-ended bus needs ::: a common ground (0 V reference) I2C "released" line level and cause ::: HIGH, held by the pull-up resistor CAN dominant bit ::: the 0 state, actively driven, always wins CAN recessive bit ::: the 1 state, released/floating, only survives if all nodes release Which ID wins CAN arbitration ::: the numerically LOWEST ID (most dominant/0 bits) UART clock tolerance for 8N1 ::: about ±5.26% (0.5/9.5) Two bounds on the I2C pull-up ::: lower from sink current, upper from rise time