ph-esp32-mac

February 12, 2026 ยท View on GitHub

Crates.io Docs.rs CI

ph-esp32-mac is a no_std, no_alloc Rust driver for the ESP32 Ethernet MAC (EMAC). It targets ESP32 hardware, provides LAN8720A PHY support, and integrates with smoltcp, embassy-net, and esp-hal.


Table of Contents

  1. Overview
  2. Status & Scope
  3. Motivation
  4. Goal
  5. Features
  6. Supported Hardware
  7. Quick Start (Happy Path)
  8. Recommended Workflow
  9. Examples
  10. Memory & DMA Sizing
  11. Feature Flags
  12. MSRV
  13. Documentation
  14. License

Overview

This crate implements the ESP32 EMAC peripheral using static DMA descriptors and buffers. It is designed for embedded use with explicit initialization, no heap allocation, and predictable memory usage. The public API is optimized for esp-hal consumers while keeping low-level control available.


Status & Scope

  • Current target: ESP32 (this release only)
  • ESP32-P4: Experimental placeholder (not implemented, hidden from docs)
  • Happy path: esp-hal synchronous and async bring-up on WT32-ETH01

Motivation

There was no existing bare-metal, no_std, no_alloc Rust driver for the ESP32 MAC, which created a barrier to using wt32_eth01.rs in the bare-metal ecosystem.


Goal

Provide an efficient bare-metal, no_std, no_alloc implementation of the ESP32 MAC to enable use of the LAN8720A Ethernet PHY.


Features

  • ESP32 RMII support (MII is available but secondary)
  • LAN8720A PHY driver with a generic PHY fallback
  • smoltcp integration (smoltcp feature)
  • embassy-net driver integration (embassy-net feature)
  • esp-hal integration helpers (esp-hal feature)
  • Async/waker support without allocation (async + critical-section)

Supported Hardware

  • ESP32 (current release target)
  • ESP32-P4 (experimental / not implemented yet, hidden from docs)

Quick Start (Happy Path)

These are the recommended esp-hal bring-up paths and match the examples in apps/examples/.

esp-hal (sync)

use esp_hal::delay::Delay;
use ph_esp32_mac::esp_hal::{EmacBuilder, EmacPhyBundle, Wt32Eth01};

ph_esp32_mac::emac_static_sync!(EMAC, 10, 10, 1600);

let mut delay = Delay::new();
EMAC.with(|emac| {
    EmacBuilder::wt32_eth01_with_mac(emac, [0x02, 0x00, 0x00, 0x12, 0x34, 0x56])
        .init(&mut delay)
        .unwrap();
    let mut emac_phy = EmacPhyBundle::wt32_eth01_lan8720a(emac, Delay::new());
    let _status = emac_phy
        .init_and_wait_link_up(&mut delay, 10_000, 200)
        .unwrap();
    emac.start().unwrap();
});

esp-hal (async)

use esp_hal::delay::Delay;
use ph_esp32_mac::esp_hal::{EmacBuilder, EmacPhyBundle, Wt32Eth01};
use ph_esp32_mac::{emac_async_isr, emac_static_async};

emac_static_async!(EMAC, EMAC_STATE, 10, 10, 1600);
emac_async_isr!(EMAC_IRQ, esp_hal::interrupt::Priority::Priority1, &EMAC_STATE);

let mut delay = Delay::new();
let emac_ptr = EMAC.init(ph_esp32_mac::Emac::new()) as *mut _;
unsafe {
    EmacBuilder::wt32_eth01_with_mac(&mut *emac_ptr, [0x02, 0x00, 0x00, 0x12, 0x34, 0x56])
        .init(&mut delay)
        .unwrap();
    let mut emac_phy = EmacPhyBundle::wt32_eth01_lan8720a(&mut *emac_ptr, Delay::new());
    let _status = emac_phy
        .init_and_wait_link_up(&mut delay, 10_000, 200)
        .unwrap();
    (*emac_ptr).start().unwrap();
}

From the repo root, use cargo xtask to build and flash apps:

cargo xtask run ex-esp-hal
cargo xtask run ex-esp-hal-async

See xtask/README.md for details.


Examples

Examples are provided as a separate crate in this repository and are not packaged with the published library crate. They require the Xtensa toolchain and flashing setup, so they are kept repo-only to avoid pulling those requirements into crates.io consumers.

See apps/examples/README.md for build and run instructions.

Recommended runner (from repo root):

cargo xtask run ex-embassy-net

Included examples:

  • smoltcp_echo
  • esp_hal_integration
  • esp_hal_async
  • embassy_net

Hardware QA runner (separate crate):


Memory & DMA Sizing

Default configuration (10 RX/TX buffers, 1600 bytes each):

ComponentSize
RX descriptors320 bytes
TX descriptors320 bytes
RX buffers16,000 bytes
TX buffers16,000 bytes
Total~32 KB

Adjust via the static macros if memory is constrained:

ph_esp32_mac::emac_static_sync!(EMAC, 4, 4, 1600);

Feature Flags

FeatureDescription
esp32ESP32 target (default)
esp32p4Experimental placeholder (not implemented)
smoltcpsmoltcp integration
embassy-netembassy-net-driver integration
esp-halesp-hal integration helpers
critical-sectionShared/ISR-safe access wrappers
asyncAsync/waker support (requires critical-section)
defmtdefmt formatting support
loglog crate support

MSRV

  • Rust 1.92.0

Documentation


License

Licensed under the Apache License, Version 2.0. See LICENSE.