Line Drivers: Push-Pull and Open-Drain
Say what a push-pull and an open-drain output each do to a shared wire, read a fight as x and as a voltage, and measure what the pull-up costs in rise time.
- Lesson
- P5.4
- Time
- 30 min
- Runs on
- Your browser
- Check
- 4 questions
A new I/O expander joined an interrupt line shared by three other chips, with its output set to push-pull. Whenever another chip asserted the interrupt, the line sat halfway between the rails and the processor never saw it. The expander was driving a 1 into a wire that the others expected to pull low freely.
- Time 500 nsv(line) = 3.3 V
A alone: the line is at 3.3 V, a clean 1.
- Time 1.5 µsv(line) = 1.65 V
B switches on. The line settles at 1.65 V, between the two thresholds, and 33 mA flows from the supply through both outputs to ground.
- Time 2.5 µsv(line) = 3.3 V
B lets go, and A pulls the line back to a 1.
Read the plot as a table
| Time | v(line) |
|---|---|
| 0 s | 3.3 V |
| 500 ns | 3.3 V |
| 1 µs | 3.3 V |
| 1.5 µs | 1.65 V |
| 2 µs | 1.65 V |
| 2.5 µs | 3.3 V |
| 3 µs | 3.3 V |
Simulated on the Analog engine (ngspice 42). The 0.3 and 0.7 VDD lines are the input thresholds UM10204 §3.1.2 uses: between them an input may read either value. A logic simulator draws this as x.
Two Ways to Drive a Wire
- Push-pull
One switch to the supply, one to ground, never both on. Both edges are driven hard, so it is fast, but only one output may own the line.
- Open drain
Each device has only the switch to ground. It pulls the line low or lets go, and a resistor brings it high. Any number of devices can share the line.
Read the diagram as text
- High-side switch: on for a 1
- Line: one owner
- Low-side switch: on for a 0
- Pull-up resistor: to the supply
- Line: shared
- Device A: pulls low or lets go
- Device B: pulls low or lets go
- High-side switch → Line: drives 1
- Low-side switch → Line: drives 0
- Pull-up resistor → Line: raises it slowly
- Device A → Line: pulls 0
- Device B → Line: pulls 0
A push-pull output that can also let go, with an enable, is a tri-state output: SPI's MISO is one.
Push-pull buys speed and pays in sharing: two push-pull outputs on one wire must never both be on. Open drain buys sharing and pays in speed: the rise is only as fast as the resistor can charge the wire.
Who Pulls Low: The Wired-AND
A low lane of 1 pulls the net down. The pull-up raises it only when every device releases.
- Cycle 0
Nobody pulls. The pull-up holds the line at 1.
- Cycle 1
A pulls, and the line is 0.
- Cycle 2
Both pull. They agree, so nothing fights.
- Cycle 3
A lets go but B still pulls: the line stays 0, and A can read that back.
- Cycle 4
B lets go too. Only now does the line rise.
Measured: the example's first five lines. The line is 1 only when every device has let go, a wired-AND.
| a_low | b_low | With the pull-up | Without it |
|---|---|---|---|
| 0 | 0 | 1 | z |
| 1 | 0 | 0 | 0 |
| 1 | 1 | 0 | 0 |
| 0 | 1 | 0 | 0 |
Measured: the example on Icarus Verilog. With nobody pulling and no pull-up, the line is z: nothing sets its level.
The line reads 1 only when every device lets go, which is an AND of the devices' released states. A device can always pull, never fight, and read the line back to see whether someone else pulls too. I2C builds clock stretching and arbitration on this (P8.5, P8.6).
Two Push-Pull Outputs on One Wire
The same program puts two push-pull outputs on one wire. Driving the same value is harmless: 1. Driving opposite values gives x, the simulator's word for the fight in the opening plot.
| Case | Four-state (Icarus Verilog) | Two-state (Verilator) |
|---|---|---|
| Open drain, nobody pulls, no pull-up | z | 0 |
| Push-pull 1 against push-pull 0 | x | 1 |
Measured: the same program on both simulators. A two-state simulator has no z or x, so it shows a legal-looking value for both faults.
A bench for a shared line should run on a four-state simulator, or check for contention itself. Otherwise a missing pull-up and two drivers fighting both pass.
The Price of Open Drain: The Rise
- push-pull, 50 Ω, 100 pF
- 1 kΩ pull-up, 100 pF
- 4.7 kΩ pull-up, 100 pF
- 4.7 kΩ pull-up, 400 pF
Read the plot as a table
| Time | push-pull, 50 Ω, 100 pF | 1 kΩ pull-up, 100 pF | 4.7 kΩ pull-up, 100 pF | 4.7 kΩ pull-up, 400 pF |
|---|---|---|---|---|
| 500 ns | 3.3 V | 3.278 V | 2.161 V | 770.6 mV |
| 1 µs | 3.3 V | 3.3 V | 2.907 V | 1.361 V |
| 1.5 µs | 3.3 V | 3.3 V | 3.164 V | 1.814 V |
| 2 µs | 3.3 V | 3.3 V | 3.253 V | 2.161 V |
| 2.5 µs | 3.3 V | 3.3 V | 3.284 V | 2.427 V |
| 3 µs | 3.3 V | 3.3 V | 3.294 V | 2.631 V |
Simulated on the Analog engine (ngspice 42) from the library's pull-up netlist (UM10204 §7.1). A rise time is read between the 0.3 VDD and 0.7 VDD crossings.
| Output | Load | R × C | Rise, 0.3 to 0.7 VDD | Meets the tr limit of |
|---|---|---|---|---|
| push-pull, 50 Ω | 100 pF | 5.0 ns | 4.2 ns | Sm, Fm, Fm+ |
| 1 kΩ pull-up | 100 pF | 100 ns | 85 ns | Sm, Fm, Fm+ |
| 4.7 kΩ pull-up | 100 pF | 470 ns | 398 ns | Sm |
| 4.7 kΩ pull-up | 400 pF | 1880 ns | 1593 ns | none |
Measured rise times; the limits are UM10204 Table 11, tr maximum: Sm 1000 ns, Fm 300 ns, Fm+ 120 ns. Table 11 also caps the load at 400 pF for Sm and Fm.
Every released rise is the same curve scaled by R × C. The 1 kΩ, 100 pF run measures 0.847 × RC, the constant UM10204 §7.1 derives from the 0.3 and 0.7 VDD thresholds. A smaller resistor is faster but makes every pull-down sink more current. Lesson P8.7 sizes it.
Where You Will Meet It
| Link | Output style | Lessons |
|---|---|---|
| UART TX | Push-pull, one owner per wire | P6.1 |
| SPI | Push-pull; MISO lets go when its select is high | P7.4 |
| QSPI data pins | Push-pull, turned around between the two sides | P7.7 |
| I2C SDA and SCL | Open drain with pull-ups, the wired-AND (UM10204 §3.1.1) | P8.1, P8.7, P8.13 |
| I2C Ultra Fast-mode | Push-pull, one direction only (§3.2.1) | P8.12 |
| I3C | Open drain while devices may compete, push-pull for data | P9.3 |
UM10204 §3.1.1 also lets a single controller drive SCL push-pull when no device on the bus stretches the clock.
Try It
The sda net is declared tri1: a pull-up the simulator models. The bare net is a plain wire with the same two open-drain outputs and nothing pulling it up. fight has two push-pull outputs.
Change tri1 sda; to wire sda;: the released rows of sda read z too. Then try tri0 sda;, a pull-down, and see which rows change.
a_low 0, b_low 0: sda 1, without the pull-up z a_low 1, b_low 0: sda 0, without the pull-up 0 a_low 1, b_low 1: sda 0, without the pull-up 0 a_low 0, b_low 1: sda 0, without the pull-up 0 a_low 0, b_low 0: sda 1, without the pull-up z push-pull 1 and 1: 1 push-pull 1 against 0: xRead included file: drivers.sv
`timescale 1ns/1ns
module od(input wire low, inout wire line); assign line = low ? 1'b0 : 1'bz; endmodule
module pp(input wire en, input wire v, inout wire line); assign line = en ? v : 1'bz; endmodule
Check Yourself
Remember
- A push-pull output drives both levels and is fast, but only one may own a wire.
- An open-drain output only pulls low or lets go; with a pull-up, the line is the AND of every device.
- Two push-pull outputs that disagree sit mid-rail and pass a large current; a four-state simulator shows x, a two-state one hides it.
- An open-drain rise is an RC charge, 0.85 RC from 0.3 to 0.7 VDD, so the pull-up and the bus capacitance set the speed.