Waveshare ESP32-P4-ETH

ESP32-P4-ETH

The Waveshare ESP32-P4-ETH is an ESP32-P4 development board with a MIPI-DSI display, capacitive touch, a MIPI-CSI camera, audio in/out, a microSD slot, and 10/100 Ethernet.

The espp::Esp32P4Eth component provides a singleton hardware abstraction for bringing up the board’s peripherals:

  • Display: a MIPI-DSI panel (ILI9881C 10.1” 800x1280 or EK79007 7” 1024x600, selected via Kconfig), with an LVGL display driver.

  • Touch: a GT911 capacitive multi-touch controller (polled — the INT / RST lines are not routed to the ESP32-P4 on this board).

  • Camera: a MIPI-CSI camera (OV5647 by default) captured through esp_video (V4L2), delivering RGB565 frames.

  • Audio: an ES8311 codec with an NS4150B amplifier for speaker output, and the onboard analog microphone through the codec’s ADC (full-duplex over I2S).

  • microSD / TF card: a 4-bit SDMMC slot powered by the on-chip LDO.

  • Ethernet: 10/100 via the internal EMAC and an IP101GRI RMII PHY, delegating to the reusable espp::Ethernet component and supplying the board-specific RMII pins (DHCP client / server).

The ES8311 codec, GT911 touch controller, and camera SCCB share a single internal I2C bus. The camera pipeline requires PSRAM and the MIPI-CSI Kconfig options enabled (see the example’s sdkconfig.defaults).

API Reference

Header File

Classes

class Esp32P4Eth : public espp::BaseComponent

Board Support Package (BSP) for the Waveshare ESP32-P4-ETH board.

This class provides a singleton interface to the board’s peripherals:

  • 10/100 Ethernet via the ESP32-P4 internal EMAC and an IP101GRI RMII PHY.

  • MIPI-DSI display (JD9365 10.1” by default, or ILI9881C 10.1” / EK79007 7”, selected via Kconfig) with a GT911 capacitive-touch controller.

  • MIPI-CSI camera (esp_video / V4L2 capture pipeline; OV5647 by default).

  • microSD / TF card over 4-bit SDMMC.

  • ES8311 audio codec (+ NS4150B amplifier) for speaker output and microphone input over I2S.

The ES8311 codec, GT911 touch, and camera SCCB share a single internal I2C bus (internal_i2c()). The Ethernet bring-up is delegated to the reusable espp::Ethernet component; this BSP supplies the board-specific pin mappings.

RMII pin mapping (ESP32-P4 routable EMAC pins). REF_CLK carries a 50 MHz reference clock (25 MHz crystal 2):

Signal

GPIO

REF_CLK

50

TX_EN

49

TXD0

34

TXD1

35

CRS_DV

28

RXD0

29

RXD1

30

MDC

31

MDIO

52

PHY_RST

51

The class is a singleton and can be accessed via get().

Example

  auto &board = Board::get();
  board.set_log_level(espp::Logger::Verbosity::INFO);
  logger.info("Display panel: {}", board.get_display_controller_name());

  // Probe the internal I2C bus (shared by the ES8311 codec, the GT911 touch
  // controller, and the camera SCCB).
  auto &i2c = board.internal_i2c();
  std::vector<uint8_t> found;
  for (uint8_t addr = 1; addr < 128; addr++) {
    if (i2c.probe_device(addr)) {
      found.push_back(addr);
    }
  }
  logger.info("Found {} I2C device(s)", found.size());

  // Display (MIPI-DSI + configured panel driver)
  if (!board.initialize_lcd()) {
    logger.error("Failed to initialize LCD!");
    return;
  }
  size_t pixel_buffer_size = board.display_width() * 50;
  if (!board.initialize_display(pixel_buffer_size)) {
    logger.error("Failed to initialize display!");
    return;
  }

  // Build the GUI: a tabview with a Status tab (live subsystem state + rotate /
  // clear buttons; touch to draw circles), an Audio tab (record / play +
  // volume), and a Camera tab (live MIPI-CSI feed). All of its public methods
  // are thread-safe, so the touch, status and camera tasks below call them
  // directly.
  static Gui gui({.log_level = espp::Logger::Verbosity::INFO});

  // On-screen status state. These are filled in as each subsystem initializes
  // below, and rendered immediately by the status task, so the display shows SD
  // / Ethernet coming online live instead of staying blank until the whole
  // bring-up finishes.
  static std::atomic<int> touch_x{0}, touch_y{0}, touch_n{0};
  static std::atomic<bool> sd_card_mounted{false};
  static std::atomic<uint32_t> sd_card_size_mb{0};
  static int64_t status_start_us = esp_timer_get_time();

  // Status updater: starts now (right after the display is up) and refreshes the
  // on-screen status ~10x/s. Ethernet state is read live from the board; SD
  // state is published into the atomics above as that subsystem comes up.
  espp::Task status_task(espp::Task::Config{
      .callback = [&board](std::mutex &m, std::condition_variable &cv) -> bool {
        const size_t free_internal = heap_caps_get_free_size(MALLOC_CAP_INTERNAL) / 1024;
        const size_t free_psram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM) / 1024;
        const int uptime_s = static_cast<int>((esp_timer_get_time() - status_start_us) / 1'000'000);
        std::string eth_text = "(no link)";
        if (board.is_ethernet_connected()) {
          auto ip = board.ethernet_ip();
          eth_text = std::to_string(esp_ip4_addr1_16(&ip)) + "." +
                     std::to_string(esp_ip4_addr2_16(&ip)) + "." +
                     std::to_string(esp_ip4_addr3_16(&ip)) + "." +
                     std::to_string(esp_ip4_addr4_16(&ip));
        }
        std::string status =
            "Panel:    " + std::string(board.get_display_controller_name()) + " (" +
            std::to_string(board.display_width()) + "x" + std::to_string(board.display_height()) +
            ")\n" + "Touch:    " + std::to_string(touch_n.load()) + " pts (" +
            std::to_string(touch_x.load()) + ", " + std::to_string(touch_y.load()) + ")\n" +
            "SD card:  " +
            (sd_card_mounted ? std::to_string(sd_card_size_mb.load()) + " MB" : "none") + "\n" +
            "Ethernet: " + eth_text + "\n" + "Camera:   " + std::to_string(board.camera_width()) +
            "x" + std::to_string(board.camera_height()) + "\n" +
            "System:   " + std::to_string(free_internal) + " KB int, " +
            std::to_string(free_psram) + " KB psram free, up " + std::to_string(uptime_s) + " s";
        gui.set_status_text(status);
        std::unique_lock<std::mutex> lock(m);
        cv.wait_for(lock, 100ms);
        return false;
      },
      .task_config = {.name = "p4-eth status", .stack_size_bytes = 6144}});
  status_task.start();

  // Touch: draw a circle wherever the screen is touched, and play a click on
  // each new touch-down. play_audio() is non-blocking, and the click is gated to
  // the touch-down edge so it doesn't retrigger every poll while held/dragging.
  static constexpr int kCircleRadius = 10;
  board.initialize_touch([&](const auto &data) {
    auto td = board.touchpad_convert(data);
    static Board::TouchpadData prev_td = {};
    touch_n = td.num_touch_points;
    touch_x = td.x;
    touch_y = td.y;
    if (td.num_touch_points > 0) {
      const bool new_touch = (prev_td != td);
      const bool touch_down_edge = (prev_td.num_touch_points == 0);
      // Touch feedback (click + circle) only applies on the draw/status page;
      // touches on the other tabs (buttons, sliders) stay silent.
      if (gui.draw_page_active()) {
        // Click feedback: instant on the touch-DOWN edge, and retriggered while
        // dragging - each retrigger restarts (clips) the click so drawing gives
        // a stream of overlapping-feel clicks. The retrigger interval keeps a
        // fast drag from restarting the click every poll (16 ms), which would
        // reduce it to a buzz of its first few milliseconds.
        static constexpr auto kClickRetriggerInterval = std::chrono::milliseconds(100);
        static auto last_click_time = std::chrono::steady_clock::time_point{};
        const auto now = std::chrono::steady_clock::now();
        const bool click_due =
            touch_down_edge || (now - last_click_time >= kClickRetriggerInterval);
        if (new_touch && click_due && !audio_bytes.empty()) {
          board.clear_audio();           // drop any queued tail (restart)
          board.play_audio(audio_bytes); // non-blocking
          last_click_time = now;
        }
        if (new_touch) {
          gui.draw_circle(td.x, td.y, kCircleRadius);
        }
      }
    }
    prev_td = td;
  });

  // microSD (optional — only present if a card is inserted)
  bool sd_ok = board.initialize_sdcard({.format_if_mount_failed = false});
  uint32_t sd_size_mb = 0, sd_free_mb = 0;
  if (sd_ok) {
    board.get_sd_card_info(&sd_size_mb, &sd_free_mb);
    logger.info("SD card: {} MB total, {} MB free", sd_size_mb, sd_free_mb);
  } else {
    logger.warn("No SD card mounted");
  }
  sd_card_mounted = sd_ok;
  sd_card_size_mb = sd_size_mb; // published to the status task

  // Audio (ES8311) — load the embedded click sound first so we can initialize
  // the codec directly at the clip's sample rate (changing the sample rate after
  // the audio task is running is racy, so we avoid it here).
  size_t wav_size = 0, wav_sample_rate = 0;
  bool have_audio = load_audio(wav_size, wav_sample_rate);
  uint32_t audio_rate = have_audio ? static_cast<uint32_t>(wav_sample_rate) : 48000;
  if (board.initialize_audio(audio_rate)) {
    board.mute(false);
    board.volume(60.0f);
    if (have_audio) {
      logger.info("Loaded {} bytes of click audio @ {} Hz", wav_size, wav_sample_rate);
    }

    // Microphone: the ES8311 is full duplex, so the onboard microphone records
    // at the speaker's sample rate. Buffer the recorded mono samples and
    // auto-stop when the buffer is full (the main loop notices and updates the
    // GUI).
    auto mic_callback = [](const uint8_t *data, size_t num_bytes) {
      if (!recording) {
        return;
      }
      size_t offset = recording_len;
      size_t to_copy = std::min(num_bytes, recording_capacity - offset);
      if (to_copy > 0) {
        memcpy(recording_buffer + offset, data, to_copy);
        recording_len = offset + to_copy;
      }
      if (recording_len >= recording_capacity) {
        recording = false;
      }
    };
    if (board.initialize_microphone(mic_callback)) {
      // allocate the recording buffer (16-bit mono at the current sample rate):
      // prefer PSRAM, fall back to a couple of seconds in internal RAM
      size_t bytes_per_second = board.audio_sample_rate() * sizeof(int16_t);
      recording_capacity = MAX_RECORDING_SECONDS * bytes_per_second;
      recording_buffer = static_cast<uint8_t *>(
          heap_caps_malloc(recording_capacity, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
      if (recording_buffer == nullptr) {
        recording_capacity = FALLBACK_RECORDING_SECONDS * bytes_per_second;
        recording_buffer =
            static_cast<uint8_t *>(heap_caps_malloc(recording_capacity, MALLOC_CAP_8BIT));
      }
      if (recording_buffer == nullptr) {
        logger.warn("Could not allocate a recording buffer; recording disabled");
        gui.set_audio_status("No recording buffer");
        recording_capacity = 0;
      } else {
        logger.info("Recording buffer: {} KB ({} s at {} Hz mono)", recording_capacity / 1024,
                    recording_capacity / bytes_per_second, board.audio_sample_rate());
      }
    } else {
      logger.warn("Could not initialize the microphone!");
      gui.set_audio_status("Mic unavailable (see log)");
    }
  }

  // The record button toggles recording; the play button toggles playback of
  // the recording (streamed to the speaker by the main loop).
  gui.set_record_callback([&]() {
    if (recording_capacity == 0) {
      logger.warn("Recording unavailable (no microphone / no buffer)");
      gui.set_audio_status("Mic unavailable (see log)");
      return;
    }
    if (recording) {
      recording = false; // the main loop notices and logs the summary
    } else {
      playing = false;
      gui.set_play_active(false);
      recording_len = 0;
      recording = true;
      gui.set_record_active(true);
      gui.set_audio_status("Recording...");
    }
  });
  gui.set_play_callback([&]() {
    if (playing) {
      playing = false;
      gui.set_play_active(false);
      gui.set_audio_status("Playback stopped");
    } else if (recording_len > 0) {
      recording = false;
      playing = true;
      gui.set_play_active(true);
      gui.set_audio_status("Playing...");
    } else {
      logger.info("Nothing recorded yet; press the record button first");
      gui.set_audio_status("Nothing recorded yet");
    }
  });

  // Ethernet (IP101GRI) — DHCP client; the callback fires once an IP is acquired
  board.initialize_ethernet({
      .on_link_up = [&]() { logger.info("Ethernet link up"); },
      .on_link_down = [&]() { logger.warn("Ethernet link down"); },
      .on_got_ip =
          [&](esp_ip4_addr_t ip) {
            char buf[16] = {0};
            esp_ip4addr_ntoa(&ip, buf, sizeof(buf));
            logger.info("Ethernet IP: {}", buf);
          },
  });

  // Camera (MIPI-CSI) — stream each RGB565 frame to the Camera tab. The BSP runs
  // a capture task that hands each frame to this callback; forward it to the
  // thread-safe GUI. Non-fatal: the rest of the example still runs if the camera
  // is unavailable.
  logger.info("Initializing camera...");
  if (!board.initialize_camera(
          [&](const uint8_t *data, int w, int h, size_t) { gui.set_camera_frame(data, w, h); })) {
    logger.warn("Failed to initialize camera; the Camera tab will stay blank");
  }

Note

Timekeeping uses the ESP32-P4’s internal RTC; use the standard C/ESP-IDF time APIs rather than a dedicated RTC driver.

Public Types

enum class DhcpMode

DHCP operating mode for the Ethernet interface.

Values:

enumerator CLIENT

DHCP client — acquire an IP from an upstream server (default).

enumerator SERVER

DHCP server — assign IPs to hosts connected to this interface.

enum class DisplayController

Enum for the display controller type (selected via Kconfig)

Values:

enumerator UNKNOWN
enumerator EK79007
enumerator ILI9881C
enumerator JD9365
using client_ip_callback_t = std::function<void(esp_ip4_addr_t ip, std::array<uint8_t, 6> mac)>

Callback invoked (SERVER mode only) each time the DHCP server assigns an IP address to a connected client.

using EthernetLinkCallback = std::function<void()>

Callback invoked when the Ethernet link state changes or the IP is lost.

Note

Runs in the ESP-IDF event-loop task context — return quickly, do not block.

using EthernetIpCallback = std::function<void(esp_ip4_addr_t ip)>

Callback invoked when the interface obtains an IPv4 address.

Note

Runs in the ESP-IDF event-loop task context — return quickly, do not block.

using Pixel = lv_color16_t

Alias for the pixel type used by the display.

using DisplayDriver = espp::display_drivers::Controller

Alias for the low-level display driver interface.

using TouchDriver = espp::Gt911

Alias for the GT911 touch controller.

using TouchpadData = espp::TouchpadData

Alias for the touchpad data.

using touch_callback_t = std::function<void(const TouchpadData&)>

Alias for the touch callback when touch events are received.

using microphone_callback_t = std::function<void(const uint8_t *data, size_t num_bytes)>

Alias for the microphone callback, called with recorded audio data.

using camera_frame_callback_t = std::function<void(const uint8_t *data, int width, int height, size_t length)>

Alias for the camera frame callback. Called from the camera task with each captured frame: data is the pixel buffer (RGB565, width x height), valid only for the duration of the callback, and length is its size in bytes. Copy the data if it needs to outlive the call.

Public Functions

inline I2c &internal_i2c()

Get a reference to the internal I2C bus

Note

Shared by the ES8311 audio codec, the GT911 touch controller, and (on this pinout) the camera SCCB

Returns:

A reference to the internal I2C bus

inline espp::Interrupt &interrupts()

Get a reference to the interrupts

Returns:

A reference to the interrupts

inline DisplayController get_display_controller() const

Get the display controller type for the configured panel

Returns:

The display controller type

inline const char *get_display_controller_name() const

Get a string name for the configured display controller

Returns:

String name of the controller

bool initialize_lcd()

Initialize the LCD (MIPI-DSI + configured panel driver)

Returns:

true if the LCD was successfully initialized, false otherwise

bool initialize_display(size_t pixel_buffer_size = 0)

Initialize the LVGL display

Parameters:

pixel_buffer_size – The size of the pixel buffer, in pixels. If 0, a default based on the configured panel width is used.

Returns:

true if the display was successfully initialized, false otherwise

bool initialize_touch(const touch_callback_t &callback = nullptr, gpio_num_t interrupt_pin = touch_interrupt_default)

Initialize the GT911 multi-touch controller

Note

On the ESP32-P4-ETH the GT911 reset and INT pins are not routed to the ESP32-P4, so touch is polled by default.

Parameters:
  • callback – The touchpad callback

  • interrupt_pin – GPIO wired to the GT911 touch INT pin. If GPIO_NUM_NC (the default), the GT911 is polled in a task. If a valid GPIO is provided, touch is read from a GPIO interrupt on that pin instead.

Returns:

true if the touchpad was successfully initialized, false otherwise

inline size_t bytes_per_pixel() const

Get the number of bytes per pixel for the display

Returns:

The number of bytes per pixel

inline std::shared_ptr<TouchpadInput> touchpad_input() const

Get the touchpad input

Returns:

A shared pointer to the touchpad input

inline TouchpadData touchpad_data() const

Get the most recent touchpad data

Returns:

The touchpad data

void touchpad_read(uint8_t *num_touch_points, uint16_t *x, uint16_t *y, uint8_t *btn_state)

Get the touchpad data for LVGL integration

Parameters:
  • num_touch_points – The number of touch points

  • x – The x coordinate

  • y – The y coordinate

  • btn_state – The button state (0 = released, 1 = pressed)

TouchpadData touchpad_convert(const TouchpadData &data) const

Convert touchpad data from raw reading to display coordinates

Parameters:

data – The touchpad data to convert

Returns:

The converted touchpad data

void brightness(float brightness)

Set the display brightness

Note

The ESP32-P4-ETH has no backlight GPIO. On the 10.1” JD9365 panel the backlight is driven by an on-board I2C controller (addr 0x45) and this call writes it; on other panels the value is stored but not applied to hardware (see the source for details).

Parameters:

brightness – The brightness as a percentage (0-100)

float brightness() const

Get the display brightness

Returns:

The brightness as a percentage (0-100)

inline size_t display_width() const

Get the display width in pixels (of the configured panel)

Returns:

The display width in pixels

inline size_t display_height() const

Get the display height in pixels (of the configured panel)

Returns:

The display height in pixels

size_t rotated_display_width() const

Get the display width in pixels, according to the current orientation.

size_t rotated_display_height() const

Get the display height in pixels, according to the current orientation.

inline const std::shared_ptr<DisplayDriver> &display_driver() const

Get a shared pointer to the low-level display driver

Returns:

A shared pointer to the display driver

void write_lcd_lines(int xs, int ys, int xe, int ye, const uint8_t *data, uint32_t user_data)

Write lines to the LCD

Note

This method queues the panel transfer asynchronously.

bool initialize_ethernet(const EthernetConfig &config)

Initialize the Ethernet interface (EMAC + IP101GRI RMII PHY).

Parameters:

configEthernet configuration (DHCP mode, callbacks). All fields have defaults, so EthernetConfig{} gives a plain DHCP client.

Returns:

True if Ethernet was successfully initialized and started.

bool initialize_ethernet()

Initialize Ethernet with default configuration (DHCP client).

Returns:

True if Ethernet was successfully initialized and started.

inline bool is_ethernet_connected() const
Returns:

True if the interface is connected with a valid IP.

inline esp_ip4_addr_t ethernet_ip() const
Returns:

The most recently acquired IPv4 address (0 if none).

bool initialize_audio (uint32_t sample_rate=48000, const espp::Task::BaseConfig &task_config={.name="p4_eth_audio",.stack_size_bytes=8192,.priority=20,.core_id=0})

Initialize the audio system (ES8311 codec)

Parameters:
  • sample_rate – The audio sample rate in Hz (default 48kHz)

  • task_config – The task configuration for the audio task

Returns:

true if the audio system was successfully initialized

void set_speaker_enabled(bool enable)

Enable or disable the speaker amplifier (NS4150B PA on GPIO53)

Parameters:

enable – True to enable the amplifier, false to disable

void volume(float volume)

Set the audio volume

Parameters:

volume – The volume as a percentage (0-100)

float volume() const

Get the audio volume

Returns:

The volume as a percentage (0-100)

void mute(bool mute)

Mute or unmute the audio

Parameters:

mute – True to mute, false to unmute

bool is_muted() const

Check if audio is muted

Returns:

True if muted, false otherwise

uint32_t audio_sample_rate() const

Get the audio sample rate

Returns:

The audio sample rate, in Hz

void audio_sample_rate(uint32_t sample_rate)

Set the audio sample rate

Parameters:

sample_rate – The audio sample rate, in Hz

size_t audio_buffer_size() const

Get the audio buffer size, in bytes

Returns:

The audio buffer size, in bytes

size_t play_audio(const uint8_t *data, uint32_t num_bytes)

Play audio data

Note

This function is non-blocking and queues the data for the audio task to play; to stream data larger than the internal buffer, call it repeatedly, advancing by the returned number of bytes

Note

Must be called from task context, not from an ISR.

Parameters:
  • data – The audio data to play (16-bit signed mono samples)

  • num_bytes – The number of bytes to play

Returns:

The number of bytes actually queued (may be less than num_bytes if the internal stream buffer is full)

size_t play_audio(std::span<const uint8_t> data)

Play audio data

Note

This function is non-blocking and queues the data for the audio task to play; to stream data larger than the internal buffer, call it repeatedly, advancing by the returned number of bytes

Note

Must be called from task context, not from an ISR.

Parameters:

data – The audio data to play (16-bit signed mono samples)

Returns:

The number of bytes actually queued (may be less than the data size if the internal stream buffer is full)

void clear_audio()

Drop any queued (not yet played) audio so a subsequent play_audio() starts immediately instead of waiting behind previously queued sound. Useful for UI sounds where a new event should restart the sound for maximum responsiveness.

bool initialize_microphone (const microphone_callback_t &callback, const espp::Task::BaseConfig &task_config={.name="microphone",.stack_size_bytes=4096,.priority=10,.core_id=1})

Initialize the microphone (the onboard analog microphone through the ES8311 codec’s ADC) and start delivering audio data to the provided callback

Note

The audio subsystem must be initialized first (the ES8311 is a full-duplex codec on a single I2S bus, so the microphone records at the speaker’s sample rate)

Note

The callback runs in the microphone task’s context, so the task’s stack must be large enough for whatever the callback does with the audio data

Parameters:
  • callback – The callback to call with recorded audio data (16-bit signed mono samples at audio_sample_rate())

  • task_config – The configuration for the microphone task

Returns:

true if the microphone was successfully initialized, false otherwise

void microphone_volume(float volume)

Set the microphone volume

Parameters:

volume – The volume as a percentage (0 - 100), mapped onto the ES8311 analog microphone gain range (0 dB - +42 dB)

float microphone_volume() const

Get the microphone volume

Returns:

The microphone volume as a percentage (0 - 100)

bool initialize_camera (const camera_frame_callback_t &callback, const espp::Task::BaseConfig &task_config={.name="p4_eth_camera",.stack_size_bytes=6144,.priority=5,.core_id=0})

Initialize the on-board MIPI-CSI camera and start streaming frames.

Brings up the ESP32-P4 camera pipeline (MIPI-CSI receiver + ISP + sensor) through esp_video (V4L2) and starts a task that delivers each captured RGB565 frame to callback. The camera sensor’s SCCB shares the internal I2C bus (SDA=7/SCL=8), so no second I2C master is created on those pins.

Note

The camera reset / power-down lines are not routed to the ESP32-P4 on this board (RPi-style CSI connector); the sensor free-runs (esp_video handles CSI/ISP/LDO). Unlike the M5Stack Tab5 there is no IO expander to pulse the camera reset. The callback runs in the camera task’s context.

Parameters:
  • callback – Function called from the camera task with each RGB565 frame (see camera_frame_callback_t). Keep it quick and non-blocking.

  • task_config – The configuration for the camera task

Returns:

true if the camera was successfully initialized and streaming

void stop_camera()

Stop the camera stream and release the camera pipeline.

uint16_t camera_width() const

Get the width of the captured camera frames, in pixels

Returns:

The camera frame width (0 if the camera is not initialized)

uint16_t camera_height() const

Get the height of the captured camera frames, in pixels

Returns:

The camera frame height (0 if the camera is not initialized)

bool initialize_sdcard(const SdCardConfig &config)

Initialize the microSD / TF card (4-bit SDMMC, powered by the on-chip LDO).

Parameters:

config – Configuration for the uSD card.

Returns:

True if the card was successfully mounted at mount_point.

inline bool is_sd_card_available() const
Returns:

True if the SD card is present and mounted.

inline sdmmc_card_t *sdcard() const
Returns:

The SDMMC card handle, or nullptr if not initialized.

bool get_sd_card_info(uint32_t *size_mb, uint32_t *free_mb) const

Get total/free space of the mounted card.

Parameters:
  • size_mb – Optional out: total size in MB.

  • free_mb – Optional out: free space in MB.

Returns:

True if the info was retrieved.

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns:

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters:

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns:

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters:

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters:

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns:

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters:

rate_limit – The rate limit to use for the logger

Public Static Functions

static inline Esp32P4Eth &get()

Access the singleton instance.

Public Static Attributes

static constexpr gpio_num_t touch_interrupt_default = GPIO_NUM_NC

Default touch INT GPIO used by initialize_touch(). GPIO_NUM_NC means the GT911 is polled; if interrupt-driven touch is enabled via Kconfig this is the configured GPIO (CONFIG_ESP32_P4_ETH_TOUCH_INTERRUPT_GPIO).

static constexpr char mount_point[] = "/sdcard"

Mount point for the uSD card filesystem.

struct EthernetConfig

Configuration for the Ethernet interface.

Public Members

DhcpMode mode = {DhcpMode::CLIENT}

DHCP operating mode.

ServerConfig server_config = {}

Only used when mode == SERVER.

Physical link came up.

Physical link went down.

EthernetIpCallback on_got_ip = {nullptr}

Interface obtained an IPv4 address.

EthernetLinkCallback on_lost_ip = {nullptr}

Interface lost its IPv4 address.

struct SdCardConfig

Configuration for the uSD card.

Public Members

bool format_if_mount_failed = false

Format the card if the mount fails.

int max_files = 5

Maximum number of open files.

size_t allocation_unit_size = 2 * 1024

FAT allocation unit size in bytes.

struct ServerConfig

Static IP configuration used when operating as a DHCP server. Leave ip_info zero-initialised to use the built-in defaults (192.168.4.1 / 255.255.255.0 / gw 192.168.4.1).

Public Members

esp_netif_ip_info_t ip_info = {}

zero-initialised → 192.168.4.1/24

client_ip_callback_t on_client_assigned = {nullptr}

Called for each assigned client IP.