enc28j60: no mem for receive buffer

alitergee
Posts: 14
Joined: Wed Aug 17, 2022 1:31 pm

enc28j60: no mem for receive buffer

Postby alitergee » Tue Jul 18, 2023 6:33 am

I am using esp-idf 4.4.4 version and I have used the component files of enc28j60 from the example of same version and updated version as well but still getting this error E (15177429) enc28j60: no mem for receive buffer after 1 or 2 days.

This is my ethernet.c

Code: Select all

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "driver/gpio.h"
#include "nvs_flash.h"
#include "esp_log.h"

#include "esp_netif.h"
#include "esp_eth.h"
#include "esp_eth_phy.h" //v6
#include "esp_event.h"

#include "./include/ethernet.h"
#include "./include/io.h"
#include "./include/nvs_read_write.h"
#include "./include/rtc.h"
#include "./include/mqtt.h"

#define TAG "ETHERNET"

//++ MODES
#define STATIC 0
#define DHCP 1

// Default Values
#define MODE DHCP

#define STATIC_IP "192.168.0.111" // v6
#define STATIC_GW "192.168.0.1"   // v6
#define STATIC_SN "255.255.255.0" // v6
#define STATIC_DNS1 "8.8.8.8"     // v6
#define STATIC_DNS2 "8.8.2.2"     // v6

extern bool mqtt_connected;

extern char mac_id[18]; //++ TO GET THE DEVICE MAC ID //v6
bool eth_con_flag = false;
// esp_netif_t *eth_netif;

static EventGroupHandle_t ethernet_events;
static const int CONNECTED_GOT_IP = BIT0;
static const int DISCONNECTED = BIT1;

char ethernet_dynamic_ip[20]; //++ to store ethernet ip when network is in dynamin mode

void eth_credential_read_nvs()
{
    memset(ethernet_dynamic_ip, 0, sizeof(ethernet_dynamic_ip));
    strcpy(ethernet_dynamic_ip, "-");
    eth_configure.nvs_eth_dhcp = read_nvs_u8("network_page", "dhcp", MODE);

    if (eth_configure.nvs_eth_dhcp == STATIC)
    {
        eth_configure.nvs_eth_ip = read_nvs_str("network_page", "static_ip", STATIC_IP);
        eth_configure.nvs_eth_gw = read_nvs_str("network_page", "static_gw", STATIC_GW);
        eth_configure.nvs_eth_snt = read_nvs_str("network_page", "static_snt", STATIC_SN);
        eth_configure.nvs_eth_dns1 = read_nvs_str("network_page", "static_dns1", STATIC_DNS1);
        eth_configure.nvs_eth_dns2 = read_nvs_str("network_page", "static_dns2", STATIC_DNS2);
    }
    vTaskDelay(50 / portTICK_PERIOD_MS);
}

static esp_err_t example_set_dns_server(esp_netif_t *netif, uint32_t addr, esp_netif_dns_type_t type)
{
    if (addr && (addr != IPADDR_NONE))
    {
        esp_netif_dns_info_t dns;
        dns.ip.u_addr.ip4.addr = addr;
        dns.ip.type = IPADDR_TYPE_V4;
        esp_netif_set_dns_info(netif, type, &dns);
    }
    return ESP_OK;
}

static void ethernet_set_static_ip(esp_netif_t *netif)
{
    if (esp_netif_dhcpc_stop(netif) != ESP_OK)
    {
        ESP_LOGE(TAG, "Failed to stop dhcp client");
        return;
    }
    esp_netif_ip_info_t ip;
    memset(&ip, 0, sizeof(esp_netif_ip_info_t));
    ip.ip.addr = ipaddr_addr(eth_configure.nvs_eth_ip);
    ip.netmask.addr = ipaddr_addr(eth_configure.nvs_eth_snt);
    ip.gw.addr = ipaddr_addr(eth_configure.nvs_eth_gw);
    if (esp_netif_set_ip_info(netif, &ip) != ESP_OK)
    {
        ESP_LOGE(TAG, "Failed to set ip info");
        return;
    }
    ESP_ERROR_CHECK(example_set_dns_server(netif, ipaddr_addr(eth_configure.nvs_eth_dns1), ESP_NETIF_DNS_MAIN));
    ESP_ERROR_CHECK(example_set_dns_server(netif, ipaddr_addr(eth_configure.nvs_eth_dns2), ESP_NETIF_DNS_BACKUP));
}

/** Event handler for Ethernet events */
void event_handler_for_ethernet(void *arg, esp_event_base_t event_base,
                                int32_t event_id, void *event_data)
{
    uint8_t mac_addr[6] = {0};
    /* we can get the ethernet driver handle from event data */
    esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;

    switch (event_id)
    {
    case ETHERNET_EVENT_CONNECTED:
        esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
        ESP_LOGI(TAG, "Ethernet Link Up");
        ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",
                 mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);

        if (eth_configure.nvs_eth_dhcp == STATIC)
            ethernet_set_static_ip(arg); // v6
        break;
    case ETHERNET_EVENT_DISCONNECTED:
        ESP_LOGE(TAG, "Ethernet Link Down");
        eth_con_flag = false;
        xEventGroupSetBits(ethernet_events, DISCONNECTED);

        if (mqtt_connected == true)
        {
            mqtt_app_stop();
            mqtt_connected = false;
        }
        break;
    case ETHERNET_EVENT_START:
        ESP_LOGI(TAG, "Ethernet Started");
        break;
    case ETHERNET_EVENT_STOP:
        ESP_LOGI(TAG, "Ethernet Stopped");
        break;
    case IP_EVENT_ETH_GOT_IP:
        eth_con_flag = true;
        eth_conn_count++;

        ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
        const esp_netif_ip_info_t *ip_info = &event->ip_info;

        // esp_netif_dns_info_t dns1, dns2;
        // esp_netif_get_dns_info(eth_netif, ESP_NETIF_DNS_MAIN, &dns1);
        // esp_netif_get_dns_info(eth_netif, ESP_NETIF_DNS_BACKUP, &dns2);

        ESP_LOGI(TAG, "\n\nxx -- ETHERNET CONNECTED -- xx\n");
        ESP_LOGI(TAG, "ethernet connection count: %d", eth_conn_count);
        ESP_LOGI(TAG, "IP :" IPSTR, IP2STR(&ip_info->ip));
        ESP_LOGI(TAG, "GATEWAY :" IPSTR, IP2STR(&ip_info->gw));
        ESP_LOGI(TAG, "SUBNET :" IPSTR, IP2STR(&ip_info->netmask));

        memset(ethernet_dynamic_ip, 0, sizeof(ethernet_dynamic_ip));
        memset(eth_gw, 0, sizeof(eth_gw));
        memset(eth_snt, 0, sizeof(eth_snt));
        memset(eth_dns, 0, sizeof(eth_dns));

        sprintf(ethernet_dynamic_ip, "" IPSTR, IP2STR(&ip_info->ip));
        sprintf(eth_gw, "" IPSTR, IP2STR(&ip_info->gw));
        sprintf(eth_snt, "" IPSTR, IP2STR(&ip_info->netmask));
        // sprintf(eth_dns, "" IPSTR, IP2STR(&dns1.ip.u_addr.ip4));

        eth_configure.nvs_eth_ip = ethernet_dynamic_ip;
        eth_configure.nvs_eth_gw = eth_gw;
        eth_configure.nvs_eth_snt = eth_snt;
        eth_configure.nvs_eth_dns1 = eth_dns;
        memset(eth_dns, 0, sizeof(eth_dns));
        // sprintf(eth_dns, "" IPSTR, IP2STR(&dns2.ip.u_addr.ip4));
        eth_configure.nvs_eth_dns2 = eth_dns;

        if (eth_configure.nvs_eth_dhcp == STATIC)
        {
            // ESP_LOGI(TAG, "DNS1 :" IPSTR, IP2STR(&dns1.ip.u_addr.ip4));
            // ESP_LOGI(TAG, "DNS2 :" IPSTR, IP2STR(&dns2.ip.u_addr.ip4));
            ESP_LOGI(TAG, "MODE : STATIC");
        }
        else
        {
            ESP_LOGI(TAG, "MODE : DHCP");
        }
        ESP_LOGI(TAG, "\n\nxx -- ETHERNET CONNECTED -- xx\n");

        vTaskDelay(50 / portTICK_PERIOD_MS);

        get_sntp_time();
        mqtt_app_start(mac_id);

        xEventGroupSetBits(ethernet_events, CONNECTED_GOT_IP);
        break;
    default:
        break;
    }
}

void ethernet_init(uint8_t mac_addr[])
{
    ESP_LOGI(TAG, "\n\nxx -- INITIALISING ETHERNET -- xx\n");

    eth_credential_read_nvs();

    ethernet_events = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());
    // Create default event loop that running in background
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
    esp_netif_t *eth_netif = esp_netif_new(&netif_cfg);

    spi_bus_config_t buscfg = {
        .miso_io_num = ETH_SPI_MISO,
        .mosi_io_num = ETH_SPI_MOSI,
        .sclk_io_num = ETH_SPI_SCK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
    };
    ESP_ERROR_CHECK(spi_bus_initialize(ETH_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
    /* ENC28J60 ethernet driver is based on spi driver */
    spi_device_interface_config_t devcfg = {
        .command_bits = 3,
        .address_bits = 5,
        .mode = 0,
        .clock_speed_hz = ETH_SPI_CLOCK_MHZ * 1000 * 1000,
        .spics_io_num = 5,
        .queue_size = 20,
        .cs_ena_posttrans = enc28j60_cal_spi_cs_hold_time(ETH_SPI_CLOCK_MHZ),
    };

    spi_device_handle_t spi_handle = NULL;
    ESP_ERROR_CHECK(spi_bus_add_device(ETH_SPI_HOST, &devcfg, &spi_handle));

    eth_enc28j60_config_t enc28j60_config = ETH_ENC28J60_DEFAULT_CONFIG(spi_handle);
    enc28j60_config.int_gpio_num = ETH_INT_GPIO;

    eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
    mac_config.smi_mdc_gpio_num = -1; // ENC28J60 doesn't have SMI interface
    mac_config.smi_mdio_gpio_num = -1;
    esp_eth_mac_t *mac = esp_eth_mac_new_enc28j60(&enc28j60_config, &mac_config);

    eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
    phy_config.autonego_timeout_ms = 0; // ENC28J60 doesn't support auto-negotiation
    phy_config.reset_gpio_num = -1;     // ENC28J60 doesn't have a pin to reset internal PHY
    esp_eth_phy_t *phy = esp_eth_phy_new_enc28j60(&phy_config);

    esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
    esp_eth_handle_t eth_handle = NULL;
    ESP_ERROR_CHECK(esp_eth_driver_install(&eth_config, &eth_handle));

    /* ENC28J60 doesn't burn any factory MAC address, we need to set it manually.
       02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control.
    */
    mac->set_addr(mac, (uint8_t[]){
                           base_mac_addr[0], base_mac_addr[1], base_mac_addr[2], base_mac_addr[3], base_mac_addr[4], base_mac_addr[5]});

    // ENC28J60 Errata #1 check
    if (emac_enc28j60_get_chip_info(mac) < ENC28J60_REV_B5 && 8 < 8)
    {
        ESP_LOGE(TAG, "SPI frequency must be at least 8 MHz for chip revision less than 5");
        ESP_ERROR_CHECK(ESP_FAIL);
    }

    /* attach Ethernet driver to TCP/IP stack */
    ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)));
    // Register user defined event handers
    ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &event_handler_for_ethernet, eth_netif));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &event_handler_for_ethernet, eth_netif));
    /* start Ethernet driver state machine */
    ESP_ERROR_CHECK(esp_eth_start(eth_handle));

    /* Set duplex needs to be called after esp_eth_start since the driver is started with auto-negotiation by default */
    esp_err_t duplex_mode_status = enc28j60_set_phy_duplex(phy, ETH_DUPLEX_FULL);
    if (duplex_mode_status == ESP_OK)
    {
        ESP_LOGI(TAG, "[ ETHERNET TRANSMISSION MODE SET TO FULL DUPLEX ]");
    }

    xEventGroupWaitBits(ethernet_events, CONNECTED_GOT_IP | DISCONNECTED, pdTRUE, pdFALSE, pdMS_TO_TICKS(10000));

    esp_netif_dhcp_status_t status;
    esp_netif_dhcpc_get_status(eth_netif, &status);
    ESP_LOGW(TAG, " DHCPC  (state=%u)", status);
    if (status == 0x0)
    {
        // esp_err_t err_dhcp = esp_netif_dhcpc_start(eth_netif); // commented
        ESP_LOGI(TAG, "DHCP client status : %s", esp_err_to_name(status));
        ESP_LOGI(TAG, "[ Restarting ESP32 ]");
        esp_restart();
    }
}
I have used the esp_eth_phy_enc28j60.c and esp_eth_mac_enc28j60.c from the examples.

Any advice will be appreciated.

ESP_ondrej
Posts: 181
Joined: Fri May 07, 2021 10:35 am

Re: enc28j60: no mem for receive buffer

Postby ESP_ondrej » Tue Jul 18, 2023 7:34 am

Do you implemented some custom application or you just run the Ethernet? If you have your application, please check that you properly handle memory, i.e. you free heap when you no more need it.

alitergee
Posts: 14
Joined: Wed Aug 17, 2022 1:31 pm

Re: enc28j60: no mem for receive buffer

Postby alitergee » Wed Jul 19, 2023 6:56 am

Hi,

Ethernet is a part of my custom application which has multiple tasks.
When free heap is printed at multiple places in the code, plenty of free heap is observed (never less than 60KB).

ESP_ondrej
Posts: 181
Joined: Fri May 07, 2021 10:35 am

Re: enc28j60: no mem for receive buffer

Postby ESP_ondrej » Wed Jul 19, 2023 9:14 am

You did't mention what chip you use so I don't know if it is PSRAM capable and if you use the PSRAM or not. The thing is the driver allocates memory in DMA capable area which is internal memory. So you can have enough heap in overall but may not have enough in DMA capable area.

It may happen that your application allocates a lot of memory at certain point in time and then you get this error. Is it persistent or not once it happens?

alitergee
Posts: 14
Joined: Wed Aug 17, 2022 1:31 pm

Re: enc28j60: no mem for receive buffer

Postby alitergee » Thu Jul 20, 2023 6:31 am

Hi @ESP_ondrej thanks for replying.

The chip that I am using is ESP32 ­WROOM­ 32UE, I'm unsure whether it is capable of PSRAM or not.

I've run two test cases for v long period.

In 1st case I am running the esp-idf enc28j60 example code with MQTT publishing "Hello World" in fixed intervals, and no error has been detected till now and the program is running smoothly.

2nd case is I am running my custom application having MQTT, Analog Inputs, UART, etc., and the
no mem for receive buffer
is observed after approximately 4 hours and the error is continuously observed until ESP32 is not Restarted.

Please refer to the serial logs from 2nd test case:

First occurrence of the error
--xx MESSAGE PUBLISHED xx--

I (15746329) MQTT: MQTT_EVENT_PUBLISHED, msg_id : 21987
I (15746339) IO: Total_MODBUS_posted: 820952
I (15750279) IO: Average Voltage DI1: 3134.000000 mV
I (15750279) IO: r_ntc 188795.252309
I (15750279) IO: Celcius -29.1
W (15750279) NVS: USING DEFAULT [ dhcp_cnt ]: 0 | (ESP_ERR_NVS_NOT_FOUND)
I (15750289) IO:
{JSON}
I (15750309) IO: MODBUS_posted size: 209
I (15750309) MQTT:

--xx MESSAGE PUBLISHED xx--
E(15750319) enc28j60: no mem for receive buffer

I (15750319) IO: Total_MODBUS_posted: 821161
E (15751329) enc28j60: no mem for receive buffer
E (15752329) enc28j60: no mem for receive buffer
E (15753329) enc28j60: no mem for receive buffer
I (15754279) IO: Average Voltage DI1: 3134.000000 mV
I (15754279) IO: r_ntc 188795.252309
I (15754279) IO: Celcius -29.1
W (15754279) NVS: USING DEFAULT [ dhcp_cnt ]: 0 | (ESP_ERR_NVS_NOT_FOUND)
I (15754289) IO:
{JSON}
I (15754309) IO: MODBUS_posted size: 209
I (15754309) IO: Total_MODBUS_posted: 821370
E (15754329) enc28j60: no mem for receive buffer
E (15755329) enc28j60: no mem for receive buffer
E (15756329) enc28j60: no mem for receive buffer
E (15757329) enc28j60: no mem for receive buffer
I (15758279) IO: Average Voltage DI1: 3134.000000 mV
I (15758279) IO: r_ntc 188795.252309
I (15758279) IO: Celcius -29.1
W (15758279) NVS: USING DEFAULT [ dhcp_cnt ]: 0 | (ESP_ERR_NVS_NOT_FOUND)
I (15758289) IO:
{JSON}
I (15758309) IO: MODBUS_posted size: 209
I (15758309) IO: Total_MODBUS_posted: 821579
E (15758329) enc28j60: no mem for receive buffer
E (15759329) enc28j60: no mem for receive buffer
E (15760329) enc28j60: no mem for receive buffer
E (15761329) enc28j60: no mem for receive buffer
I (15762279) IO: Average Voltage DI1: 3134.000000 mV
I (15762279) IO: r_ntc 188795.252309
I (15762279) IO: Celcius -29.1
I (15762289) IO:
{JSON}
I (15762309) IO: MODBUS_posted size: 209
I (15762309) IO: Total_MODBUS_posted: 821788
E (15762329) enc28j60: no mem for receive buffer
E (15763209) TRANSPORT_BASE: tcp_write error, errno=No more processes
E (15763209) MQTT_CLIENT: Writing failed: errno=11
E (15763209) MQTT: MQTT_EVENT_ERROR
E (15763209) MQTT_CLIENT: Error to resend data
E (15763219) MQTT: MQTT_EVENT_DISCONNECTED
I (15763219) MQTT:

--xx MESSAGE PUBLISHED xx--

E (15763249) MQTT: FREE HEAP before: 336
E (15763259) MQTT: Deleting MQTT task
E (15763329) enc28j60: no mem for receive buffer
E (15763329) enc28j60: no mem for receive buffer
E (15763329) enc28j60: no mem for receive buffer
E (15763329) enc28j60: no mem for receive buffer
E (15763339) enc28j60: no mem for receive buffer
E (15763339) enc28j60: no mem for receive buffer
E (15763349) enc28j60: no mem for receive buffer
E (15763349) enc28j60: no mem for receive buffer
Before panic restart
E (24962189) enc28j60: no mem for receive buffer
E (24962189) enc28j60: no mem for receive buffer
E (24962199) enc28j60: no mem for receive buffer
E (24962199) enc28j60: no mem for receive buffer
E (24962219) enc28j60: no mem for receive buffer
E (24962219) enc28j60: no mem for receive buffer
E (24962229) enc28j60: no mem for receive buffer
E (24962229) enc28j60: no mem for receive buffer
E (24962239) enc28j60: no mem for receive buffer
E (24962239) enc28j60: no mem for receive buffer
E (24962249) enc28j60: no mem for receive buffer
E (24962249) enc28j60: no mem for receive buffer
E (24962259) enc28j60: no mem for receive buffer
E (24962259) enc28j60: no mem for receive buffer
E (24962269) enc28j60: no mem for receive buffer
E (24962279) enc28j60: no mem for receive buffer
I (24962279) IO: Average Voltage DI1: 3134.000000 mV
E (24962279) enc28j60: no mem for receive buffer
E (24962289) enc28j60: no mem for receive buffer
I (24962299) IO: Celcius -29.1
E (24962299) enc28j60: no mem for receive buffer
E (24962309) NVS: Error (ESP_ERR_NO_MEM) opening NVS handle!
E (24962309) enc28j60: no mem for receive buffer
I (24962319) IO:
{JSON}
E (24962319) enc28j60: no mem for receive buffer
I (24962339) SPIFFS:
JSON written in file =
{JSON}

I (24962339) IO: MODBUS_posted size: 209
I (24962369) SPIFFS: Opening file /spiffs/data_22.txt
E (24962359) enc28j60: no mem for receive buffer
E (24962389) enc28j60: no mem for receive buffer
I (24962389) SPIFFS: JSON written : 99

I (24962379) IO: Total_MODBUS_posted: 1302488
E (24962399) enc28j60: no mem for receive buffer
E (24962409) enc28j60: no mem for receive buffer
E (24962409) enc28j60: no mem for receive buffer
E (24962419) enc28j60: no mem for receive buffer

Switching to new file
E (24962429) enc28j60: no mem for receive buffer
E (24962429) NVS: Error (ESP_ERR_NO_MEM) opening NVS handle!

abort() was called at PC 0x40082f13 on core 0


Backtrace:0x40081c86:0x3ffc14a00x4008a7bd:0x3ffc14c0 0x40091fea:0x3ffc14e0 0x40082f13:0x3ffc1550 0x4008306a:0x3ffc1570 0x4000bde5:0x3ffc1590 0x40001ef0:0x3ffc15b0 0x4016fca7:0x3ffc15d0 0x4016fd65:0x3ffc1600 0x400ddfa4:0x3ffc1620 0x4008dac5:0x3ffc16a0




ELF file SHA256: 8d5d3fff303029d3

Rebooting...
ets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESET),boot:0x37 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2

ESP_ondrej
Posts: 181
Joined: Fri May 07, 2021 10:35 am

Re: enc28j60: no mem for receive buffer

Postby ESP_ondrej » Thu Jul 20, 2023 10:40 am

As can be seen from the logs, it's not just ENC28J60 issue. NVS is also not able to open handle due to memory: "NVS: Error (ESP_ERR_NO_MEM) opening NVS handle!"

You have to debug your application how it utilizes the heap.

alitergee
Posts: 14
Joined: Wed Aug 17, 2022 1:31 pm

Re: enc28j60: no mem for receive buffer

Postby alitergee » Thu Jul 20, 2023 10:50 am

Okay, I will look out for memory allocations in the applications.

I will let you know if I stumble somewhere.

Thank you so much.

marks_cheider
Posts: 3
Joined: Tue Aug 15, 2023 7:25 am

Re: enc28j60: no mem for receive buffer

Postby marks_cheider » Thu Feb 08, 2024 7:15 am

Hi, I hope, my experience with "no mem receive buffe" error could help you. Check your code for malloc function. Be sure that you free that heap after using it.

Who is online

Users browsing this forum: No registered users and 80 guests