espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.52k stars 7.26k forks source link

w5500 MAC triggering an unrecoverable error. (IDFGH-13843) #14691

Open lekshith opened 4 days ago

lekshith commented 4 days ago

Answers checklist.

IDF version.

5.1v

Espressif SoC revision.

ESP-IDF v5.1.4, chip revision: v0.1

Operating System used.

Windows

How did you build your project?

VS Code IDE

If you are using Windows, please specify command line type.

None

Development Kit.

ESP32S3

Power Supply used.

USB

What is the expected behavior?

In my application, I have initialised Ethernet in a standard mode with clock speed of 30MHZ. I also use the SPIRAM. Both the application share the same bus config and hosted using SPI_HOST 2. I was previously hosting a web server along side using PSRAM, which never had any problem.

What is the actual behavior?

However, now I have disabled the web server to use ethernet over MODBUS TCP/IP stack. I use the standard freemodbus library and create a continuous polling loop to monitor the incoming packets at the port. Here is the RTOS task created:

`void modbus_tcp_task(void* pvParameters)
{
    // Modbus TCP slave handler
    memset(&mbc_slave_handler, 0, sizeof(mbc_slave_handler));

    // Initialize Modbus TCP stack
    esp_err_t err = mbc_tcp_slave_create(&mbc_slave_handler);
    if (err != ESP_OK) {
        ESP_LOGE(TAG5, "Failed to initialize Modbus TCP stack: %d", err);
        vTaskDelete(NULL);
        return;
    }

    // Set communication parameters
    mb_communication_info_t comm_info = {
        .ip_port = 502,  // Default Modbus TCP port
        .ip_addr_type = MB_IPV4,
        .ip_mode = MB_MODE_TCP,
    };

    // Start Modbus TCP stack
    err = mbc_tcp_slave_start();
    if (err != ESP_OK) {
        ESP_LOGE(TAG5, "Failed to start Modbus TCP stack: %d", err);
        vTaskDelete(NULL);
        return;
    }
    ESP_LOGI(TAG5, "Modbus TCP stack initialized and started");

    // Main loop for handling incoming Modbus TCP requests
    while (1) {
        // Check if the Modbus stack is active
        if (eMBState == STATE_ENABLED) {
            // Process requests from Modbus TCP client
            eMBErrorCode status = eMBPoll();  // Check if a request has been received
            if (status != MB_ENOERR) {
                ESP_LOGE(TAG5, "Error polling Modbus TCP: 0x%x", (int)status);
            } else {
                ESP_LOGI(TAG5, "Modbus TCP request processed successfully");
            }
        }
        vTaskDelay(pdMS_TO_TICKS(500));  // Poll every 100 ms
    }
}`

And the bus configuration for SPI initialisation:

spi_bus_config_t buscfg = {
        .miso_io_num = SPI_MISO_GPIO,
        .mosi_io_num = SPI_MOSI_GPIO,
        .sclk_io_num = SPI_SCLK_GPIO,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
    };
    ESP_ERROR_CHECK(spi_bus_initialize(ETH_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
    /* w5500 ethernet driver is based on spi driver */
    spi_device_interface_config_t spi_devcfg = {
        .mode = 0,
        .clock_speed_hz = ETH_SPI_CLOCK_MHZ * 1000 * 1000,
        .spics_io_num = ETH_SPI_CS_GPIO,
        .queue_size = 20,
        .cs_ena_posttrans = 2,
    };

Steps to reproduce.

The task mostly uses the standard library function and works as expected. polling interval is 500ms. Ethernet is currently just hosting the TCP stack, while the webserver is disabled. PSRAM is used. However, it keeps triggering a unrecoverable error at random times (usually after 30 mins of runtime), Debug logs are shown below:

Debug Logs.

E (4158012) w5500.mac: w5500_spi_read(163): spi transmit failed
E (4158012) w5500.mac: w5500_read_buffer(276): read RX buffer failed
E (4158012) w5500.mac: emac_w5500_receive(680): read payload failed, len=60, offset=65529
E (4158022) w5500.mac: frame read from module failed
I (4158062) adc_api: Multisource Control Mode. Fans are controlled via Modbus/BMS, Webserver, and 0-10V 1 : 0.000000
I (4158122) adc_api: Fan Speed: 6553/65535, 10.00%
I (4159292) adc_api: Multisource Control Mode. Fans are controlled via Modbus/BMS, Webserver, and 0-10V 1 : 0.000000
I (4159352) adc_api: Fan Speed: 6553/65535, 10.00%
E (4159552) w5500.mac: w5500_spi_write(139): spi transmit failed
E (4159552) w5500.mac: w5500_write_buffer(253): write TX buffer failed
E (4159552) w5500.mac: emac_w5500_transmit(582): write frame failed
I (4160502) adc_api: Multisource Control Mode. Fans are controlled via Modbus/BMS, Webserver, and 0-10V 1 : 0.000000
I (4160562) adc_api: Fan Speed: 6553/65535, 10.00%

More Information.

I have tried initialising different clock speed for the ethernet. A similar error was specified as bug in this issue https://github.com/espressif/esp-idf/issues/11845 and has been fixed for ESP-IDF 5.0v and above, but I'm still facing this issue. Either way, I still integrated the commit shown, didn't help the issue. Any suggestions are welcome. Thanks.

lekshith commented 2 days ago

Chipset: ESP32S3 IDF version: v5.1.4 SPI uses the spi_device_polling_transmit in all cases from the ESP-IDF v5..1.4 Custom PCB with U12-W5500 module and ethernet port placed less than 2 cm away from the chip. Ethernet initialisation is the basic initialisation example. I've been using the same ethernet port to host a local web server which works without any issue. Now I have disabled the web server and integrated a new feature i.e., MODBUS poll over TCP/IP stack for which I'm using the freemodbus library. Please have a look at the ethernet initialisation function.

`void init_ethernet(void)
{
    esp_netif_config_t netif_cfg_DHCP_client = ESP_NETIF_DEFAULT_ETH();
    esp_netif_t *eth_netif = esp_netif_new(&netif_cfg_DHCP_client);

    spi_bus_config_t buscfg = {
        .miso_io_num = SPI_MISO_GPIO,
        .mosi_io_num = SPI_MOSI_GPIO,
        .sclk_io_num = SPI_SCLK_GPIO,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
    };
    ESP_ERROR_CHECK(spi_bus_initialize(ETH_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
    /* w5500 ethernet driver is based on spi driver */
    spi_device_interface_config_t spi_devcfg = {
        .mode = 0,
        .clock_speed_hz = ETH_SPI_CLOCK_MHZ * 1000 * 1000,
        .spics_io_num = ETH_SPI_CS_GPIO,
        .queue_size = 20,
        .cs_ena_posttrans = 2,
    };

    eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(ETH_SPI_HOST, &spi_devcfg);
    w5500_config.int_gpio_num = ETH_SPI_INT_GPIO; // Set GPIO number for ethernet interrupt
    eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
    mac_config.rx_task_stack_size = KILOBYTE * 16; // Set task size
    esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);

    eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
    phy_config.reset_gpio_num = -1;
    esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);

    esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
    esp_err_t err = esp_eth_driver_install(&eth_config, &eth_handle);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Failed to install ethernet w5500 driver %u", err);
    }
    else
    {
        uint8_t mac_addr[6];
        esp_read_mac(mac_addr, ESP_MAC_ETH);
        mac->set_addr(mac, mac_addr); /* Set mac address */
        ESP_LOGI(TAG, "--->> Set mac" MACSTR, MAC2STR(mac_addr));

        /* 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, &eth_event_handler, NULL));
        ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));

        /* Start Ethernet driver state machine */
        ESP_ERROR_CHECK(esp_eth_start(eth_handle));
    }
}

`