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:
-
What methods does
OutputConfighave? Look at theimpl OutputConfigsection. -
Drive Strength: Find the
DriveStrengthenum. 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)
-
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.
-
Create an input: Check the pinout card — which pin is the button?
#![allow(unused)] fn main() { let button = Input::new(peripherals.GPIOXX, InputConfig::default()); } -
Explore
Pulloptions: Look up thePullenum. 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
- If the button connects the pin to GND when pressed → you need
- Try the wrong pull setting. What happens?
- Which pull setting does your button need? Think about the circuit:
-
Read the button state: Don't just use
is_low(). Look at what other methods are available:is_high()→boolis_low()→boolget_level()→Level
Try using
get_level()with amatchstatement:#![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
OutputConfigsetting -
Created a button
Inputwith an appropriatePullsetting -
Read the button state using
get_level()(not justis_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.