|
| 1 | +/* |
| 2 | + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Unlicense OR CC0-1.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <stdio.h> |
| 8 | +#include <stdint.h> |
| 9 | +#include <stddef.h> |
| 10 | +#include <string.h> |
| 11 | +#include "esp_system.h" |
| 12 | +#include "nvs_flash.h" |
| 13 | +#include "esp_event.h" |
| 14 | +#include "esp_netif.h" |
| 15 | +#include "eppp_link.h" |
| 16 | +#include "esp_log.h" |
| 17 | +#include "esp_check.h" |
| 18 | +#include "console_ping.h" |
| 19 | +#include "esp_eth_driver.h" |
| 20 | +#include "driver/gpio.h" |
| 21 | +#include "esp_eth_phy_dummy.h" |
| 22 | + |
| 23 | +#ifdef CONFIG_EXAMPLE_NODE_SERVER |
| 24 | +#define EPPP_CONFIG() EPPP_DEFAULT_SERVER_CONFIG() |
| 25 | +#define EPPP_ROLE EPPP_SERVER |
| 26 | +#define EPPP_RMII_CLK_SINK |
| 27 | +#else |
| 28 | +#define EPPP_CONFIG() EPPP_DEFAULT_CLIENT_CONFIG() |
| 29 | +#define EPPP_ROLE EPPP_CLIENT |
| 30 | +#define EPPP_RMII_CLK_SOURCE |
| 31 | +#endif |
| 32 | + |
| 33 | +void register_iperf(void); |
| 34 | + |
| 35 | +static const char *TAG = "eppp_emac2emac"; |
| 36 | + |
| 37 | + |
| 38 | +static esp_eth_mac_t *s_mac = NULL; |
| 39 | +static esp_eth_phy_t *s_phy = NULL; |
| 40 | + |
| 41 | +#ifdef EPPP_RMII_CLK_SOURCE |
| 42 | +IRAM_ATTR static void gpio_isr_handler(void *arg) |
| 43 | +{ |
| 44 | + BaseType_t high_task_wakeup = pdFALSE; |
| 45 | + TaskHandle_t task_handle = (TaskHandle_t)arg; |
| 46 | + |
| 47 | + vTaskNotifyGiveFromISR(task_handle, &high_task_wakeup); |
| 48 | + if (high_task_wakeup != pdFALSE) { |
| 49 | + portYIELD_FROM_ISR(); |
| 50 | + } |
| 51 | +} |
| 52 | +#else |
| 53 | +#define STARTUP_DELAY_MS 500 |
| 54 | +#endif |
| 55 | + |
| 56 | +esp_err_t eppp_transport_ethernet_init(esp_eth_handle_t *handle[]) |
| 57 | +{ |
| 58 | + *handle = malloc(sizeof(esp_eth_handle_t)); |
| 59 | + ESP_RETURN_ON_FALSE(handle, ESP_ERR_NO_MEM, TAG, "Our of memory"); |
| 60 | + |
| 61 | +#ifdef EPPP_RMII_CLK_SOURCE |
| 62 | + esp_rom_gpio_pad_select_gpio(EMAC_CLK_OUT_180_GPIO); |
| 63 | + gpio_set_pull_mode(EMAC_CLK_OUT_180_GPIO, GPIO_FLOATING); // to not affect GPIO0 (so the Sink Device could be flashed) |
| 64 | + gpio_install_isr_service(0); |
| 65 | + gpio_config_t gpio_source_cfg = { |
| 66 | + .pin_bit_mask = (1ULL << CONFIG_EXAMPLE_RMII_CLK_READY_GPIO), |
| 67 | + .mode = GPIO_MODE_INPUT, |
| 68 | + .pull_up_en = GPIO_PULLUP_DISABLE, |
| 69 | + .pull_down_en = GPIO_PULLDOWN_ENABLE, |
| 70 | + .intr_type = GPIO_INTR_ANYEDGE |
| 71 | + }; |
| 72 | + gpio_config(&gpio_source_cfg); |
| 73 | + TaskHandle_t task_handle = xTaskGetHandle(pcTaskGetName(NULL)); |
| 74 | + gpio_isr_handler_add(CONFIG_EXAMPLE_RMII_CLK_READY_GPIO, gpio_isr_handler, task_handle); |
| 75 | + ESP_LOGW(TAG, "waiting for RMII CLK sink device interrupt"); |
| 76 | + ESP_LOGW(TAG, "if RMII CLK sink device is already running, reset it by `EN` button"); |
| 77 | + while (1) { |
| 78 | + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); |
| 79 | + if (gpio_get_level(CONFIG_EXAMPLE_RMII_CLK_READY_GPIO) == 1) { |
| 80 | + break; |
| 81 | + } |
| 82 | + } |
| 83 | + ESP_LOGI(TAG, "starting Ethernet initialization"); |
| 84 | +#else |
| 85 | + gpio_config_t gpio_sink_cfg = { |
| 86 | + .pin_bit_mask = (1ULL << CONFIG_EXAMPLE_RMII_CLK_READY_GPIO), |
| 87 | + .mode = GPIO_MODE_OUTPUT, |
| 88 | + .pull_up_en = GPIO_PULLUP_DISABLE, |
| 89 | + .pull_down_en = GPIO_PULLDOWN_DISABLE, |
| 90 | + .intr_type = GPIO_INTR_DISABLE |
| 91 | + }; |
| 92 | + gpio_config(&gpio_sink_cfg); |
| 93 | + gpio_set_level(CONFIG_EXAMPLE_RMII_CLK_READY_GPIO, 0); |
| 94 | + vTaskDelay(pdMS_TO_TICKS(STARTUP_DELAY_MS)); |
| 95 | + gpio_set_level(CONFIG_EXAMPLE_RMII_CLK_READY_GPIO, 1); |
| 96 | +#endif // EPPP_RMII_CLK_SOURCE |
| 97 | + |
| 98 | + // --- Initialize Ethernet driver --- |
| 99 | + // Init common MAC and PHY configs to default |
| 100 | + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); |
| 101 | + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); |
| 102 | + |
| 103 | + // Update PHY config based on board specific configuration |
| 104 | + phy_config.reset_gpio_num = -1; // no HW reset |
| 105 | + |
| 106 | + // Init vendor specific MAC config to default |
| 107 | + eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); |
| 108 | + // Update vendor specific MAC config based on board configuration |
| 109 | + // No SMI, speed/duplex must be statically configured the same in both devices |
| 110 | +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) |
| 111 | + esp32_emac_config.smi_gpio.mdc_num = -1; |
| 112 | + esp32_emac_config.smi_gpio.mdio_num = -1; |
| 113 | +#else |
| 114 | + esp32_emac_config.smi_mdc_gpio_num = -1; |
| 115 | + esp32_emac_config.smi_mdio_gpio_num = -1; |
| 116 | +#endif |
| 117 | +#ifdef EPPP_RMII_CLK_SOURCE |
| 118 | + esp32_emac_config.clock_config.rmii.clock_mode = EMAC_CLK_OUT; |
| 119 | + esp32_emac_config.clock_config.rmii.clock_gpio = EMAC_CLK_OUT_180_GPIO; |
| 120 | +#else |
| 121 | + esp32_emac_config.clock_config.rmii.clock_mode = EMAC_CLK_EXT_IN; |
| 122 | + esp32_emac_config.clock_config.rmii.clock_gpio = EMAC_CLK_IN_GPIO; |
| 123 | +#endif // EPPP_RMII_CLK_SOURCE |
| 124 | + |
| 125 | + // Create new ESP32 Ethernet MAC instance |
| 126 | + s_mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); |
| 127 | + // Create dummy PHY instance |
| 128 | + s_phy = esp_eth_phy_new_dummy(&phy_config); |
| 129 | + |
| 130 | + // Init Ethernet driver to default and install it |
| 131 | + esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy); |
| 132 | +#ifdef EPPP_RMII_CLK_SINK |
| 133 | + // REF RMII CLK sink device performs multiple EMAC init attempts since RMII CLK source device may not be ready yet |
| 134 | + int i; |
| 135 | + for (i = 1; i <= 5; i++) { |
| 136 | + ESP_LOGI(TAG, "Ethernet driver install attempt: %i", i); |
| 137 | + if (esp_eth_driver_install(&config, *handle) == ESP_OK) { |
| 138 | + break; |
| 139 | + } |
| 140 | + vTaskDelay(pdMS_TO_TICKS(100)); |
| 141 | + } |
| 142 | + ESP_RETURN_ON_FALSE(i <= 5, ESP_FAIL, TAG, "Ethernet driver install failed"); |
| 143 | +#else |
| 144 | + ESP_RETURN_ON_ERROR(esp_eth_driver_install(&config, *handle), TAG, "Ethernet driver install failed"); |
| 145 | +#endif // EPPP_RMII_CLK_SINK |
| 146 | + return ESP_OK; |
| 147 | + |
| 148 | +} |
| 149 | + |
| 150 | +void app_main(void) |
| 151 | +{ |
| 152 | + ESP_LOGI(TAG, "[APP] Startup.."); |
| 153 | + ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size()); |
| 154 | + ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); |
| 155 | + |
| 156 | + ESP_ERROR_CHECK(nvs_flash_init()); |
| 157 | + ESP_ERROR_CHECK(esp_netif_init()); |
| 158 | + ESP_ERROR_CHECK(esp_event_loop_create_default()); |
| 159 | + |
| 160 | + /* Sets up the default EPPP-connection |
| 161 | + */ |
| 162 | + eppp_config_t config = EPPP_CONFIG(); |
| 163 | + config.transport = EPPP_TRANSPORT_ETHERNET; |
| 164 | + esp_netif_t *eppp_netif = eppp_open(EPPP_ROLE, &config, portMAX_DELAY); |
| 165 | + if (eppp_netif == NULL) { |
| 166 | + ESP_LOGE(TAG, "Failed to connect"); |
| 167 | + return ; |
| 168 | + } |
| 169 | + // Initialize console REPL |
| 170 | + ESP_ERROR_CHECK(console_cmd_init()); |
| 171 | + |
| 172 | + register_iperf(); |
| 173 | + |
| 174 | + printf("\n =======================================================\n"); |
| 175 | + printf(" | Steps to Test EPPP-emac2emca bandwidth |\n"); |
| 176 | + printf(" | |\n"); |
| 177 | + printf(" | 1. Wait for the ESP32 to get an IP |\n"); |
| 178 | + printf(" | 2. Server: 'iperf -u -s -i 3' (on host) |\n"); |
| 179 | + printf(" | 3. Client: 'iperf -u -c SERVER_IP -t 60 -i 3' |\n"); |
| 180 | + printf(" | |\n"); |
| 181 | + printf(" =======================================================\n\n"); |
| 182 | + |
| 183 | + // using also ping command to check basic network connectivity |
| 184 | + ESP_ERROR_CHECK(console_cmd_ping_register()); |
| 185 | + ESP_ERROR_CHECK(console_cmd_start()); |
| 186 | + |
| 187 | + // handle GPIO0 workaround for ESP32 |
| 188 | +#ifdef CONFIG_EXAMPLE_NODE_SERVER |
| 189 | + // Wait indefinitely or reset when "RMII CLK Sink Device" resets |
| 190 | + // We reset the "RMII CLK Source Device" to ensure there is no CLK at GPIO0 of the |
| 191 | + // "RMII CLK Sink Device" during startup |
| 192 | + while (1) { |
| 193 | + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); |
| 194 | + if (gpio_get_level(CONFIG_EXAMPLE_RMII_CLK_READY_GPIO) == 0) { |
| 195 | + break; |
| 196 | + } |
| 197 | + } |
| 198 | + ESP_LOGW(TAG, "RMII CLK Sink device reset, I'm going to reset too!"); |
| 199 | + esp_restart(); |
| 200 | +#endif |
| 201 | +} |
0 commit comments