Pull-up and Pull-down Resistors

Pull-up and pull-down resistors are simple solutions that ensure a pin always has a known voltage level, even when nothing else is driving it. Let's understand how they work.

What Are Pull-up and Pull-down Resistors?

Pull-up Resistor

Connects the pin to the positive voltage (3.3V on the Pico) through a resistor. This "pulls" the pin HIGH by default. When you press a button that connects the pin to ground, the pin reads LOW.

Pull-down Resistor

Connects the pin to ground (0V) through a resistor. This "pulls" the pin LOW by default. When you press a button that connects the pin to 3.3V, the pin reads HIGH.

How Pull-up Resistors Work

Let's look at a typical button circuit with a pull-up resistor:

Pull-up resistor circuit diagram

Pull-up resistor configuration

How It Works

  • Button not pressed: Current flows through the resistor to the GPIO pin, holding it at 3.3V (HIGH)
  • Button pressed: You create a direct path to ground. Electricity follows the path of least resistance, current flows through the button to ground, and the pin reads LOW

How Pull-down Resistors Work

A pull-down resistor works in the opposite direction:

Pull-down resistor circuit diagram

Pull-down resistor configuration

How It Works

  • Button not pressed: The GPIO pin is connected to ground through the resistor, reading LOW
  • Button pressed: The button connects the pin directly to 3.3V, and the pin reads HIGH

Internal Pull Resistors

The Raspberry Pi Pico has built-in pull-up and pull-down resistors on every GPIO pin. You don't need to add external resistors for basic button inputs. You can enable them in software.

Important

Hardware Bug in Early RP2350 Chips: There's a hardware bug (E9) in the initial RP2350 chip that affects internal pull-down resistors. The bug causes the GPIO pin to read HIGH even when the button isn't pressed.

The bug was fixed in the newer RP2350 A4 chip revision.

Workaround: If you have an older chip, avoid using Pull::Down. Use Pull::Up instead, or use an external pull-down resistor with Pull::None.

Using Internal Pull Resistors in Code

Here's how to configure internal pull resistors in Rust:

Pull-up Configuration

rust
let button = Input::new(p.PIN_16, Pull::Up);

// With pull-up enabled:
// - Button not pressed = HIGH
// - Button pressed (connected to GND) = LOW

if button.is_low() {
    // Button is pressed
}

Pull-down Configuration

rust
let button = Input::new(p.PIN_16, Pull::Down);

// With pull-down enabled:
// - Button not pressed = LOW
// - Button pressed (connected to 3.3V) = HIGH

if button.is_high() {
    // Button is pressed
}

No Pull (Floating)

rust
let button = Input::new(p.PIN_16, Pull::None);

// Use this only when:
// - You have an external pull resistor
// - Connecting to devices that actively drive the pin HIGH or LOW
Tip

For the Pico 2 W, it's recommended to use Pull::Up for buttons connected to ground. This avoids the pull-down bug in early chips and is the most common button configuration.