MCUForge Beta Cloud build · Local flash

Guides › Tutorial · UART

ESP32 UART echo with ESP-IDF, built in the browser

A second UART on the ESP32 that sends back everything it receives, and logs it. You will wire a USB-to-serial adapter, read the code, build it, flash the board and type to it. No local ESP-IDF needed.

ESP-IDF v6.1 · ESP32 · about 15 minutes · updated 27 October 2026

What you need

Wiring

The example uses UART2 of the ESP32 on two free GPIOs. Cross TX and RX, and connect the grounds:

ESP32Adapter
GPIO4 (TX)RX
GPIO5 (RX)TX
GNDGND

Do not connect GPIO4 to GPIO5 directly as a "loopback": the board would echo its own echo forever. The point of the adapter is that your typing is the only thing arriving on RX.

1. Open the example

In MCUForge Studio choose Project › Open Example... and open Communication › uart_echo. Make sure the target at the top is ESP32. The project has the usual ESP-IDF layout: CMakeLists.txt, main/uart_echo_example_main.c and main/Kconfig.projbuild, which defines the pins, port and baud rate.

2. The code, line by line

The settings come from Kconfig (menuconfig) instead of being hard-coded. For the ESP32 the defaults are UART port 2, 115200 baud, TX on GPIO4 and RX on GPIO5:

#define ECHO_TEST_TXD        (CONFIG_EXAMPLE_UART_TXD)        // 4
#define ECHO_TEST_RXD        (CONFIG_EXAMPLE_UART_RXD)        // 5
#define ECHO_UART_PORT_NUM   (CONFIG_EXAMPLE_UART_PORT_NUM)   // 2 on ESP32
#define ECHO_UART_BAUD_RATE  (CONFIG_EXAMPLE_UART_BAUD_RATE)  // 115200

The work happens in a FreeRTOS task. First it describes the line format: 8 data bits, no parity, 1 stop bit, no hardware flow control.

uart_config_t uart_config = {
    .baud_rate = ECHO_UART_BAUD_RATE,
    .data_bits = UART_DATA_8_BITS,
    .parity    = UART_PARITY_DISABLE,
    .stop_bits = UART_STOP_BITS_1,
    .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
    .source_clk = UART_SCLK_DEFAULT,
};

Then it installs the driver with a 2 KB receive buffer (and no transmit buffer, so writes wait until the bytes are out), applies the format and routes the UART to the chosen pins:

uart_driver_install(ECHO_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags);
uart_param_config(ECHO_UART_PORT_NUM, &uart_config);
uart_set_pin(ECHO_UART_PORT_NUM, ECHO_TEST_TXD, ECHO_TEST_RXD, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

The loop reads whatever arrived within 20 ms, writes the same bytes back, and logs them on the main console (UART0, the USB port):

int len = uart_read_bytes(ECHO_UART_PORT_NUM, data, BUF_SIZE - 1, 20 / portTICK_PERIOD_MS);
uart_write_bytes(ECHO_UART_PORT_NUM, (const char *) data, len);
if (len) {
    data[len] = '\0';
    ESP_LOGI(TAG, "Recv str: %s", (char *) data);
}

app_main only starts that task: xTaskCreate(echo_task, "uart_echo_task", ...).

3. Build

Press Build. The project is compiled on the server with ESP-IDF v6.1; the Build Console shows the output and errors appear in Problems. The first build of a project takes a minute or two, later ones are faster.

4. Flash

Connect the ESP32 with its USB cable, choose Device › Connect, pick the board's port in the Chrome dialog, then Device › Flash. Open the Serial Monitor tab to see the board's log (UART0).

5. Test

Open the adapter's port in your serial terminal at 115200 baud, 8N1. Type hello:

If nothing comes back

Next steps

Build it yourself

Open the uart_echo example in MCUForge, build it in the cloud and flash your ESP32 from the browser. Free plan: 10 builds a day.

Try MCUForge free