Blink an LED
One LED, one resistor, and the arithmetic that decides whether the GPIO survives. This is the second program everybody writes and the first one that can damage the board.
The resistor is not optional
An LED does not have a resistance in the way a wire does. It drops a roughly fixed voltage — about 2 V for a red one — and passes as much current as the rest of the circuit will allow. Connect it straight to a pin and "as much as the rest of the circuit will allow" is decided by the pin's own internal resistance, which is to say by how much heat the pin can take before it stops working.
The sum is one line:
R = (3.3 V − 2.0 V) / 0.01 A = 130 Ω
Round up to the nearest thing in your drawer. 220 Ω is the value everybody actually uses and it is bright enough in a lit room.
Why 40 mA is the number that matters
The datasheet's "recommended operating conditions" put the absolute maximum at 40 mA per GPIO, and there is a whole-chip limit underneath it as well. A single LED at 10 mA is nowhere near either. Eight of them on eight pins is 80 mA and still fine; eight addressable LEDs at full white is nearly half an amp and is not, and that is a supply problem rather than a pin problem.
Reading an output pin back
digitalRead on a pin configured as OUTPUT returns what you last wrote,
because it reads the output register. That is what makes the one-line toggle
work without a bool of your own — and it is also why it is not a way to check
whether anything is actually connected.
The code
GPIO 23 through the LED, through a resistor, to ground. The toggle version reads the pin back rather than tracking the state in a variable of its own.
#define LED_PIN 23
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void loop() {
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
delay(500);
}LED_BUILTIN is defined by the board package, not the chip. On boards with an addressable LED instead of a plain one it will not light, and that is the board rather than your code.
The same circuit. Pin objects remember their direction, so there is no separate pinMode step.
from machine import Pin
import time
led = Pin(23, Pin.OUT)
while True:
led.value(not led.value())
time.sleep(0.5)Typing these four lines into the REPL blinks the LED immediately, with no compile and no upload. It is the fastest way to check a wiring change.
When it does not work
Turn it around. An LED conducts one way only — long leg to the resistor and the GPIO, short leg to ground. Backwards it is simply an open circuit, and it neither lights nor complains.
A resistor was probably missing. Without one the current is limited only by the pin's own resistance, which is the pin heating up. Move to another GPIO and check that the LED still works elsewhere before blaming the sketch.
The resistor is too large, or the LED is a blue or white one. Blue and white LEDs drop about 3 V, so at 3.3 V there is almost nothing left to push current with. A red or green one is the right choice on a 3.3 V board.
You are on a strapping pin, or drawing far too much. GPIO 0, 2, 12 and 15 are read at boot, and a load on one of them can change what the chip decides to do. Move to a pin with no other job.
Two programs in and the toolchain has worked twice. The page you will actually come back to is the one about the day it stops.
When uploads fail →Edit this page — content/esp32/blink-an-led.mdx
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.