Exercise B: Explore GPIO Configurations

~20 min

The blinky example used OutputConfig::default(). But what does "default" actually mean? And what other configurations are available?

This is where you start exploring the documentation on your own.

Part 1: Output Configuration

Your LED is blinking with the default config. Let's see what else exists.

Open [`OutputConfig`](https://docs.espressif.com/projects/rust/esp-hal/latest/esp32c3/esp_hal/gpio/struct.OutputConfig.html) on docs.rs. Answer these questions:
  1. What methods does OutputConfig have? Look at the impl OutputConfig section.

  2. Drive Strength: Find the DriveStrength enum. How many variants does it have? What do they mean?

    • Try changing the drive strength in your blinky code:
    #![allow(unused)]
    fn main() {
    let config = OutputConfig::default()
        .with_drive_strength(DriveStrength::_20mA);
    }
    • Can you see any difference? (On an LED, higher drive strength = slightly brighter, but it depends on the circuit)
  3. Open Drain: What does .with_open_drain(true) do?

    • Try it. Does your LED still work? Why or why not?
    • (Hint: open-drain needs an external pull-up resistor to go high)

Part 2: Adding a Button Input

Now add a button to read. Keep your LED output — we'll control it with the button.

Open [`Input`](https://docs.espressif.com/projects/rust/esp-hal/latest/esp32c3/esp_hal/gpio/struct.Input.html) and [`InputConfig`](https://docs.espressif.com/projects/rust/esp-hal/latest/esp32c3/esp_hal/gpio/struct.InputConfig.html) on docs.rs.
  1. Create an input: Check the pinout card — which pin is the button?

    #![allow(unused)]
    fn main() {
    let button = Input::new(peripherals.GPIOXX, InputConfig::default());
    }
  2. Explore Pull options: Look up the Pull enum. What variants exist?

    • Which pull setting does your button need? Think about the circuit:
      • If the button connects the pin to GND when pressed → you need Pull::Up
      • If the button connects the pin to VCC when pressed → you need Pull::Down
    • Try the wrong pull setting. What happens?
  3. Read the button state: Don't just use is_low(). Look at what other methods are available:

    • is_high()bool
    • is_low()bool
    • get_level()Level

    Try using get_level() with a match statement:

    #![allow(unused)]
    fn main() {
    match button.get_level() {
        Level::Low => { /* button pressed? */ },
        Level::High => { /* button released? */ },
    }
    }
The blinky example showed you ONE configuration: `OutputConfig::default()`. By reading the docs, you just discovered drive strength, open-drain mode, pull resistors, and multiple ways to read a pin state. This is what ecosystem navigation looks like.

Checkpoint

Before moving on, you should have:

  • Tried at least one non-default OutputConfig setting
  • Created a button Input with an appropriate Pull setting
  • Read the button state using get_level() (not just is_high())
```rust
loop {
    match button.get_level() {
        Level::Low => led.set_high(),   // Button pressed (with pull-up)
        Level::High => led.set_low(),   // Button released
    }
}

```admonish hint title="Hint: Full solution" collapsible=true
See `solutions/button-configs/src/main.rs` for a complete example with multiple configurations demonstrated.