ESP32/Setup and uploading/05. Blink an LED
Your chip
Your language
Setup and uploading · 05 of 81

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.

/esp32/blink-an-led · arduino · S3

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.

GPIO 23 → LED → resistor → GND
100 Ω
Resistor100 Ω
Current
12 mA
Across the resistor
1.16 V
Left in the pin
0.14 V
12 mA, from (3.3 − 2.0) ÷ 100 Ω. The resistor is not protecting the LED from voltage, it is setting the current — the LED itself drops the same 2 V whatever you do, so everything left over has to land somewhere.

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.

On your S3
ChipXtensa LX7 · 2 × 240 MHz
Board settingESP32S3 Dev Module
Default I2CSDA 8 · SCL 9
Watch out forThe port vanishes after upload

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.

blink.ino
#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.

When it does not work

The LED never lights, in either direction

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.

It lit once and now nothing works on that pin

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.

It is very dim compared to the one on the board

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.

The board reboots when the LED turns on

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.

Where this goes next

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.

Browse ESP32 on the forum