The hardware Hello World is blinking an LED. It is a simple ritual, but it touches every important part of a new board: power, toolchain, GPIO and flashing.
What you need
| Item | Detail |
|---|---|
| Board | ESP32 DevKitC, ESP32-WROOM-32 or similar |
| LED | Any color, ~2 V forward drop |
| Resistor | 220 Ω to 330 Ω |
| Software | PlatformIO (recommended) or Arduino IDE 2.x |
Tip: many DevKits already ship an LED on
GPIO2. You can use it to test without wiring anything, though it is usually inverted.
The pinout in two minutes
The ESP32 has GPIOs numbered 0 to 39, but not all are usable:
GPIO6–GPIO11are wired to the SPI flash. Do not touch them.GPIO34–GPIO39are input only (no internal pull-up).GPIO1(TX0) andGPIO3(RX0) are used by the serial port.GPIO0selects the boot mode; avoid using it as an output.
For an LED, any output GPIO works. We will use GPIO2.
Arduino code
The Arduino core makes startup trivial:
#include <Arduino.h>
constexpr int LED_PIN = 2;
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void loop() {
digitalWrite(LED_PIN, HIGH);
delay(1000);
digitalWrite(LED_PIN, LOW);
delay(1000);
}delay() blocks (and sometimes that matters)
delay() halts the whole CPU. For a blink it is fine, but as soon as you add
Wi-Fi or several sensors you will want millis():
unsigned long last = 0;
constexpr unsigned long INTERVAL = 1000;
void loop() {
if (millis() - last >= INTERVAL) {
last = millis();
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
}
}The same in ESP-IDF (Rust)
If you prefer Rust, the esp-idf-hal crate offers a typed API. A blink
with esp-idf-svc looks like this:
use esp_idf_svc::hal::delay::FreeRtos;
use esp_idf_svc::hal::gpio::PinDriver;
use esp_idf_svc::hal::peripherals::Peripherals;
fn main() -> anyhow::Result<()> {
esp_idf_svc::sys::link_patches();
let peripherals = Peripherals::take()?;
let mut led = PinDriver::output(peripherals.pins.gpio2)?;
loop {
led.set_high()?;
FreeRtos::delay_ms(1000);
led.set_low()?;
FreeRtos::delay_ms(1000);
}
}
The big difference: in Rust the compiler forces you to declare the pin as an output before writing to it. Many hardware mistakes vanish at compile time.
PlatformIO setup
A minimal platformio.ini for the Arduino core:
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
And for Rust with esp-idf:
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = espidf
monitor_speed = 115200Troubleshooting
- It will not flash / board not found. Install the
cp210xorch34xdrivers matching your board’s USB chip. - It flashes but does not blink. Check the LED polarity and the resistor.
- It reboots in a loop. Usually a power issue: use a USB port that can deliver at least 500 mA.
Next step
With GPIO under control you have the essentials. The natural next jump is connectivity (Wi-Fi, MQTT), which we will cover on the blog. For now you can move on to serial monitor and debugging or go back to the series hub.