From 1f2af24118817158385dea1947c2c696ef2edc32 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 9 Apr 2021 20:36:01 +0200 Subject: [PATCH 1/2] esp_eth: Recover the w5500 driver from missed io interrupt If the GPIO interrupt is re-asserted too quickly it could be missed. If this happens the driver goes silent and never receives any data. Recover by periodic checks of the IO signal level --- components/esp_eth/src/esp_eth_mac_w5500.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/esp_eth/src/esp_eth_mac_w5500.c b/components/esp_eth/src/esp_eth_mac_w5500.c index 1f97d7fd68..55dcafe5c6 100644 --- a/components/esp_eth/src/esp_eth_mac_w5500.c +++ b/components/esp_eth/src/esp_eth_mac_w5500.c @@ -322,8 +322,12 @@ static void emac_w5500_task(void *arg) uint8_t *buffer = NULL; uint32_t length = 0; while (1) { - // block indefinitely until some task notifies me - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + // check if the task receives any notification + if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(1000)) == 0 && // if no notification ... + gpio_get_level(emac->int_gpio_num) != 0) { // ...and no interrupt asserted + continue; // -> just continue to check again + } + /* read interrupt status */ w5500_read(emac, W5500_REG_SOCK_IR(0), &status, sizeof(status)); /* packet received */ From d09f6cac24713ed59b167a807cae6340c1cab470 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 9 Apr 2021 21:25:20 +0200 Subject: [PATCH 2/2] esp_eth: Improve GPIO interrupt processing in w5500 driver Increase the interrupt reassert level timing so the chances of missing two consecutive events are minimal. Enable only SIR_RECV interrupt event, so the SEND events are not used for GPIO signal. --- components/esp_eth/src/esp_eth_mac_w5500.c | 7 +++++-- components/esp_eth/src/w5500.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/components/esp_eth/src/esp_eth_mac_w5500.c b/components/esp_eth/src/esp_eth_mac_w5500.c index 55dcafe5c6..e7f5def779 100644 --- a/components/esp_eth/src/esp_eth_mac_w5500.c +++ b/components/esp_eth/src/esp_eth_mac_w5500.c @@ -267,9 +267,12 @@ static esp_err_t w5500_setup_default(emac_w5500_t *emac) /* Enable MAC RAW mode for SOCK0, enable MAC filter, no blocking broadcast and multicast */ reg_value = W5500_SMR_MAC_RAW | W5500_SMR_MAC_FILTER; MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_MR(0), ®_value, sizeof(reg_value)) == ESP_OK, "write SMR failed", err, ESP_FAIL); - /* Enable receive and send event for SOCK0 */ - reg_value = W5500_SIR_RECV | W5500_SIR_SEND; + /* Enable receive event for SOCK0 */ + reg_value = W5500_SIR_RECV; MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_IMR(0), ®_value, sizeof(reg_value)) == ESP_OK, "write SOCK0 IMR failed", err, ESP_FAIL); + /* Set the interrupt re-assert level to maximum (~1.5ms) to lower the chances of missing it */ + uint16_t int_level = __builtin_bswap16(0xFFFF); + MAC_CHECK(w5500_write(emac, W5500_REG_INTLEVEL, &int_level, sizeof(int_level)) == ESP_OK, "write INTLEVEL failed", err, ESP_FAIL); err: return ret; diff --git a/components/esp_eth/src/w5500.h b/components/esp_eth/src/w5500.h index 8e423796fc..4460f7a8de 100644 --- a/components/esp_eth/src/w5500.h +++ b/components/esp_eth/src/w5500.h @@ -33,6 +33,7 @@ #define W5500_REG_MR W5500_MAKE_MAP(0x0000, W5500_BSB_COM_REG) // Mode #define W5500_REG_MAC W5500_MAKE_MAP(0x0009, W5500_BSB_COM_REG) // MAC Address +#define W5500_REG_INTLEVEL W5500_MAKE_MAP(0x0013, W5500_BSB_COM_REG) // Interrupt Level Timeout #define W5500_REG_IR W5500_MAKE_MAP(0x0015, W5500_BSB_COM_REG) // Interrupt #define W5500_REG_IMR W5500_MAKE_MAP(0x0016, W5500_BSB_COM_REG) // Interrupt Mask #define W5500_REG_SIR W5500_MAKE_MAP(0x0017, W5500_BSB_COM_REG) // Socket Interrupt