Pull-up

A resistor with one end on a signal and the other on a rail. When something drives the signal, it wins, because a driver is far stronger than the resistor. When nothing drives it, the resistor gently pulls the line up to the rail.

flowchart TB
    V(["3V3 rail"]) --> R["10k"]
    R --> S["the signal"]
    D["a driver,<br/>when it is driving"] --> S
    S --> IN["the input<br/>that reads it"]
    S -.->|"nobody driving,<br/>and no resistor"| F["floating: reads as neither<br/>high nor low, and can oscillate"]

A floating input is the failure this prevents. A CMOS input left undriven does not read a sensible default; it drifts, picks up noise, and can switch fast enough to draw real current. Anything that is undriven some of the time needs a defined level, which covers a reset line before the driver comes up, an open-drain bus, and an input to a chip that has not been fitted.

Two rules read this shape. floating-input looks for inputs with no defined level, and i2c-pull-up checks the pair an I2C bus requires, because I2C drivers can only pull DOWN and the bus cannot return high without them.

The value is a compromise rather than a constant. Lower means a faster return to high and more current wasted while the line is held low. i2c-pull-up names no resistance for that reason, and says to size it from the bus capacitance and clock rate instead.

The mirror image is a pull-down, to ground rather than to a rail.

Where the course teaches it: chapter 1 reads one off a query, and chapter 4 is the whole chapter about them.