MCU - ESP32 Wroom 32
IDE VSCODE
IDE ESP-IDF 5.1
My device needs to receive data via SPI every 1ms and send it via Eth W5500. Using WiFi instead of W5500, the project works stably.
I have already tested the operation of the W5500 + SPIslave(DMA) for two weeks, so I am providing a short code to find bugs, and not a real project.
Description of the problem: When the SPI_slave (DMA) and the W5500 chip (only the Eth driver, the LWIP library is not used) work simultaneously and transmit packets (any) to the IP address of my ESP32 device, after a certain time a failure occurs:
- E (992450) w5500.mac: emac_w5500_alloc_recv_buf(535): invalid frame length 3
- Guru Meditation Error: Core 1 panic'ed (Unhandled debug exception).
- Debug exception reason: Stack canary watchpoint triggered (w5500_tsk)
- Core 1 register dump:
- PC : 0x4008847f PS : 0x00060736 A0 : 0x8008d350 A1 : 0x3ffb8ec0
- 0x4008847f: esp_cpu_compare_and_set at C:/Users/yuriy/esp/esp-idf/components/esp_hw_support/cpu.c:410
- A2 : 0x3ffb0084 A3 : 0xb33fffff A4 : 0x0000abab A5 : 0x00000058
- A6 : 0x0000000a A7 : 0xff000000 A8 : 0x3ffb22e4 A9 : 0x5a97e5cc
- A10 : 0x3ffb0234 A11 : 0x3ffb22e4 A12 : 0x3ffb93f4 A13 : 0x00000005
- A14 : 0x3ffb93bc A15 : 0x00000000 SAR : 0x00000004 EXCCAUSE: 0x00000001
- EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffff9
- 0x400014fd: strlen in ROM
- 0x4000150d: strlen in ROM
- Backtrace: 0x4008847c:0x3ffb8ec0 0x4008d34d:0x3ffb8ef0 0x4008c760:0x3ffb8f30 0x40089f3e:0x3ffb8f60 0x4008a4bd:0x3ffb8f90 0x4008a68a:0x3ffb8fd0 0x400843af:0x3ffb9000 0x40084599:0x3ffb9030 0x400d8214:0x3ffb9060 0x400d6c9d:0x3ffb9090 0x400d6699:0x3ffb90c0 0x4000bd83:0x3ffb90f0 0x4000117d:0x3ffb9110 0x400592fe:0x3ffb9130 0x4005937a:0x3ffb9150 0x400e9d93:0x3ffb9170 0x400f1c1b:0x3ffb91a0 0x400ed816:0x3ffb91c0 0x400ed981:0x3ffb94e0 0x400f76c1:0x3ffb9510 0x400917bd:0x3ffb9550 0x400e533d:0x3ffb95a0 0x400e5656:0x3ffb95e0 0x4008d182:0x3ffb9620
- 0x4008847c: esp_cpu_compare_and_set at C:/Users/yuriy/esp/esp-idf/components/esp_hw_support/cpu.c:410
- 0x4008d34d: spinlock_acquire at C:/Users/yuriy/esp/esp-idf/components/esp_hw_support/include/spinlock.h:103
- (inlined by) xPortEnterCriticalTimeout at C:/Users/yuriy/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:501
- 0x4008c760: vPortEnterCritical at C:/Users/yuriy/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h:575
- (inlined by) xTaskPriorityDisinherit at C:/Users/yuriy/esp/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:5184
- 0x40089f3e: prvCopyDataToQueue at C:/Users/yuriy/esp/esp-idf/components/freertos/FreeRTOS-Kernel/queue.c:2414
- 0x4008a4bd: xQueueGenericSend at C:/Users/yuriy/esp/esp-idf/components/freertos/FreeRTOS-Kernel/queue.c:906
- 0x4008a68a: xQueueGiveMutexRecursive at C:/Users/yuriy/esp/esp-idf/components/freertos/FreeRTOS-Kernel/queue.c:737
- 0x400843af: lock_release_generic at C:/Users/yuriy/esp/esp-idf/components/newlib/locks.c:190
- 0x40084599: _lock_release_recursive at C:/Users/yuriy/esp/esp-idf/components/newlib/locks.c:202
- 0x400d8214: uart_write at C:/Users/yuriy/esp/esp-idf/components/vfs/vfs_uart.c:219
- 0x400d6c9d: console_write at C:/Users/yuriy/esp/esp-idf/components/vfs/vfs_console.c:73
- 0x400d6699: esp_vfs_write at C:/Users/yuriy/esp/esp-idf/components/vfs/vfs.c:445 (discriminator 4)
- 0x4000bd83: _write_r in ROM
- 0x4000117d: __swrite in ROM
- 0x400592fe: __sflush_r in ROM
- 0x4005937a: _fflush_r in ROM
- 0x400e9d93: __sfvwrite_r at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdio/fvwrite.c:251
- 0x400f1c1b: __sprint_r at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdio/vfprintf.c:429
- (inlined by) __sprint_r at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdio/vfprintf.c:399
- 0x400ed816: _vfprintf_r at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdio/vfprintf.c:1777 (discriminator 1)
- 0x400ed981: vprintf at /builds/idf/crosstool-NG/.build/HOST-x86_64-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdio/vprintf.c:34 (discriminator 5)
- 0x400f76c1: esp_log_writev at C:/Users/yuriy/esp/esp-idf/components/log/log.c:200
- 0x400917bd: esp_log_write at C:/Users/yuriy/esp/esp-idf/components/log/log.c:210
- 0x400e533d: emac_w5500_alloc_recv_buf at C:/Users/yuriy/esp/esp-idf/components/esp_eth/src/esp_eth_mac_w5500.c:535 (discriminator 5)
- 0x400e5656: emac_w5500_task at C:/Users/yuriy/esp/esp-idf/components/esp_eth/src/esp_eth_mac_w5500.c:670
- 0x4008d182: vPortTaskWrapper at C:/Users/yuriy/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162
- ELF file SHA256: 0928843e63d183e2
- Rebooting...
When increasing rx_task_stack_size = 2048 to rx_task_stack_size = 8192 errors:
- E (120665) w5500.mac: emac_w5500_alloc_recv_buf(535): invalid frame length 3
- E (120665) w5500.mac: no mem for receive buffer
- E (122156) w5500.mac: emac_w5500_alloc_recv_buf(535): invalid frame length 3
- E (122156) w5500.mac: no mem for receive buffer
- E (122966) w5500.mac: emac_w5500_alloc_recv_buf(535): invalid frame length 3
- E (122966) w5500.mac: no mem for receive buffer
- E (123003) w5500.mac: emac_w5500_alloc_recv_buf(535): invalid frame length 0
- E (123004) w5500.mac: emac_w5500_alloc_recv_buf(535): invalid frame length 0
- E (123008) w5500.mac: emac_w5500_alloc_recv_buf(535): invalid frame length 0
I ask for help to solve the problem of unstable operation of the W5500 together with SPI_Slave.
Thank you.
My task SPI code:
- #define GPIO_MOSI 13
- #define GPIO_MISO 12
- #define GPIO_SCLK 14
- #define GPIO_CS 21//15
- #define RCV_HOST HSPI_HOST
- spi_slave_transaction_t t;
- spi_slave_transaction_t *loopbuf;
- uint8_t *sendbuf;
- uint8_t *recvbuf;
- int n=0;
- //Called after a transaction is queued and ready for pickup by master.
- void IRAM_ATTR my_post_setup_cb(spi_slave_transaction_t *trans) {
- }
- //Called after transaction is sent/received. We use this to set the handshake line low.
- void IRAM_ATTR my_post_trans_cb(spi_slave_transaction_t *trans) {
- }
- //Main application
- static void IRAM_ATTR My_SPI_Slave_task(void *pvParameters){
- sendbuf = heap_caps_calloc(1,1500, MALLOC_CAP_DMA);
- recvbuf = heap_caps_calloc(1,1500, MALLOC_CAP_DMA);
- if (!sendbuf) {
- ESP_LOGI("Create pool:", "No enough memory");
- //return ESP_ERR_NO_MEM;
- }
- if (!recvbuf) {
- ESP_LOGI("Create pool:", "No enough memory");
- //return ESP_ERR_NO_MEM;
- }
- esp_err_t ret;
- //Configuration for the SPI bus
- spi_bus_config_t buscfg={
- .mosi_io_num=GPIO_MOSI,
- .miso_io_num=GPIO_MISO,
- .sclk_io_num=GPIO_SCLK,
- .quadwp_io_num = -1,
- .quadhd_io_num = -1,
- .isr_cpu_id = INTR_CPU_ID_AUTO,
- };
- //Configuration for the SPI slave interface
- spi_slave_interface_config_t slvcfg={
- .mode=0,
- .spics_io_num=GPIO_CS,
- .queue_size=3,
- .flags=0,
- .post_setup_cb=my_post_setup_cb,
- .post_trans_cb=my_post_trans_cb
- };
- gpio_set_pull_mode(GPIO_MOSI, GPIO_PULLUP_ONLY);
- gpio_set_pull_mode(GPIO_SCLK, GPIO_PULLUP_ONLY);
- gpio_set_pull_mode(GPIO_CS, GPIO_PULLUP_ONLY);
- ret=spi_slave_initialize(RCV_HOST, &buscfg, &slvcfg, SPI_DMA_CH_AUTO );
- assert(ret==ESP_OK);
- loopbuf = (spi_slave_transaction_t *) malloc (sizeof(spi_slave_transaction_t));
- t.length=1500*8;
- t.tx_buffer=sendbuf;
- t.rx_buffer=recvbuf;
- size_t item_size;
- while(1) {
- ret = spi_slave_transmit(RCV_HOST, &t, 1000);
- }
- }
Eth_W5500 driver initialization code:
- #define CONFIG_ETH_PHY_ADDR 1
- #define CONFIG_ETH_PHY_RST_GPIO -1
- #define CONFIG_ETH_SPI_MISO_GPIO 19
- #define CONFIG_ETH_SPI_MOSI_GPIO 23
- #define CONFIG_ETH_SPI_SCLK_GPIO 18
- #define CONFIG_ETH_SPI_CLOCK_MHZ 32
- #define CONFIG_ETH_SPI_CS_GPIO 5
- #define CONFIG_ETH_SPI_HOST VSPI_HOST
- #define CONFIG_ETH_SPI_INT_GPIO 4
- static const char *TAG2 = "LOG";
- ////////////////////////////
- /** Event handler for Ethernet events */
- static void IRAM_ATTR eth_event_handler(void *arg, esp_event_base_t event_base,
- int32_t event_id, void *event_data)
- {
- uint8_t mac_addr[6] = {};
- /* 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(TAG2, "Ethernet Link Up");
- ESP_LOGI(TAG2, "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]);
- break;
- case ETHERNET_EVENT_DISCONNECTED:
- ESP_LOGI(TAG2, "Ethernet Link Down");
- break;
- case ETHERNET_EVENT_START:
- ESP_LOGI(TAG2, "Ethernet Started");
- break;
- case ETHERNET_EVENT_STOP:
- ESP_LOGI(TAG2, "Ethernet Stopped");
- break;
- default:
- break;
- }
- }
- esp_eth_handle_t MyInitEth(){
- eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); // apply default common MAC configuration
- mac_config.rx_task_stack_size = 2048;
- mac_config.rx_task_prio = 15;
- eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); // apply default PHY configuration
- phy_config.phy_addr = CONFIG_ETH_PHY_ADDR; // alter the PHY address according to your board design
- phy_config.reset_gpio_num = CONFIG_ETH_PHY_RST_GPIO; // alter the GPIO used for PHY reset
- // Install GPIO interrupt service (as the SPI-Ethernet module is interrupt-driven)
- gpio_install_isr_service(0);
- // SPI bus configuration
- spi_device_handle_t spi_handle = NULL;
- spi_bus_config_t buscfg = {
- .miso_io_num = CONFIG_ETH_SPI_MISO_GPIO,
- .mosi_io_num = CONFIG_ETH_SPI_MOSI_GPIO,
- .sclk_io_num = CONFIG_ETH_SPI_SCLK_GPIO,
- .quadwp_io_num = -1,
- .quadhd_io_num = -1,
- };
- ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_ETH_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
- // Configure SPI device
- spi_device_interface_config_t spi_devcfg = {
- .mode = 0,
- .clock_speed_hz = CONFIG_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
- .spics_io_num = CONFIG_ETH_SPI_CS_GPIO,
- .queue_size = 20
- };
- /* w5500 ethernet driver is based on spi driver */
- eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(CONFIG_ETH_SPI_HOST, &spi_devcfg);
- w5500_config.int_gpio_num = CONFIG_ETH_SPI_INT_GPIO;
- esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
- esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
- /////////////////////////////
- bool flow_ctrl_enable = true;/**/
- esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // apply default driver configuration
- esp_eth_handle_t eth_handle = NULL; // after the driver is installed, we will get the handle of the driver
- esp_eth_ioctl(eth_handle, ETH_CMD_S_FLOW_CTRL, &flow_ctrl_enable);/**/
- esp_eth_driver_install(&config, ð_handle); // install driver
- esp_eth_ioctl(eth_handle, ETH_CMD_S_FLOW_CTRL, &flow_ctrl_enable);/**/
- uint8_t mac_addr[6] = {06,30,00,79,67,80};
- esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, mac_addr);
- ESP_ERROR_CHECK(esp_event_loop_create_default());
- esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL); // register Ethernet event handler (to deal with user-specific stuff when events like link up/down happened)
- return eth_handle;
- }
- /** Event handler for IP_EVENT_ETH_GOT_IP */
- static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
- int32_t event_id, void *event_data)
- {
- 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_LOGI(TAG2, "Ethernet Got IP Address");
- ESP_LOGI(TAG2, "~~~~~~~~~~~");
- ESP_LOGI(TAG2, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
- ESP_LOGI(TAG2, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
- ESP_LOGI(TAG2, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
- ESP_LOGI(TAG2, "~~~~~~~~~~~");
- }
- void nnetif(esp_eth_handle_t www){
- esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); // apply default network interface configuration for Ethernet
- esp_netif_t *eth_netif = esp_netif_new(&cfg); // create network interface for Ethernet driver
- esp_netif_attach(eth_netif, esp_eth_new_netif_glue(www)); // attach Ethernet driver to TCP/IP stack
- esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL); // register user defined IP event handlers
- esp_eth_start(www); // start Ethernet driver state machine
- }
My main code:
- void app_main(void)
- {
- esp_eth_handle_t myEth = MyInitEth();
- esp_netif_init(); // Initialize TCP/IP network interface (should be called only once in application)
- nnetif(myEth);
- vTaskDelay(7000);
- xTaskCreate(My_SPI_Slave_task, "My_SPI_Slave", 4096, NULL, 5, NULL);
- //xTaskCreate(My_udp_server_task, "My_udp_server", 4096,NULL, 5, NULL);
- }