ESP32 + Rust: Interactive Project with UART-Controlled LED
Introduction
In my previous article, we explored the "Hello, World!" of embedded programming: a blinking LED on the ESP32 using Rust. That project was all about setting up the development environment and running simple code. Now, let’s take it up a notch by making the ESP32 interactive. Instead of passively blinking, we’ll enable the ESP32 to respond to commands sent from a computer via USB serial (UART). This project introduces real-time interaction, laying the foundation for more complex Internet of Things (IoT) applications.
Let’s dive into creating an interactive UART-controlled LED project with Rust on the ESP32!
Prerequisites
Before starting, ensure you have the following from previous article:
-
Hardware:
- An ESP32 development board (e.g., ESP32-DevKitC).
- An LED connected to GPIO5 with a current-limiting resistor (e.g., 220–330 ohms to ground).
- A USB cable for serial communication and power.
-
Software:
- Rust installed with the
esp-idftoolchain configured. Refer to the [step-by-step guide on Patreon] if you haven’t set this up yet. - A serial terminal program.
- Rust installed with the
Project Plan
Here’s the high-level plan for our interactive project:
- Initialize UART: Configure the ESP32’s UART0 peripheral for serial communication.
- Read Input: Capture data sent from a serial terminal.
- Parse Commands: Interpret the received data as commands to control the LED.
- Perform Actions: Turn the LED on/off or report its status based on the command.
- Provide Feedback: Echo commands and send debug information (e.g., raw hex data) back to the terminal.
Features Implemented
This project implements the following features:
-
Interactive Commands via UART:
1: Turn the LED on.0: Turn the LED off.5: Report the LED’s current state (ONorOFF).
-
Robust UART Handling:
- A fixed-size input buffer with safety checks to prevent overflows.
- Conversion of raw input to UTF-8 strings with trimming of whitespace and newline characters.
- Debugging output in hexadecimal format to inspect raw received data.
-
User Feedback:
- Echoes every command received.
- Displays the raw input buffer, trimmed command, and action result.
- Sends error messages for invalid inputs or read errors.
Workflow
The ESP32’s default UART0 pins (TX on GPIO1, RX on GPIO3) are already configured for USB serial communication in most development boards. We’ll leverage this setup to communicate with a computer. The LED is connected to GPIO5, and we’ll use Rust’s esp_idf_hal crate to control both the UART and GPIO peripherals.
Code Breakdown
Below is a detailed explanation of the Rust program that powers this project.
1. Setting Up Peripherals
We use the esp_idf_hal crate to safely initialize the ESP32’s peripherals. The Peripherals::take() method ensures exclusive access to hardware resources.
use Peripherals;
let peripherals = match take ;
let pins = peripherals.pins;
This code retrieves the GPIO and UART peripherals for use in the program.
2. Configuring the LED
The LED is connected to GPIO5 and configured as an output pin using PinDriver::output. We initialize it to the low state (off).
use PinDriver;
let mut led = match output ;
let _ = led.set_low;
3. Setting Up UART
We configure UART0 for serial communication at a baud rate of 115200. The TX and RX pins are mapped to GPIO1 and GPIO3, respectively, which are the default USB serial pins on most ESP32 boards.
use ;
use Hertz;
let config = new.baudrate;
let uart = match new ;
// Send initial confirmation message
let _ = uart.write;
The initial ESP32 Ready message confirms that the UART is operational.
4. Command Processing Loop
The main loop reads serial input into a 64-byte buffer and processes it as UTF-8 commands. It supports the commands 1, 0, and 5, and provides feedback for each action.
use str;
let mut buf = ;
loop
Full code you can find in my GitHub: https://github.com/AnakenRalf/esp32-comport-simple-communication
5. Debugging with Hex Output
To aid debugging, the program converts the raw input buffer to a hexadecimal string and sends it back over UART. This allows you to inspect the exact bytes received, which is especially useful for diagnosing issues with serial communication.
Serial Terminal Implementation
There are many serial terminal programs available, such as PuTTY (Windows), minicom, or picocom (Linux/macOS). However, each has its own quirks, and unexpected data (e.g., extra newlines or control characters) can cause the ESP32 to report errors like Invalid UTF-8 input or Read error. To simplify communication for this educational project, we provide a custom Python serial terminal script that sends exactly the expected commands.
# Adjust 'COM3' to your port, e.g., '/dev/ttyUSB0' on Linux
=
# Configure serial port
=
# Clear initial buffer and read boot messages
=
break
# Send command with \r\n
# Read responses for up to 0.5s
=
=
This script:
- Connects to the ESP32 via the specified COM port (adjust
COM3to match your system). - Sends commands with proper newline termination (
\r\n). - Displays responses from the ESP32, including raw hex output and command feedback.
- Closes the serial port cleanly when you type
exitor interrupt the program.
Using this script ensures reliable communication, but as you gain experience, you can extend the ESP32’s command parser to handle more complex inputs (e.g., accumulating data until a newline is received).
How to Use
Follow these steps to set up and run the project:
-
Connect the Hardware:
- Wire an LED to GPIO5 with a current-limiting resistor (e.g., 220–330 ohms) to ground.
- Connect the ESP32 to your computer via a USB cable.
-
Build and Flash:
- Use the
esp-idftoolchain to compile the Rust code to your ESP32. Run: - Flash binary files to controller
- Use the
-
Run the Python Serial Terminal:
- Save the Python script above as
serial_terminal.py. - Install the
pyseriallibrary:pip install pyserial. - Run the script:
python serial_terminal.py. - Adjust the COM port in the script if necessary (e.g.,
/dev/ttyUSB0on Linux).
- Save the Python script above as
-
Send Commands:
- Type
1and press Enter to turn the LED on. - Type
0and press Enter to turn the LED off. - Type
5and press Enter to check the LED’s state. - Type
exitto close the serial terminal.
- Type
-
Observe Feedback:
- The ESP32 responds with:
- The raw input buffer in hexadecimal.
- The trimmed command.
- The result of the command (e.g.,
Command: ON, LED ONorUnknown command).
- The ESP32 responds with:
Demo
You can see actions in YouTube short video
Why This Step Is Important
This project marks a significant milestone in your Rust + ESP32 journey:
- Interactivity: The ESP32 is no longer just executing pre-programmed code—it’s responding to real-time user input.
- Foundation for IoT: UART communication is a building block for more advanced features, such as Wi-Fi configuration, sensor data reporting, or remote control.
- Debugging Skills: By including raw hex output and error handling, you’re learning how to diagnose issues in embedded systems.
- Scalability: The command-processing loop can be extended to support additional commands, such as PWM for LED brightness or Wi-Fi setup for network connectivity.
This project bridges the gap between a simple “Hello, World” and a true interactive embedded application.
ADV
Become Patreon for support Me.