mirror of
https://github.com/esphome/esphome.git
synced 2026-10-01 00:40:21 +00:00
[ethernet] Move received frames to PSRAM on SPI ethernet chips (#19377)
This commit is contained in:
@@ -10,6 +10,9 @@
|
||||
#include <lwip/dns.h>
|
||||
#include <cinttypes>
|
||||
#include "esp_event.h"
|
||||
#ifdef USE_PSRAM
|
||||
#include <esp_psram.h>
|
||||
#endif
|
||||
|
||||
// IDF 6.0 moved per-chip PHY/MAC drivers to the Espressif Component Registry;
|
||||
// they are no longer included via esp_eth.h and need explicit includes.
|
||||
@@ -71,6 +74,32 @@ static const char *const TAG = "ethernet";
|
||||
// PHY register size for hex logging
|
||||
static constexpr size_t PHY_REG_SIZE = 2;
|
||||
|
||||
// Dual wifi + ethernet SPI builds: the one place internal RAM is short and lwip's other buffers are
|
||||
// already in PSRAM. Not with L2 TAP, whose filter lives in the glue's input path this replaces.
|
||||
#if defined(USE_PSRAM) && defined(USE_ETHERNET_SPI) && defined(USE_WIFI) && !defined(CONFIG_ESP_NETIF_L2_TAP)
|
||||
#define USE_ETHERNET_RX_PSRAM
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - reported by dump_config()
|
||||
static bool rx_psram_installed = false;
|
||||
|
||||
// ESP-IDF ethernet drivers malloc() every received frame in internal RAM, where it stays until lwIP
|
||||
// hands it to the application. Move it to PSRAM; if that fails the frame is passed on where it is.
|
||||
static esp_err_t eth_input_to_psram(esp_eth_handle_t handle, uint8_t *buffer, uint32_t length, void *priv) {
|
||||
auto *copy = static_cast<uint8_t *>(heap_caps_malloc(length, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
|
||||
if (copy != nullptr) {
|
||||
memcpy(copy, buffer, length);
|
||||
free(buffer); // NOLINT(cppcoreguidelines-no-malloc) - allocated by the driver with malloc()
|
||||
buffer = copy;
|
||||
} else {
|
||||
static bool warned = false; // once, this runs per frame in the driver's task
|
||||
if (!warned) {
|
||||
warned = true;
|
||||
ESP_LOGW(TAG, "PSRAM allocation failed, frame kept in internal RAM (reported once)");
|
||||
}
|
||||
}
|
||||
return esp_netif_receive(static_cast<esp_netif_t *>(priv), buffer, length, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
void EthernetComponent::log_error_and_mark_failed_(esp_err_t err, const char *message) {
|
||||
ESP_LOGE(TAG, "%s: (%d) %s", message, err, esp_err_to_name(err));
|
||||
this->mark_failed();
|
||||
@@ -453,6 +482,16 @@ void EthernetComponent::ethernet_lazy_init_() {
|
||||
/* attach Ethernet driver to TCP/IP stack */
|
||||
err = esp_netif_attach(this->eth_netif_, esp_eth_new_netif_glue(this->eth_handle_));
|
||||
ESPHL_ERROR_CHECK(err, "ETH netif attach error");
|
||||
#ifdef USE_ETHERNET_RX_PSRAM
|
||||
// The glue frees every receive buffer with free(), so the replacement buffer must come from the heap
|
||||
if (esp_psram_is_initialized()) {
|
||||
err = esp_eth_update_input_path(this->eth_handle_, eth_input_to_psram, this->eth_netif_);
|
||||
rx_psram_installed = err == ESP_OK;
|
||||
if (!rx_psram_installed) {
|
||||
ESP_LOGW(TAG, "PSRAM RX path not installed: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Register user defined event handers
|
||||
err = esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &EthernetComponent::eth_event_handler, nullptr);
|
||||
@@ -630,6 +669,13 @@ void EthernetComponent::dump_config() {
|
||||
this->clk_pin_, this->mdc_pin_, this->mdio_pin_, this->phy_addr_);
|
||||
#endif
|
||||
ESP_LOGCONFIG(TAG, " Type: %s", eth_type);
|
||||
#ifdef USE_ETHERNET_RX_PSRAM
|
||||
// Only known once the driver is up; with enable_on_boot: false that is after this dump
|
||||
if (this->ethernet_initialized_) {
|
||||
ESP_LOGCONFIG(TAG, " RX frames: %s",
|
||||
rx_psram_installed ? LOG_STR_LITERAL("PSRAM") : LOG_STR_LITERAL("internal RAM"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
network::IPAddresses EthernetComponent::get_ip_addresses() {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# W5500 next to wifi with PSRAM: compiles the input path that moves received frames to PSRAM
|
||||
packages:
|
||||
ethernet: !include common-w5500.yaml
|
||||
|
||||
psram:
|
||||
mode: quad
|
||||
|
||||
wifi:
|
||||
ssid: MySSID
|
||||
password: password1
|
||||
|
||||
network:
|
||||
priority:
|
||||
- ethernet
|
||||
- wifi
|
||||
Reference in New Issue
Block a user