Lab: blink the ESP32-S3-DevKitC-1 RGB LED
This lab blinks the onboard addressable RGB LED of the ESP32-S3-DevKitC-1 through the Adafruit NeoPixel driver, with every version pinned so the compile is reproducible. Read the board identification guide first if you do not know your board revision: the LED GPIO depends on it.
What this experiment exercises
- The addressable RGB LED wiring facts (GPIO38 on v1.1 / GPIO48 on v1.0) from the board record — a
digitalWrite()cannot produce colors on this LED, see why the LED is on GPIO38 or GPIO48. - The pinned toolchain (Arduino core + driver library versions below) compiling the sketch for the ESP32-S3.
- The first-flash path: flash via the USB-to-UART port following the first connection guide.
Pinned versions
| Component | Version | Why pinned |
|---|---|---|
| Board | ESP32-S3-DevKitC-1 | The lab reads its LED GPIO facts from the board record |
| Board revision | v1.1 (LED on GPIO38); BOARD_REV=10 selects the v1.0 wiring (GPIO48) | The revision moved the LED; both constants are in the sketch |
| Compile target | FQBN esp32:esp32:esp32s3 (core default menu values; the blink sketch uses no PSRAM or non-default flash settings, so the binary is not tied to one ordering SKU) | Stated exactly, not claimed for every SKU |
| arduino-cli | 1.5.1 | Toolchain entry point |
| arduino-esp32 core | 3.3.12 | SDK version the sketch compiles against |
| Adafruit_NeoPixel | 1.15.5 | LED driver, version-locked |
The sketch
Source in the repository: site/labs/esp32-s3-blink-led/esp32-s3-blink-led.ino.
#include <Adafruit_NeoPixel.h>
// The RGB LED GPIO moved between board revisions; both constants come from
// the official Espressif user guides pinned on the board page.
constexpr int LED_PIN_V1_0 = 48; // v1.0: GPIO48, J3 contact 16
constexpr int LED_PIN_V1_1 = 38; // v1.1: GPIO38, J3 contact 10
// Select your board revision: 10 for v1.0, 11 for v1.1.
#ifndef BOARD_REV
#define BOARD_REV 11
#endif
#if BOARD_REV == 10
constexpr int LED_PIN = LED_PIN_V1_0;
#elif BOARD_REV == 11
constexpr int LED_PIN = LED_PIN_V1_1;
#else
#error "BOARD_REV must be 10 (v1.0, GPIO48) or 11 (v1.1, GPIO38)"
#endif
constexpr int LED_COUNT = 1;
constexpr unsigned long BLINK_INTERVAL_MS = 800;
constexpr uint32_t COLOR_ORDER = NEO_GRB + NEO_KHZ800;
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, COLOR_ORDER);
const uint32_t COLORS[] = {
Adafruit_NeoPixel::Color(20, 0, 0), // dim red
Adafruit_NeoPixel::Color(0, 20, 0), // dim green
Adafruit_NeoPixel::Color(0, 0, 20), // dim blue
};
constexpr int COLOR_COUNT = sizeof(COLORS) / sizeof(COLORS[0]);
int colorIndex = 0;
bool ledOn = false;
unsigned long lastToggle = 0;
void setup() {
strip.begin();
strip.setBrightness(32);
strip.show(); // start dark: init state must be explicit, not assumed
}
void loop() {
unsigned long now = millis();
if (now - lastToggle < BLINK_INTERVAL_MS) {
return;
}
lastToggle = now;
ledOn = !ledOn;
if (ledOn) {
strip.setPixelColor(0, COLORS[colorIndex % COLOR_COUNT]);
colorIndex++;
} else {
strip.setPixelColor(0, 0); // explicit off
}
strip.show();
}The full sketch in the repository additionally documents the identification guide link, the toolchain table and the WS2812/digitalWrite caveat in its header comments.
Compile and flash
arduino-cli compile --fqbn esp32:esp32:esp32s3 site/labs/esp32-s3-blink-led
arduino-cli upload --fqbn esp32:esp32:esp32s3 -p /dev/<your-usb-serial-port> site/labs/esp32-s3-blink-ledCompile receipt
Compiled on 2026-11-09 00:49 CST with the pinned toolchain below; both board revisions compiled in separate clean build paths, and a negative build proves the BOARD_REV macro actually reaches the sketch.
Toolchain actually used (versions read back from the build, not assumed):
| Component | Version | Evidence |
|---|---|---|
| arduino-cli | 1.5.1 | arduino-cli entry point |
| arduino-esp32 core | 3.3.12 | Used platform line: esp32:esp32 3.3.12 |
| xtensa-esp-elf-gcc | 14.2.0 (crosstool-NG esp-14.2.0_20260121) | xtensa-esp32s3-elf-gcc --version |
| Adafruit NeoPixel | 1.15.5 | Used library line |
| builtin ctags | 5.8-arduino11 | platform build dependency |
Commands (one per board revision, separate build paths):
arduino-cli compile --fqbn esp32:esp32:esp32s3 \
--build-property "compiler.cpp.extra_flags=-DBOARD_REV=11" \
--build-path build/r11 site/labs/esp32-s3-blink-led
arduino-cli compile --fqbn esp32:esp32:esp32s3 \
--build-property "compiler.cpp.extra_flags=-DBOARD_REV=10" \
--build-path build/r10 site/labs/esp32-s3-blink-ledResults:
| Build | Exit | Sketch size | RAM | esp32-s3-blink-led.ino.bin SHA-256 (first 16) |
|---|---|---|---|---|
BOARD_REV=11 (v1.1, LED on GPIO38) | 0 | 289858 / 1310720 bytes (22%) | 22208 / 327680 (6%) | 3eb838864030eb06… |
BOARD_REV=10 (v1.0, LED on GPIO48) | 0 | 289858 / 1310720 bytes (22%) | 22208 / 327680 (6%) | 89d1e4bac804483f… |
BOARD_REV=99 (negative control) | 1 | — | — | no output |
Macro evidence (the revision constant genuinely drives the binary, not just the source):
- The two revisions produce different binaries (
3eb83886…vs89d1e4ba…) and different.elffiles — the LED pin constant (GPIO38 vs GPIO48) differs in the compiled output. - The negative control
-DBOARD_REV=99fails the build at the sketch’s own guard:esp32-s3-blink-led.ino:37: error: #error "BOARD_REV must be 10 (v1.0, GPIO48) or 11 (v1.1, GPIO38)"— proving the macro reaches the translation unit.
Status: compiled (pinned toolchain), not flashed to hardware
Both board revisions compile cleanly with the pinned versions above — that is the verified claim. No hardware flashing or on-board observation happened: the blink result on a physical board has not been seen in this environment, and the upload command above remains the reader’s step. The LED GPIO facts, the addressable-LED driver choice and the revision caveats all come from the fixed official sources on the board page.