A beginner-friendly ESP32 project demonstrating hardware control on the Atom Echo M5 device. This example shows how to read button input and control an RGB LED using modern ESP-IDF APIs.
This project is perfect for beginners learning embedded C programming and ESP32 development:
- C Programming Basics: Variables, functions, structures, pointers, and control flow
- Hardware Control: GPIO input/output, reading buttons, controlling LEDs
- ESP32 Peripherals: Using the RMT (Remote Control Transceiver) for precise timing
- Real-time Systems: Understanding FreeRTOS tasks and timing
- Embedded Concepts: Debouncing, edge detection, infinite loops
- Protocol Implementation: WS2812 "NeoPixel" LED communication
- Reads button presses from the built-in button
- Toggles an RGB LED on/off with each button press
- Implements proper button debouncing for reliable operation
- Uses the modern ESP-IDF v5.x RMT driver API (no deprecation warnings!)
- Atom Echo M5: A compact ESP32-PICO based development board
- Built-in Button: Connected to GPIO39 (input-only pin)
- WS2812 RGB LED: Connected to GPIO27 (addressable "smart" LED)
-
ESP-IDF v5.0+: The official ESP32 development framework
# Install ESP-IDF following the official guide: # https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/
-
USB Driver: For the CH9102 USB-to-Serial chip on Atom Echo
- Most systems have this built-in
- If needed: CH9102 Driver
atom_echo_beep/
βββ main/
β βββ CMakeLists.txt # Build configuration
β βββ main.c # Main program (heavily commented!)
βββ CMakeLists.txt # Project configuration
βββ README.md # This file
βββ sdkconfig # ESP-IDF configuration
# Clean any previous builds
idf.py fullclean
# Set target to ESP32
idf.py set-target esp32
# Build the project
idf.py build
# Find your serial port
ls /dev/cu.*
# Look for something like: /dev/cu.usbserial-XXXXXXXX
# Flash to device (use slower baud rate for reliability)
idf.py -p /dev/cu.usbserial-XXXXXXXX -b 115200 flash
# Monitor serial output
idf.py -p /dev/cu.usbserial-XXXXXXXX monitor
# Press Ctrl+] to exit monitorIf you have issues flashing, try:
# Erase flash completely and start fresh
python -m esptool --port /dev/cu.usbserial-XXXXXXXX --chip esp32 erase_flash
# Then try flashing again with even slower baud rate
idf.py -p /dev/cu.usbserial-XXXXXXXX -b 9600 flashThe code is extensively commented to help beginners understand every concept. Here are the key sections:
#include "freertos/FreeRTOS.h" // Real-time operating system
#include "driver/gpio.h" // GPIO control
#include "driver/rmt_tx.h" // RMT transmitter (for LED timing)- Input Pin (Button): GPIO39 - special "input-only" pin
- Output Pin (LED): GPIO27 - controls WS2812 RGB LED
The WS2812 is a "smart" LED that receives data through precise timing:
- Bit 0: 350ns HIGH + 1000ns LOW
- Bit 1: 1000ns HIGH + 350ns LOW
- Data Format: 24 bits total (8 bits each for Green, Red, Blue)
Mechanical buttons "bounce" - they make/break contact multiple times when pressed. The code implements a 50ms debounce delay to ensure clean button detection.
The program runs in an infinite loop (common in embedded systems):
- Read button state
- Detect press (HIGHβLOW transition)
- Toggle LED if valid press detected
- Small delay to prevent CPU hogging
ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan));
// ^ ^
// Address of config Address to store handleThe & gets the memory address of a variable, allowing functions to modify it.
.pin_bit_mask = (1ULL << BUTTON_PIN) // Creates: 0x8000000000
// ^ ^
// 1 Shift left by 39 positionsUsed to select specific GPIO pins by setting individual bits.
gpio_config_t button_config = {
.pin_bit_mask = ..., // Named field initialization
.mode = GPIO_MODE_INPUT,
// ...
};C structures group related data; we initialize them with named fields.
Modern ESP-IDF uses "handles" (opaque pointers) to manage hardware:
rmt_channel_handle_t led_chan; // Handle to RMT channel
rmt_encoder_handle_t led_encoder; // Handle to encoder- Interactive Tutorial: Learn-C.org
- Book: "The C Programming Language" by K&R (classic)
- Video Series: CS50 Introduction to Computer Science
- Official Docs: ESP-IDF Programming Guide
- Examples: ESP-IDF Examples Repository
- Forum: ESP32 Forum
- FreeRTOS: FreeRTOS.org - Real-time operating system
- GPIO: General Purpose Input/Output - digital pin control
- RMT: Remote Control Transceiver - generates precise waveforms
- WS2812: Datasheet - LED protocol details
Once you understand the basic code, try these modifications:
-
Change LED Colors: Modify the RGB values in
ws2812_set_color()ws2812_set_color(255, 0, 0); // Bright red ws2812_set_color(0, 255, 0); // Bright green ws2812_set_color(0, 0, 255); // Bright blue
-
Add Color Cycling: Make the LED cycle through colors
-
Pattern Sequences: Create blinking or fading patterns
-
Multiple Press Actions: Different actions for short/long press
-
Rainbow Effect: Smoothly transition through color spectrum
- Check GPIO27 connection
- Verify WS2812 timing parameters
- Ensure proper power supply (3.3V)
- GPIO39 has no internal pull-up (external resistor on board)
- Check debounce timing
- Verify button is connected to GPIO39
- This code uses the modern RMT API (driver/rmt_tx.h)
- No deprecation warnings with ESP-IDF v5.0+
This example code is provided as-is for educational purposes. Feel free to use and modify for your projects!
Found an issue or have an improvement? Feel free to contribute!
- Understand the existing code structure
- Keep comments beginner-friendly
- Test your changes on actual hardware
Happy Learning! π This project is designed to help you understand embedded C programming and ESP32 development. Take your time to read through the comments in main.c - they explain every concept in detail!