From 566a471d02cc23cade11bb0537251d3e94aafb02 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 27 Feb 2024 17:14:50 +0100 Subject: [PATCH] fix(eppp): Some optional fixes to SDIO --- components/eppp_link/README.md | 15 +- components/eppp_link/eppp_link.c | 14 +- components/eppp_link/eppp_sdio.h | 9 +- components/eppp_link/eppp_sdio_host.c | 171 ++++++++++------------- components/eppp_link/eppp_sdio_slave.c | 71 ++++++---- components/eppp_link/include/eppp_link.h | 21 ++- 6 files changed, 158 insertions(+), 143 deletions(-) diff --git a/components/eppp_link/README.md b/components/eppp_link/README.md index 9b517e7f6a5..4112c059199 100644 --- a/components/eppp_link/README.md +++ b/components/eppp_link/README.md @@ -14,7 +14,7 @@ brings in the WiFi connectivity from the "SLAVE" microcontroller. SLAVE micro HOST micro \|/ +----------------+ +----------------+ | | | serial line | | - +---+ WiFi NAT PPPoS |======== UART / SPI =======| PPPoS client | + +---+ WiFi NAT PPPoS |=== UART / SPI / SDIO =====| PPPoS client | | (server)| | | +----------------+ +----------------+ ``` @@ -39,14 +39,19 @@ brings in the WiFi connectivity from the "SLAVE" microcontroller. ## Throughput -Tested with WiFi-NAPT example, no IRAM optimizations +Tested with WiFi-NAPT example ### UART @ 3Mbauds * TCP - 2Mbits/s * UDP - 2Mbits/s -### SPI @ 20MHz +### SPI @ 16MHz -* TCP - 6Mbits/s -* UDP - 10Mbits/s +* TCP - 5Mbits/s +* UDP - 8Mbits/s + +### SDIO + +* TCP - 9Mbits/s +* UDP - 11Mbits/s diff --git a/components/eppp_link/eppp_link.c b/components/eppp_link/eppp_link.c index f3274c83cbe..054073473cb 100644 --- a/components/eppp_link/eppp_link.c +++ b/components/eppp_link/eppp_link.c @@ -94,8 +94,10 @@ esp_err_t eppp_sdio_host_tx(void *h, void *buffer, size_t len); esp_err_t eppp_sdio_host_rx(esp_netif_t *netif); esp_err_t eppp_sdio_slave_rx(esp_netif_t *netif); esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len); -esp_err_t eppp_sdio_host_init(void); +esp_err_t eppp_sdio_host_init(struct eppp_config_sdio_s *config); esp_err_t eppp_sdio_slave_init(void); +void eppp_sdio_slave_deinit(void); +void eppp_sdio_host_deinit(void); #else static esp_err_t transmit(void *h, void *buffer, size_t len) { @@ -726,6 +728,13 @@ void eppp_deinit(esp_netif_t *netif) } #elif CONFIG_EPPP_LINK_DEVICE_UART deinit_uart(esp_netif_get_io_driver(netif)); +#elif CONFIG_EPPP_LINK_DEVICE_SDIO + struct eppp_handle *h = esp_netif_get_io_driver(netif); + if (h->role == EPPP_CLIENT) { + eppp_sdio_host_deinit(); + } else { + eppp_sdio_slave_deinit(); + } #endif netif_deinit(netif); } @@ -754,11 +763,10 @@ esp_netif_t *eppp_init(eppp_type_t role, eppp_config_t *config) init_uart(esp_netif_get_io_driver(netif), config); #elif CONFIG_EPPP_LINK_DEVICE_SDIO esp_err_t ret; - struct eppp_handle *h = esp_netif_get_io_driver(netif); if (role == EPPP_SERVER) { ret = eppp_sdio_slave_init(); } else { - ret = eppp_sdio_host_init(); + ret = eppp_sdio_host_init(&config->sdio); } if (ret != ESP_OK) { diff --git a/components/eppp_link/eppp_sdio.h b/components/eppp_link/eppp_sdio.h index 48fb8d9d232..757f83d54e6 100644 --- a/components/eppp_link/eppp_sdio.h +++ b/components/eppp_link/eppp_sdio.h @@ -5,13 +5,14 @@ */ #pragma once -#define MAX_PAYLOAD 1500 +#define MAX_SDIO_PAYLOAD 1500 #define SDIO_ALIGN(size) (((size) + 3U) & ~(3U)) -#define SDIO_PAYLOAD SDIO_ALIGN(MAX_PAYLOAD) +#define SDIO_PAYLOAD SDIO_ALIGN(MAX_SDIO_PAYLOAD) - -#define SLAVE_INTR 0 +// Interrupts and registers +#define SLAVE_INTR 0 #define SLAVE_REG_REQ 0 +// Requests from host to slave #define REQ_RESET 1 #define REQ_INIT 2 diff --git a/components/eppp_link/eppp_sdio_host.c b/components/eppp_link/eppp_sdio_host.c index b4deee8c869..fda628651dd 100644 --- a/components/eppp_link/eppp_sdio_host.c +++ b/components/eppp_link/eppp_sdio_host.c @@ -13,17 +13,24 @@ #include "eppp_sdio.h" #include "driver/sdmmc_host.h" #include "sdmmc_cmd.h" +#include "esp_check.h" +#include "eppp_link.h" #if CONFIG_SOC_SDMMC_HOST_SUPPORTED +// For blocking operations #define TIMEOUT_MAX UINT32_MAX - +// Short timeout for sending/receiving ESSL packets +#define PACKET_TIMEOUT_MS 50 +// Used for padding unaligned packets, to simplify the logic and keep PPP protocol intact when padded +#define PPP_SOF 0x7E static const char *TAG = "eppp_sdio_host"; static SemaphoreHandle_t s_essl_mutex = NULL; static essl_handle_t s_essl = NULL; +static sdmmc_card_t *s_card = NULL; -static CACHE_ALIGNED_ATTR uint8_t send_buffer[SDIO_ALIGN(MAX_PAYLOAD)]; -static DMA_ATTR uint8_t rcv_buffer[SDIO_ALIGN(MAX_PAYLOAD)]; +static CACHE_ALIGNED_ATTR uint8_t send_buffer[SDIO_PAYLOAD]; +static DMA_ATTR uint8_t rcv_buffer[SDIO_PAYLOAD]; esp_err_t eppp_sdio_host_tx(void *h, void *buffer, size_t len) { @@ -36,133 +43,87 @@ esp_err_t eppp_sdio_host_tx(void *h, void *buffer, size_t len) size_t send_len = SDIO_ALIGN(len); if (send_len > len) { // pad with SOF's - memset(&send_buffer[len], 0x7E, send_len - len); + memset(&send_buffer[len], PPP_SOF, send_len - len); } xSemaphoreTake(s_essl_mutex, portMAX_DELAY); - esp_err_t ret = essl_send_packet(s_essl, send_buffer, send_len, 50); - if (ret == ESP_ERR_TIMEOUT || ret == ESP_ERR_NOT_FOUND) { - ESP_LOGW(TAG, "slave not ready to receive packet %x", ret); - xSemaphoreGive(s_essl_mutex); - return ESP_ERR_NO_MEM; + esp_err_t ret = essl_send_packet(s_essl, send_buffer, send_len, PACKET_TIMEOUT_MS); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Slave not ready to receive packet %x", ret); + vTaskDelay(pdMS_TO_TICKS(1000)); + ret = ESP_ERR_NO_MEM; // to inform the upper layers } +// vTaskDelay(pdMS_TO_TICKS(50)); ESP_LOG_BUFFER_HEXDUMP(TAG, send_buffer, send_len, ESP_LOG_VERBOSE); xSemaphoreGive(s_essl_mutex); - return ESP_OK; + return ret; } static esp_err_t request_slave_reset(void) { + esp_err_t ret = ESP_OK; ESP_LOGI(TAG, "send reset to slave..."); - esp_err_t ret = essl_write_reg(s_essl, SLAVE_REG_REQ, REQ_RESET, NULL, TIMEOUT_MAX); - if (ret != ESP_OK) { - goto fail; - } - ret = essl_send_slave_intr(s_essl, BIT(SLAVE_INTR), TIMEOUT_MAX); - if (ret != ESP_OK) { - goto fail; - } - - vTaskDelay(pdMS_TO_TICKS(500)); - ret = essl_wait_for_ready(s_essl, TIMEOUT_MAX); - if (ret != ESP_OK) { - goto fail; - } + ESP_GOTO_ON_ERROR(essl_write_reg(s_essl, SLAVE_REG_REQ, REQ_RESET, NULL, TIMEOUT_MAX), err, TAG, "write-reg failed"); + ESP_GOTO_ON_ERROR(essl_send_slave_intr(s_essl, BIT(SLAVE_INTR), TIMEOUT_MAX), err, TAG, "send-intr failed"); + vTaskDelay(pdMS_TO_TICKS(PACKET_TIMEOUT_MS)); + ESP_GOTO_ON_ERROR(essl_wait_for_ready(s_essl, TIMEOUT_MAX), err, TAG, "wait-for-ready failed"); ESP_LOGI(TAG, "slave io ready"); - return ESP_OK; -fail: - return ESP_FAIL; +err: + return ret; } -esp_err_t eppp_sdio_host_init(void) +esp_err_t eppp_sdio_host_init(struct eppp_config_sdio_s *eppp_config) { - esp_err_t res; - - sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + esp_err_t ret = ESP_OK; - // initialise SDMMC host - res = sdmmc_host_init(); - if (res != ESP_OK) { - return ESP_FAIL; - } + ESP_GOTO_ON_ERROR(sdmmc_host_init(), err, TAG, "sdmmc host init failed"); // configure SDIO interface and slot - slot_config.width = 4; - slot_config.clk = 18; - slot_config.cmd = 19; - slot_config.d0 = 49; - slot_config.d1 = 50; - slot_config.d2 = 16; - slot_config.d3 = 17; - - res = sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config); - if (res != ESP_OK) { - ESP_LOGE(TAG, "init SDMMC Host slot %d failed", SDMMC_HOST_SLOT_1); - return ESP_FAIL; - } + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + slot_config.width = eppp_config->width; +#ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX + slot_config.clk = eppp_config->clk; + slot_config.cmd = eppp_config->cmd; + slot_config.d0 = eppp_config->d0; + slot_config.d1 = eppp_config->d1; + slot_config.d2 = eppp_config->d2; + slot_config.d3 = eppp_config->d3; +#endif + + ESP_GOTO_ON_ERROR(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config), err, TAG, "init sdmmc host slot failed"); sdmmc_host_t config = SDMMC_HOST_DEFAULT(); config.flags = SDMMC_HOST_FLAG_4BIT; config.max_freq_khz = SDMMC_FREQ_HIGHSPEED; - sdmmc_card_t *card = (sdmmc_card_t *)malloc(sizeof(sdmmc_card_t)); - if (card == NULL) { - return ESP_ERR_NO_MEM; - } - - if (sdmmc_card_init(&config, card) != ESP_OK) { - ESP_LOGE(TAG, "sdmmc_card_init failed"); - goto fail; - } + s_card = (sdmmc_card_t *)malloc(sizeof(sdmmc_card_t)); + ESP_GOTO_ON_FALSE(s_card, ESP_ERR_NO_MEM, err, TAG, "card allocation failed"); + ESP_GOTO_ON_ERROR(sdmmc_card_init(&config, s_card), err, TAG, "sdmmc card init failed"); essl_sdio_config_t ser_config = { - .card = card, + .card = s_card, .recv_buffer_size = SDIO_PAYLOAD, }; - res = essl_sdio_init_dev(&s_essl, &ser_config); - if (res != ESP_OK || s_essl == NULL) { - ESP_LOGE(TAG, "essl_sdio_init_dev failed %d", res); - goto fail; - } - res = essl_init(s_essl, TIMEOUT_MAX); - if (res != ESP_OK) { - ESP_LOGE(TAG, "essl_init failed %d", res); - goto fail; - } + ESP_GOTO_ON_FALSE(essl_sdio_init_dev(&s_essl, &ser_config) == ESP_OK && s_essl, ESP_FAIL, err, TAG, "essl_sdio_init_dev failed"); + ESP_GOTO_ON_ERROR(essl_init(s_essl, TIMEOUT_MAX), err, TAG, "essl-init failed"); + ESP_GOTO_ON_ERROR(request_slave_reset(), err, TAG, "failed to reset the slave"); + ESP_GOTO_ON_FALSE((s_essl_mutex = xSemaphoreCreateMutex()), ESP_ERR_NO_MEM, err, TAG, "failed to create semaphore"); + return ret; - if (request_slave_reset() != ESP_OK) { - ESP_LOGE(TAG, "failed to reset the slave"); - goto fail; - } - s_essl_mutex = xSemaphoreCreateMutex(); - if (s_essl_mutex == NULL) { - ESP_LOGE(TAG, "failed to create semaphore"); - goto fail; - } - return ESP_OK; - -fail: +err: essl_sdio_deinit_dev(s_essl); s_essl = NULL; - return ESP_FAIL; + return ret; } static esp_err_t get_intr(uint32_t *out_raw) { esp_err_t ret = ESP_OK; - ret = essl_wait_int(s_essl, TIMEOUT_MAX); - if (ret != ESP_OK) { - return ret; - } - ret = essl_get_intr(s_essl, out_raw, NULL, TIMEOUT_MAX); - if (ret != ESP_OK) { - return ret; - } - ret = essl_clear_intr(s_essl, *out_raw, TIMEOUT_MAX); - if (ret != ESP_OK) { - return ret; - } + ESP_GOTO_ON_ERROR(essl_wait_int(s_essl, TIMEOUT_MAX), err, TAG, "essl-wait-int failed"); + ESP_GOTO_ON_ERROR(essl_get_intr(s_essl, out_raw, NULL, TIMEOUT_MAX), err, TAG, "essl-get-int failed"); + ESP_GOTO_ON_ERROR(essl_clear_intr(s_essl, *out_raw, TIMEOUT_MAX), err, TAG, "essl-clear-int failed"); ESP_LOGD(TAG, "intr: %08"PRIX32, *out_raw); - return ESP_OK; +err: + return ret; } esp_err_t eppp_sdio_host_rx(esp_netif_t *netif) @@ -173,16 +134,15 @@ esp_err_t eppp_sdio_host_rx(esp_netif_t *netif) return ESP_OK; } if (err != ESP_OK) { - ESP_LOGE(TAG, "failed to read interrupt register"); + ESP_LOGE(TAG, "failed to check for interrupts %d", err); return ESP_FAIL; } - const int wait_ms = 50; if (intr & ESSL_SDIO_DEF_ESP32.new_packet_intr_mask) { xSemaphoreTake(s_essl_mutex, portMAX_DELAY); esp_err_t ret; do { - size_t size_read = MAX_PAYLOAD; - ret = essl_get_packet(s_essl, rcv_buffer, MAX_PAYLOAD, &size_read, wait_ms); + size_t size_read = SDIO_PAYLOAD; + ret = essl_get_packet(s_essl, rcv_buffer, SDIO_PAYLOAD, &size_read, PACKET_TIMEOUT_MS); if (ret == ESP_ERR_NOT_FOUND) { ESP_LOGE(TAG, "interrupt but no data can be read"); break; @@ -204,6 +164,15 @@ esp_err_t eppp_sdio_host_rx(esp_netif_t *netif) return ESP_OK; } +void eppp_sdio_host_deinit() +{ + essl_sdio_deinit_dev(s_essl); + sdmmc_host_deinit(); + free(s_card); + s_card = NULL; + s_essl = NULL; +} + #else // SDMMC_HOST NOT-SUPPORTED esp_err_t eppp_sdio_host_tx(void *handle, void *buffer, size_t len) @@ -216,6 +185,10 @@ esp_err_t eppp_sdio_host_rx(esp_netif_t *netif) return ESP_ERR_NOT_SUPPORTED; } +void eppp_sdio_host_deinit() +{ +} + esp_err_t eppp_sdio_host_init() { return ESP_ERR_NOT_SUPPORTED; diff --git a/components/eppp_link/eppp_sdio_slave.c b/components/eppp_link/eppp_sdio_slave.c index 3e0d421d951..6f5435d2250 100644 --- a/components/eppp_link/eppp_sdio_slave.c +++ b/components/eppp_link/eppp_sdio_slave.c @@ -10,9 +10,10 @@ #include "esp_netif.h" #include "driver/sdio_slave.h" #include "eppp_sdio.h" +#include "esp_check.h" #if CONFIG_SOC_SDIO_SLAVE_SUPPORTED -#define BUFFER_NUM 2 +#define BUFFER_NUM 4 static const char *TAG = "eppp_sdio_slave"; static WORD_ALIGNED_ATTR uint8_t sdio_slave_rx_buffer[BUFFER_NUM][SDIO_PAYLOAD]; @@ -44,30 +45,23 @@ esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len) static esp_err_t slave_reset(void) { + esp_err_t ret = ESP_OK; ESP_LOGI(TAG, "SDIO slave reset"); - esp_err_t ret; sdio_slave_stop(); - ret = sdio_slave_reset(); - if (ret != ESP_OK) { - return ret; - } - ret = sdio_slave_start(); - if (ret != ESP_OK) { - return ret; - } + ESP_GOTO_ON_ERROR(sdio_slave_reset(), err, TAG, "slave reset failed"); + ESP_GOTO_ON_ERROR(sdio_slave_start(), err, TAG, "slave start failed"); while (1) { sdio_slave_buf_handle_t handle; ret = sdio_slave_send_get_finished(&handle, 0); - if (ret != ESP_OK) { - break; - } - ret = sdio_slave_recv_load_buf(handle); - if (ret != ESP_OK) { + if (ret == ESP_ERR_TIMEOUT) { break; } + ESP_GOTO_ON_ERROR(ret, err, TAG, "slave-get-finished failed"); + ESP_GOTO_ON_ERROR(sdio_slave_recv_load_buf(handle), err, TAG, "slave-load-buf failed"); } - return ESP_OK; +err: + return ret; } esp_err_t eppp_sdio_slave_rx(esp_netif_t *netif) @@ -78,24 +72,30 @@ esp_err_t eppp_sdio_slave_rx(esp_netif_t *netif) s_slave_request = REQ_INIT; } sdio_slave_buf_handle_t handle; + size_t length; + uint8_t *ptr; esp_err_t ret = sdio_slave_recv_packet(&handle, pdMS_TO_TICKS(1000)); if (ret == ESP_ERR_TIMEOUT) { return ESP_OK; } - if (ret == ESP_ERR_NOT_FINISHED) { // don't support receiving in fragments, we rely on upper layers - ESP_LOGE(TAG, "Failed to receive full packet"); - return ESP_FAIL; - } - size_t length; - uint8_t *ptr = sdio_slave_recv_get_buf(handle, &length); - ESP_LOG_BUFFER_HEXDUMP(TAG, ptr, length, ESP_LOG_VERBOSE); - esp_netif_receive(netif, ptr, length, NULL); - ret = sdio_slave_recv_load_buf(handle); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to recycle packet buffer"); - return ret; + if (ret == ESP_ERR_NOT_FINISHED || ret == ESP_OK) { +again: + ptr = sdio_slave_recv_get_buf(handle, &length); + esp_netif_receive(netif, ptr, length, NULL); + if (sdio_slave_recv_load_buf(handle) != ESP_OK) { + ESP_LOGE(TAG, "Failed to recycle packet buffer"); + return ESP_FAIL; + } + if (ret == ESP_ERR_NOT_FINISHED) { + ret = sdio_slave_recv_packet(&handle, 0); + if (ret == ESP_ERR_NOT_FINISHED || ret == ESP_OK) { + goto again; + } + } + return ESP_OK; } - return ESP_OK; + ESP_LOGE(TAG, "Error when receiving packet %d", ret); + return ESP_FAIL; } @@ -129,7 +129,6 @@ esp_err_t eppp_sdio_slave_init(void) sdio_slave_deinit(); return ESP_FAIL; } - ret = sdio_slave_recv_load_buf(handle); if (ret != ESP_OK) { sdio_slave_deinit(); @@ -137,7 +136,7 @@ esp_err_t eppp_sdio_slave_init(void) } } - sdio_slave_set_host_intena(SDIO_SLAVE_HOSTINT_SEND_NEW_PACKET); + sdio_slave_set_host_intena(SDIO_SLAVE_HOSTINT_SEND_NEW_PACKET); // only need one interrupt to notify of a new packet ret = sdio_slave_start(); if (ret != ESP_OK) { @@ -147,6 +146,12 @@ esp_err_t eppp_sdio_slave_init(void) return ESP_OK; } +void eppp_sdio_slave_deinit(void) +{ + sdio_slave_stop(); + sdio_slave_deinit(); +} + #else // SOC_SDIO_SLAVE NOT-SUPPORTED esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len) @@ -158,6 +163,10 @@ esp_err_t eppp_sdio_slave_rx(esp_netif_t *netif) return ESP_ERR_NOT_SUPPORTED; } +void eppp_sdio_slave_deinit() +{ +} + esp_err_t eppp_sdio_slave_init(void) { return ESP_ERR_NOT_SUPPORTED; diff --git a/components/eppp_link/include/eppp_link.h b/components/eppp_link/include/eppp_link.h index 797b7f92fdc..3cd1f2a4eee 100644 --- a/components/eppp_link/include/eppp_link.h +++ b/components/eppp_link/include/eppp_link.h @@ -28,7 +28,16 @@ .rx_io = 26, \ .queue_size = 16, \ .rx_buffer_size = 1024, \ - }, \ + }, \ + .sdio = { \ + .width = 4, \ + .clk = 18, \ + .cmd = 19, \ + .d0 = 49, \ + .d1 = 50, \ + .d2 = 16, \ + .d3 = 17, \ + }, \ . task = { \ .run_task = true, \ .stack_size = 4096, \ @@ -80,6 +89,16 @@ typedef struct eppp_config_t { int rx_buffer_size; } uart; + struct eppp_config_sdio_s { + int width; + int clk; + int cmd; + int d0; + int d1; + int d2; + int d3; + } sdio; + struct eppp_config_task_s { bool run_task; int stack_size;