The esp.emac: no mem for receive buffer error is a fatal runtime fault indicating that the ESP32's Ethernet MAC (EMAC) peripheral cannot allocate DMA-capable internal SRAM to store incoming network frames. When you see this string in your serial monitor, your wired network interface is effectively dead. In a real circuit or installation, this error changes your system from a reliable wired node into a deaf endpoint: it halts all incoming TCP/MQTT traffic, drops active socket connections, and frequently triggers a Task Watchdog Timer (TWDT) panic that freezes the entire microcontroller until a hardware reset.
What people commonly confuse it with are general Wi-Fi stack memory leaks (which throw wifi: no mem), external PSRAM allocation failures, or physical PHY layer link drops (which cause CRC errors, not DMA panics). This error is strictly tied to the 520 KB of usable internal SRAM on the standard ESP32, which is the only memory space the Ethernet DMA controller can access.
The Anatomy of the EMAC Receive Buffer Failure
To understand why this happens, you have to look at how the ESP32 handles wired Ethernet. Unlike Wi-Fi, which is managed by a separate coprocessor, the Ethernet MAC is a peripheral directly on the main die. It relies on Direct Memory Access (DMA) to move packets from the RMII interface into memory without waking the CPU for every byte.
A Worked Numeric Example
Let's calculate the exact buffer budget using default ESP-IDF v5.1 configurations to see how quickly this memory vanishes. The Ethernet driver allocates discrete blocks for Rx (receive) and Tx (transmit) descriptors and buffers.
- Buffer Size: Standard Ethernet MTU is 1500 bytes. Adding the 14-byte header and 4-byte FCS gives 1518 bytes. ESP-IDF rounds this up to 1550 bytes for memory alignment.
- Default Rx Buffers:
CONFIG_ETH_DMA_RX_BUFFER_NUMdefaults to 10. - Default Tx Buffers:
CONFIG_ETH_DMA_TX_BUFFER_NUMdefaults to 10.
The math: (10 Rx × 1550 bytes) + (10 Tx × 1550 bytes) = 31,000 bytes (~30.2 KB) of contiguous DMA-capable SRAM required just for the baseline Ethernet driver. If your application—such as an mbedTLS handshake, a large JSON parser, or an audio buffer—fragments the internal heap, the allocator might have 40 KB of free SRAM total, but no single contiguous 1.5 KB block available. When a burst of network traffic arrives and the driver attempts to replenish or scale its Rx ring, heap_caps_malloc(1550, MALLOC_CAP_DMA) returns NULL, throwing the no mem for receive buffer panic.
Where You Meet This in Practice
You will almost exclusively encounter this error on ESP32 boards with integrated wired Ethernet, such as the Wireless-Tag WT32-ETH01, the Olimex ESP32-POE, or custom PCBs utilizing the LAN8720A or DP83848 PHY chips via the RMII interface.
Common Trigger Scenarios:
- High-Throughput MQTT over TLS: TLS handshakes and encrypted payloads consume massive amounts of internal heap. If you aren't explicitly routing your TLS buffers to PSRAM, the internal SRAM fragments, starving the EMAC.
- Concurrent Wi-Fi and Ethernet: Running Wi-Fi (for OTA updates or fallback) alongside Ethernet doubles the demand on internal DMA memory. The Wi-Fi stack alone reserves roughly 70 KB of internal SRAM.
- Memory Leaks in Task Loops: Failing to free dynamically allocated structs in your
loop()or FreeRTOS tasks slowly eats the internal heap until the EMAC cannot allocate its next Rx descriptor.
Diagnostic Matrix and Memory Fixes
Before changing code, verify your heap state. Inject this snippet into your main loop to monitor DMA-capable memory in real-time:
#include "esp_heap_caps.h"
void check_dma_heap() {
size_t free_dma = heap_caps_get_free_size(MALLOC_CAP_DMA);
size_t largest_dma_block = heap_caps_get_largest_free_block(MALLOC_CAP_DMA);
ESP_LOGI("HEAP", "DMA Free: %u bytes | Largest Contiguous Block: %u bytes", free_dma, largest_dma_block);
}
If largest_dma_block drops below 2048 bytes, your EMAC is on the verge of crashing.
| Symptom | Root Cause | Exact Fix (sdkconfig / Code) |
|---|---|---|
| Crash immediately upon Ethernet initialization | Internal heap exhausted by Wi-Fi or Bluetooth before EMAC starts. | Disable Wi-Fi/BT if unused, or initialize Ethernet before Wi-Fi in app_main(). |
| Crash during high-speed data ingress (e.g., file download) | Rx buffers depleted faster than CPU can process them; heap fragmented. | Increase CONFIG_ETH_DMA_RX_BUFFER_NUM to 20 in menuconfig. Ensure TCP task priority > EMAC task priority. |
| Random crashes after hours of uptime | Slow internal heap leak in application code (e.g., unclosed sockets, unfreed cJSON objects). | Audit code with heap_caps_monitor(). Force large allocations to PSRAM using heap_caps_malloc(size, MALLOC_CAP_SPIRAM). |
| Error only occurs when mbedTLS is active | TLS context allocating internal SRAM by default. | Enable CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC and route TLS buffers to PSRAM via custom allocators. |
For deeper architectural guidance on memory partitioning, refer to the official Espressif Memory Allocation Documentation and the ESP-IDF Ethernet API Reference.
Frequently Asked Questions
Why does esp.emac no mem for receive buffer happen even with 4MB PSRAM?
External PSRAM (SPI RAM) is connected via the SPI bus, which is too slow and architecturally incompatible with the ESP32's internal EMAC DMA controller on standard ESP32 chips (like the ESP32-WROOM-32E). The DMA hardware physically lacks the memory mapping to write incoming Ethernet frames directly into PSRAM. Even if you have 4MB or 8MB of PSRAM available, the EMAC is strictly limited to the ~520 KB of internal SRAM. If that internal space is fragmented, the error occurs regardless of external memory availability.
How do I increase the EMAC receive buffer size in ESP-IDF?
You can adjust the buffer count and size via the ESP-IDF configuration tool (idf.py menuconfig). Navigate to Component config > Ethernet. Here, you can modify CONFIG_ETH_DMA_RX_BUFFER_NUM (default 10) to a higher value like 16 or 20 to absorb traffic bursts. However, be careful: increasing this value consumes more internal SRAM. If you push it too high (e.g., >30), you will cause the exact out-of-memory error you are trying to prevent during initialization.
Can I use an ESP32-S3 to bypass the DMA internal SRAM limit?
Yes, partially. The ESP32-S3 architecture includes improvements to how DMA interacts with external memory, and it features a larger internal SRAM footprint (up to 512 KB of fast SRAM natively, plus OTG memory). However, the ESP32-S3 does not have a native internal EMAC peripheral; it relies on SPI Ethernet (like the W5500 or ENC28J60) or USB-to-Ethernet bridges. If you are using an SPI Ethernet module on an ESP32-S3, the DMA constraints are vastly different, and the esp.emac error (which is specific to the internal RMII MAC) will not appear in the same way.
Is this error caused by a faulty LAN8720A PHY chip?
No. A faulty LAN8720A PHY chip, a bad 50MHz RMII clock crystal, or incorrect TX/RX pin wiring will result in physical link failures, timeout errors, or high CRC/FCS packet drop rates. The no mem for receive buffer error occurs after the PHY has successfully received a valid frame and passed it to the MAC layer, but the MAC's software driver fails to secure RAM to store it. It is strictly a software memory management issue, not a hardware PHY fault.






