Getting started with the ESP32
“ESP32” is the family of cheap and fast microcontrollers with WiFi and Bluetooth onboard. This lesson is about getting started fast with any ESP32 using LabWired!
Contents
- Which chip is on your board
- Which board to buy
- Start now, with no board
- Install the toolchain
- The first program
- Five failures that stop the first upload
- The pins that you must not use
- What to build after the blink
Which chip is on your board
Read the metal shield on the module. It gives the chip name. The name sets everything else.
| Chip | Core | Radio | GPIOs | USB |
|---|---|---|---|---|
| ESP32 | Two Xtensa LX6, up to 240 MHz | Wi-Fi 4, Bluetooth Classic and LE | 34 | External converter chip |
| ESP32-S3 | Two Xtensa LX7, up to 240 MHz | Wi-Fi 4, Bluetooth LE | 45 | In the chip |
| ESP32-C3 | One RISC-V, up to 160 MHz | Wi-Fi 4, Bluetooth LE | 22 | In the chip |
| ESP32-C6 | One RISC-V | Wi-Fi 6, Bluetooth LE, 802.15.4 | — | In the chip |
| ESP32-H2 | One RISC-V | Bluetooth LE, 802.15.4. No Wi-Fi | — | In the chip |
Four differences change what you write and how you wire:
- The instruction set changes, but your code does not. The classic ESP32 and the S3 use an Xtensa core. The C3, C6, and H2 use RISC-V. With LabWired you just select a board; we support running code and Arduino sketches on all of them!
- The USB port changes what you debug. The classic ESP32 has no USB peripheral. Its board uses a separate converter chip (CP2102 or CH340) between the USB connector and the chip UART. The C3, S3, C6, and H2 have a USB Serial/JTAG controller in the chip. The port that your computer sees is then made by the chip itself, and it disappears while the chip resets. Failure 5 is a result of this. Labwired can directly flash all EPS32 boards via Tools->Deploy menu, when you are suing Chrome or other compatible browser.
- Radio interfaces. The C6 and H2 have a second radio for Thread, Zigbee, and Matter. The H2 has no Wi-Fi at all. If a project needs a web server, do not buy an H2.
Which board to buy
A development board is a module, a voltage regulator, a USB connector, and a row of pins. Boards cost between 5 and 15 US dollars. Three boards cover almost all first projects:
- ESP32-C3-DevKitM-1, or the smaller ESP32-C3 SuperMini clone, the cheapest way to start. One core and USB directly to the chip. Buy this to learn.
- ESP32-DevKitC V4, or a DevKit V1 (DOIT) clone, the classic board. The largest quantity of tutorials, sample code, and forum answers refers to it. Buy this if you intend to follow older material without translation. The clones use the same chip, and their headers are frequently 30 pins instead of 38, so count the pins before you use a diagram.
- ESP32-S3-DevKitC-1 — two cores, more pins, more random-access memory (RAM), and an option for external pseudo-static RAM (PSRAM). Buy this for a display, a camera, or audio. Any modern project. LabWired support all of those boards.
Buy two boards. A second board tells you in one minute if a failure is in the hardware or in your code. The second board costs less than the hour that you spend without it.
You can see full pinout in chip properties in Labwired.
Start now
The lab below is an ESP32-C3 SuperMini with an LED and a 330 Ω resistor on GPIO4. It operates in your browser. There is no toolchain to install, no driver, and no cable. You can build your virtual circuit. write and validate you r code and than flash the board.
The firmware is the same Arduino sketch that The first program gives below. The chip is not a video of a chip. The LED on the canvas changes state each 500 ms because the program in the model wrote to the GPIO4 output register.
This is the header of that board. and from the ESP32-C3 datasheet:
Two properties of this board catch people:
- GPIO8 does two jobs. It drives the on-board LED, at the low level, and the chip reads it at reset to select the boot mode. A circuit that holds it low can stop the board from starting.
- The nine missing pins are not a saving. GPIO12 to GPIO17 are the flash bus and GPIO18 and GPIO19 are the USB pins, so the module does not bring them out. A tutorial written for a larger C3 board can name a pin that your header does not have.
Two conditions make this more than a demonstration:
- It repeats. The same firmware and the same diagram give the same output each time. On real hardware, a timing failure can occur once each 50 boots. Here it occurs each time or not at all.
- You can change it. Change the pin number, the delay, or the text. Run it again. Nothing is damaged, and nothing needs a new upload.
Use the lab to learn the program structure and the pin rules. Use the real board to learn the parts that a simulation cannot teach you: a loose wire, a weak power supply, and a cable that does not carry data.
Install the toolchain
Three environments are used. Select one and do not mix them at the start.
Arduino IDE is the correct first choice. It has the largest quantity of libraries, and almost all beginner material uses it.
- Install the Arduino IDE, version 2.x.
- Open File > Preferences. In Additional boards manager URLs, add:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json - Open Tools > Board > Boards Manager. Search for
esp32. Install esp32 by Espressif Systems, version 3.x. The download is approximately 1 GB and it takes some minutes. - Select your board in Tools > Board. Select the port in Tools > Port.
ESP-IDF is the official Espressif framework. It gives access to each peripheral, the real-time operating system (FreeRTOS), and the partition table. Move to it when Arduino hides something that you must control. Do not start with it.
PlatformIO, as an extension in VS Code, builds Arduino and ESP-IDF projects. It records the exact framework version in a platformio.ini file in the project, so a project builds again after two years. Use it when a project becomes larger than one file.
The first program
#include <Arduino.h>
const int LED_PIN = 4;
uint32_t count = 0;
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
Serial.println("ESP32-C3 up. First blink.");
}
void loop() {
digitalWrite(LED_PIN, HIGH);
Serial.print("blink ");
Serial.println(++count);
delay(500);
digitalWrite(LED_PIN, LOW);
delay(500);
}
setup() operates one time after each reset. loop() then operates again and again until the power stops. There is no main() that you write, and there is no exit.
Serial.begin(115200) starts the serial port at 115200 bits each second. Set the same speed in the Serial Monitor. An incorrect speed does not give an error. It gives characters that have no meaning, which is the same symptom as damaged hardware and sends many beginners to the wrong conclusion.
delay(500) stops the program for 500 milliseconds. It is correct in a first program and incorrect in a real one: the processor does no other work during that time. Use millis() to compare times when the program must do more than one operation.
Use the LED pin of your board. GPIO4 is the pin in this lab. The DevKit V1 uses GPIO2. The C3 SuperMini has a user LED on GPIO8 that is active-low, so LOW makes it operate. If the LED does not change, this is the first item to examine.
Five failures that stop the first upload
These five conditions cause almost all failed first uploads. Examine them in this sequence.
1. The cable carries power and not data. Many USB cables that are supplied with a device have two conductors, not four. The board receives power, the LED on the board operates, and no port appears on the computer. Use a different cable before you examine anything else. This is the most frequent failure and the least expected.
2. The driver is not installed. A board that uses a converter chip needs the driver for that chip: CP210x for a Silicon Labs converter, CH340 for a WCH converter. Without the driver, no port appears. Boards with a USB port directly to the chip (C3, S3, C6, H2) do not need a driver.
3. The chip is not in download mode. The board resets the chip into download mode with the data terminal ready (DTR) and request to send (RTS) lines. Some boards do not have the transistor circuit that this needs. The upload then stops at Connecting........_____. Do it manually, in this order:
4. The port is incorrect. More than one serial port can be present, in particular on a computer with Bluetooth. Disconnect the board, look at the port list, connect the board, and look again. The port that appears is your board.
5. The port disappears after the upload. This occurs on the C3, S3, C6, and H2, and not on the classic ESP32. Their USB port is made by the chip. When the chip resets to start your program, the port disappears from the computer and then appears again. The Serial Monitor loses the connection and shows nothing.
There are two results of this condition. First, in the Arduino IDE, set Tools > USB CDC On Boot > Enabled, or Serial sends to the hardware UART pins and not to the USB port. Second, open the Serial Monitor after the board completes the restart, and expect to lose the first lines that the program prints. To read the first lines, put a delay(2000) at the start of setup().
The last condition looks the same as a chip that has stopped: no output. An empty buffer is not a stopped chip. Change one condition at a time.
The pins that you must not use
The ESP32 family has a GPIO matrix. Almost any peripheral can operate on almost any pin. This is a real advantage, and it is also the reason that a tutorial pin number can damage your project without an error message.
Some pins have another function that operates before your program does.
The manufacturer diagram gives each pin and each function. These are the two Espressif boards. The C3 SuperMini is in Start now, with no board above.
Those diagrams give each function of each pin. They do not answer the question that you have while you select a pin, which is shorter: may I use this one? The figure below answers that question, for the three chips, from the same datasheets.
The paragraphs below give the reason behind each colour.
Strapping pins are read by the chip at reset to select the boot mode. If your circuit holds one at the incorrect level, the chip does not start your program. It goes into download mode, or it does not start at all. On the classic ESP32 there are five: GPIO0, GPIO2, GPIO5, GPIO12, and GPIO15. On the C3 there are three: GPIO2, GPIO8, and GPIO9. On the S3 there are four: GPIO0, GPIO3, GPIO45, and GPIO46.
GPIO12 on the classic ESP32 is the condition that is most difficult to find. It selects the voltage of the internal regulator that supplies the flash memory. It has an internal pull-down resistor. If you connect a device that pulls GPIO12 up at reset, the chip sets the flash supply to 1.8 V, the flash does not operate, and the board goes into a boot loop. The wiring is correct, the code is correct, and the board does not start.
Flash pins connect the chip to its own program memory. If you use them, the chip cannot read the program that it is executing. On the classic ESP32 these are GPIO6 to GPIO11. On the C3 these are GPIO12 to GPIO17. On the S3 these are GPIO26 to GPIO32, and also GPIO33 to GPIO37 on modules that have octal PSRAM. Many boards do not bring these pins to the header. Do not use them if they are present.
Input-only pins are on the classic ESP32: GPIO34 to GPIO39. They have no output driver and no internal pull-up or pull-down resistor. digitalWrite on one of these pins does nothing and reports no error. A button on one of these pins needs an external resistor.
USB pins carry the USB signals on the chips that have a USB controller: GPIO18 and GPIO19 on the C3, and GPIO19 and GPIO20 on the S3. Use them for another function and you lose the port that you program the board through.
Console pins carry UART0, which is where the boot messages and Serial.print go: GPIO1 and GPIO3 on the classic ESP32, GPIO20 and GPIO21 on the C3, GPIO43 and GPIO44 on the S3. The circuit operates if you use them, and you lose the serial monitor while it does. Connect an LED to GPIO1 on a DevKit V1 and it blinks with each character that the board prints.
The second analog-to-digital converter (ADC2) and Wi-Fi are in conflict on the classic ESP32. The Wi-Fi driver uses ADC2. A read on an ADC2 pin while Wi-Fi is active can fail instead of giving a value. If a sensor reading becomes incorrect at the moment that the network connects, this is the cause. Use an ADC1 pin (GPIO32 to GPIO39) for each analog input in a project that uses Wi-Fi.
A short rule for the classic ESP32: use GPIO4, GPIO16 to GPIO23, GPIO25 to GPIO27, and GPIO32 or GPIO33 for outputs. Keep GPIO34 to GPIO39 for inputs.
What to build after the blink
Add one item at a time, and make sure that each item operates before you add the next.
- Read a sensor over I²C. A BME280 gives temperature, humidity, and pressure on two wires. This teaches you buses, addresses, and pull-up resistors — and it is where most beginners meet their first failure with no error message. Debugging I²C gives the four failures and the check that finds each one.
- Connect to Wi-Fi and print your internet protocol (IP) address. This is 10 lines. It is also the point at which power supply failures start: the radio takes current in pulses, and a weak USB port causes a brownout reset the moment that the radio transmits.
- Send the sensor reading somewhere. A message queuing telemetry transport (MQTT) broker, an HTTP endpoint, or a display.
- Make it operate on a battery. Deep sleep changes each decision that you made before it. It is the correct point to move from Arduino to ESP-IDF.
Each of these steps is available in the browser before your board arrives, and each of them stays available after: a lab that repeats exactly is the fastest way to separate a code failure from a hardware failure.
Open the Playground to wire your own ESP32 circuit, or point your coding agent at the LabWired MCP server and have it run the firmware that it writes, on a chip model, before you flash a board.
Do you have an ESP32 failure that took you a day to find? Tell us on r/labwired. We add the best examples to this lesson.