Skip to content

mytechnotalent/esp32c3_rust_uart_driver

Repository files navigation

ESP32-C3 Bare-Metal UART Driver

FREE Reverse Engineering Self-Study Course HERE

VIDEO PROMO HERE


ESP32-C3 Rust UART Driver

Embedded Rust w/ bare-metal USB Serial/JTAG UART driver for the ESP32C3.


Complete Component Kit BUY

10% DISCOUNT CODE

KVPE_HS320548_10PC


FULL TUTORIAL HERE


Install ESP Toolchain

Windows Installer HERE

Linux and macOS Installer HERE


Required Hardware

  • ESP32-C3 DevKit
    • Development board based on the ESP32-C3 microcontroller (RISC-V 32-bit @ 160MHz).
    • Features: Onboard USB-JTAG debugger, WiFi/BLE connectivity, 4MB Flash, 400KB SRAM.
    • Ideal for bare-metal Rust development and low-level embedded systems learning.
  • USB-C Cable
    • For powering the board and programming via USB-JTAG.
  • Push Button
    • Momentary tactile switch for GPIO input.
    • One side connects to 3.3V, other side to GPIO1.
  • LED
    • Standard LED with current-limiting resistor (220Ω-1kΩ).
    • Anode (longer lead) to GPIO0, cathode to GND.
  • 10kΩ Resistor
    • Pull-down resistor for button (GPIO1 to GND).
    • Keeps GPIO1 LOW when button not pressed.
  • Breadboard and Jumper Wires
    • For prototyping connections between ESP32-C3, button, LED, and resistors.
    • Requires access to 3.3V, GND, GPIO0, and GPIO1 pins on the DevKit.

🚀 Quick Start

# Install the RISC-V target and Rust nightly
rustup toolchain install nightly
rustup target add riscv32imc-unknown-none-elf --toolchain nightly
rustup default nightly

# Connect your ESP32-C3 DevKit via USB

# Build and flash (debug build for development)
cargo run

# Or build and flash optimized release build
cargo run --release

That's it! The firmware will build and flash automatically with bootloader and partition table.


What's Included

  • Custom RISC-V Entry Point: RISC-V _start function with proper initialization
  • Startup Handler: Manual .data/.bss initialization and stack pointer setup
  • Exception Handlers: Machine-mode trap handlers for RISC-V exceptions
  • Peripheral Interrupt Handlers: ESP32-C3 specific peripheral interrupt handlers
  • USB Serial/JTAG UART Driver: Direct USB CDC communication matching assembly reference
  • Button Input Driver: GPIO input with IO_MUX configuration for reading button state
  • LED Output Driver: GPIO output control for LED indication
  • Serial Command Interface: Control LED via UART with ON/OFF/toggle commands
  • No Runtime Dependencies: Pure bare-metal implementation without runtime crates
  • Flash Script: Automated build, image creation, and flashing with bootloader support
  • VS Code Debugging: Full GDB debugging support via OpenOCD and USB-JTAG

Hardware Pin Mapping

  • Button: GPIO 1 (GPIO input with pull-down, active-high)
  • LED: GPIO 0 (GPIO output)
  • USB Serial/JTAG: Built-in USB CDC (GPIO 18/19, no external wiring needed)
  • UART0 Fallback: GPIO 20 (RX), GPIO 21 (TX)

Wiring

3.3V -------- [Button] -------- GPIO1 -------- [10kΩ] -------- GND
                                                                  
GPIO0 -------- [220Ω] -------- [LED+] -------- [LED-] -------- GND
  • Button connects GPIO1 to 3.3V when pressed (active-high)
  • 10kΩ pull-down resistor keeps GPIO1 LOW when button not pressed
  • LED turns ON when GPIO0 is HIGH
  • USB-C cable provides serial communication (no additional wiring needed)

Usage

After flashing the firmware, open a serial terminal at any baud rate (USB CDC ignores baud rate):

# macOS/Linux
screen /dev/cu.usbmodem3101

# Or using minicom
minicom -D /dev/cu.usbmodem3101

# Windows (use PuTTY, TeraTerm, or similar)

Button Control

  • Press Button: LED toggles and prints current state
    • "ON" when LED turns on
    • "OFF" when LED turns off

Serial Commands

Type commands followed by Enter (\r\n):

  • ON - Turn LED on
  • OFF - Turn LED off
  • 1 - Turn LED on (responds "ON")
  • 0 - Turn LED off (responds "OFF")
  • t - Toggle LED (responds "TOGGLED")

Example Session

ON          # Type ON and press Enter
            # LED turns on, cursor moves to next line
OFF         # Type OFF and press Enter  
            # LED turns off, cursor moves to next line
1           # Type 1 and press Enter
ON          # Firmware responds
t           # Type t and press Enter
TOGGLED     # Firmware responds
            # Press button - LED toggles
OFF         # Firmware prints current state

Building

This project targets the RISC-V 32-bit architecture with M and C extensions.

# Install the RISC-V target (if not already installed)
rustup target add riscv32imc-unknown-none-elf --toolchain nightly

# Build release
cargo build --release --target riscv32imc-unknown-none-elf

# Build debug (for debugging)
cargo build --target riscv32imc-unknown-none-elf

Flashing to ESP32-C3

Using the Flash Script (Recommended)

This project includes a flash script that handles:

  • Building the Rust binary (release or debug)
  • Converting ELF to ESP32-C3 bootable image format
  • Flashing bootloader, partition table, and application
# Flash debug build (for development and debugging)
cargo run

# Flash release build (optimized for speed and size)
cargo run --release

# Or use the script directly
./scripts/flash.sh        # release
./scripts/flash.sh debug  # debug

The script requires:

  • esptool: Install via pip install esptool
  • Bootloader: Pre-built bootloader in bootloader/bootloader.bin
  • Partition Table: Custom partition layout in partition/partitions.csv Memory Layout:
  • 0x0000: Bootloader
  • 0x8000: Partition table
  • 0x10000: Application (your code)

Manual Flashing (Advanced)

If you need to flash manually:

# Build
cargo build --release --target riscv32imc-unknown-none-elf

# Create ESP32-C3 image
esptool.py --chip esp32c3 elf2image \
    target/riscv32imc-unknown-none-elf/release/esp32c3_bm_uart_driver \
    -o target/app.bin

# Flash all components
esptool.py --chip esp32c3 --port /dev/cu.usbmodem3101 write_flash \
    0x0 bootloader/bootloader.bin \
    0x8000 partition/partitions.bin \
    0x10000 target/app.bin

Debugging with VS Code

This project includes full debugging support using OpenOCD and GDB.

Prerequisites

  1. ESP-IDF toolchain installed and sourced
  2. OpenOCD from ESP-IDF (included in toolchain)
  3. VS Code with Native Debug extension

Debug Workflow

  1. Flash debug build:
    cargo run
  2. Start OpenOCD:
    • In VS Code: Tasks: Run TaskOpenOCD
    • Or from terminal: ./scripts/openocd-wrapper.sh
  3. Start debugging:
    • Press F5 or click Run → Start Debugging
    • Debugger will connect, reset the target, and stop at startup
  4. Debug features:
    • Set breakpoints by clicking line numbers
    • Step through code (F10 = Step Over, F11 = Step Into)
    • Inspect variables and registers
    • View call stack Note: Debug builds have opt-level = 0 for better stepping but run slower. Release builds are optimized and faster but harder to debug.

Key Features

  1. Custom Startup Code: Complete control over RISC-V reset sequence and memory initialization
  2. Type Safety: Rust's type system prevents many common embedded bugs
  3. Explicit Memory Management: Manual .data/.bss initialization with volatile reads/writes
  4. Direct GPIO Control: Raw register access for GPIO button and LED control
  5. USB Serial/JTAG Driver: Bare-metal USB CDC implementation matching assembly reference
  6. Command Parser: Multi-character command buffering with string matching
  7. VS Code Integration: Full debugging support with GDB and OpenOCD
  8. Automated Flashing: Simple script handles bootloader and image conversion

Inspecting the Binary

View the sections and symbols:

# View section headers
cargo readobj --bin esp32c3_bm_uart_driver --target riscv32imc-unknown-none-elf -- --section-headers

# View symbol table
cargo nm --bin esp32c3_bm_uart_driver --target riscv32imc-unknown-none-elf

# Disassemble
cargo objdump --bin esp32c3_bm_uart_driver --target riscv32imc-unknown-none-elf -- -d

Generate API Documentation

cargo doc --no-deps --document-private-items --open

Memory Layout

  • FLASH: 4MB starting at 0x42000000 (instruction bus)
  • DRAM: 400KB starting at 0x3FC80000
  • IRAM: 384KB starting at 0x40380000 Defined in memory.ld for the ESP32-C3.

License

MIT

About

Embedded Rust w/ bare-metal USB Serial/JTAG UART driver for the ESP32C3.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published