UNIT 07 · LESSON 3 OF 6

Reading Inputs and Handling Floating Pins

What else does a reliable input need?

INTERACTIVEWhat does the pin read?
The value an input pin reads for a chosen pull and connectionthe pin reads1pull: pull-up; connected to a button to GND (released)defined level 1no current through the pull
The value an input pin reads for a chosen pull and connectionthe pin reads1pull: pull-up; connected to a button to GND(released)defined level 1no current through the pull

Try this

Pull
Reads 1.

An input reads a defined level only if something drives it or a pull resistor holds it. A button connects the pin to one rail only while pressed; the pull must hold the opposite rail the rest of the time. While the button is pressed, the pull resistor carries VDD/R. Internal pulls are weak (tens of kΩ; 50 kΩ is used here as an illustrative value). On the RP2040, enabling both pulls gives a bus keeper that holds the last level.

What you will be able to do
  • Choose the pull configuration for a button, a driven signal and an unused pin, and predict what each reads.
  • Calculate the current a pull resistor carries while a button is held.
  • Explain why a floating input is unreliable and can waste power, and configure unused pins.
  • Read several related pins in one register access and explain why separate reads can produce impossible states.
  • Account for the input synchroniser delay when timing an input.
Before you start
  • Pad controls: input enable, pulls, Schmitt trigger (lesson 1).
  • Floating inputs and pull resistors (unit 1, lesson 3).
Steps in this lesson
  1. Every input needs a driver or a pull
  2. Floating and unused pins
  3. Reading related pins together
  4. Worked example: a battery-powered button
  5. Common misconceptions

The puzzle

A button reads correctly on the bench, and on a customer’s desk it sometimes registers presses nobody made. A rotary encoder occasionally counts backwards for one step. Both inputs are wired correctly and both read the pin exactly as the manual says. What else does a reliable input need?

STEP 1

Every input needs a driver or a pull

An input pin reads a defined level only while something drives it: an output, a button connected to a rail, or a pull resistor. A button connects the pin to one rail only while pressed; the pull must hold the opposite rail the rest of the time (unit 1, lesson 3). The two usual wirings:

wiringpullreleasedpressed
button to GNDpull-up10 (active low)
button to VDDpull-down01 (active high)

↑ This step uses the figure at the top of the page.

While the button is held, the pull resistor carries VDD/R continuously; with a 50 kΩ internal pull at 3.3 V that is 66 µA, negligible for a mains device and significant for a battery device that holds a button for hours. The RP2040 also offers a bus keeper (both pulls on): a weak pull toward whatever level the pin last had, useful on a shared line, but no help for a button.

STEP 2

Floating and unused pins

An input connected to nothing floats: its level is set by leakage, noise and whatever charge it last held, so it can read anything and change on its own. Worse, a CMOS input buffer at an intermediate voltage has both its transistors partly on and draws current. Unused pins should therefore be put in a defined state:

  • enable a pull (the RP2040 pads reset with the pull-down on), or
  • configure them as outputs driving a fixed level, if nothing on the board connects to them, or
  • disconnect the input buffer (RP2040: clear the pad’s input enable; STM32F4: analog mode).

Pins used as analog inputs need the digital buffer off too: the RP2040’s boot ROM and the SDK both clear the input enable of its ADC pins, GPIO26–29. Calling gpio_init() on those pins turns it back on; the SDK’s ADC pin set-up function turns it off again.

STEP 4

Worked example: a battery-powered button

A handheld device uses an internal pull-up with a button to ground. Assume 50 kΩ (internal pulls are specified as a range; take the value from your datasheet).

Ipressed=3.3 V50 kΩ=66 μAI_{pressed} = \frac{3.3\ \text{V}}{50\ \text{k}\Omega} = 66\ \mu\text{A}

If the user can leave the button held (in a pocket, under a case), that is 66 µA for as long as it lasts, which may exceed the whole chip’s sleep current. Options: an external pull-up of 1 MΩ with the internal pulls disabled (gpio_disable_pulls(); against the RP2040’s default pull-down it would read 0 for ever): 3.3 µA, but 1 µA of leakage already drops 1 V across it, leaving little margin above the input threshold. Or firmware that disables the pull while the button is known to be held and polls it rarely.

MYTHS AND FACTS

Common misconceptions

An input with nothing connected reads 0

It floats and can read anything.

The internal pull is always enough

It is weak (tens of kΩ): fine for a button next to the chip, marginal on long wires in a noisy environment, where a stronger external pull and filtering help.

Reading pins one by one is equivalent to reading the port

Separate reads sample at different instants.

Unused pins can be left as they come out of reset

Only if the reset state is defined; on many chips pins reset as floating inputs.

Check yourself

Answer in your head, then open the card.

A button connects a pin to 3.3 V. Which pull do you need, and what does the pin read when released and pressed?

A pull-down: released reads 0, pressed reads 1.

An encoder's A and B are read with two gpio_get() calls. Occasionally the count moves the wrong way for one step. Why, and what fixes it?

The two reads sample A and B at different instants; if both lines change between them (an interrupt between the two calls makes that likely), the program sees a state that never existed. Read GPIO_IN once with gpio_get_all() and take both bits from that value.

Why do the RP2040's boot ROM and SDK clear the input enable of GPIO26–29?

They are the ADC inputs. With the digital input buffer enabled, an analog voltage between the thresholds can make the buffer draw current and couple noise; turning it off leaves the pin to the ADC.

A pull-up of 10 kΩ holds a line that a button shorts to ground. The button is held for 10 minutes. What charge does that take from a 3.3 V battery?

330 µA × 600 s = 0.198 C, about 55 µAh.

Sources (4)
  1. Raspberry Pi Ltd, pico-sdk 1.5.1, hardware_gpio/gpio.h and hardware_regs sio.h, pads_bank0.h — gpio_get() reads one bit of sio_hw->gpio_in and gpio_get_all() the whole register (SIO GPIO_IN, “Input value for GPIO0...29”); gpio_set_pulls: “setting both pulls enables a bus keep function, i.e. a weak pull to whatever is current high/low state”; gpio_set_input_enabled, gpio_set_input_hysteresis_enabled; pads reset with IE = 1, PDE = 1, SCHMITT = 1
  2. Raspberry Pi Ltd, pico-sdk 1.5.1, hardware_regs/pio.h (PIO_INPUT_SYNC_BYPASS) — “There is a 2-flipflop synchronizer on each GPIO input, which protects PIO logic from metastabilities. This increases input delay”
  3. Raspberry Pi Ltd, pico-bootrom-rp2040, bootrom/bootrom_rt0.S, and pico-sdk 1.5.1 pico_runtime/runtime.c — both the boot ROM (disable_adc_ie) and runtime_init() clear the input enable of GPIO26–29, the ADC-capable pins, “after resetting BANK0”
  4. STMicroelectronics, stm32f4xx-hal-driver, Inc/stm32f4xx_hal_gpio.h and Src/stm32f4xx_hal_gpio.c — GPIO_MODE_INPUT “Input Floating Mode” (no pull unless PUPDR is set); GPIO_MODE_ANALOG; HAL_GPIO_ReadPin reads IDR