Open K-hastings opened 3 months ago
Those features were added here by @uLipe. Not sure if they are still valid or maintained.
Please, open a PR with the fix if you find a solution.
Espressif updated the ethernet handling stack here. I made some changes to get microROS to work with ethernet on 5.2 but had no time to test the results yet.
ESP NETIF Glue Event Handlers
esp_eth_set_default_handlers() and esp_eth_clear_default_handlers() functions are removed. Registration of the default IP layer handlers for Ethernet is now handled automatically. If you have already followed the suggestion to fully initialize the Ethernet driver and network interface before registering their Ethernet/IP event handlers, then no action is required (except for deleting the affected functions). Otherwise, you may start the Ethernet driver right after they register the user event handler.
Could you please open a PR with the solution?
Please mind the esp-idf v4 is not compatible with v5.
So the PR for it would add support for v5 and above, not for replace the v4.x since they are in LTS and production periods.
I've been experimenting with an Olimex ESP32 PoE board equipped with an internal Lan8720 chip and have tested the provided code with both middleware: embeddedRTPS and XRCE-DDS in Espressif IDF v5.2.1.
Here are the changes made:
Removed esp_eth_set_default_handlers
as it's now handled automatically. Refer to this documentation for more details.
// Removed: Set default handlers to process TCP/IP stuffs
//ESP_ERROR_CHECK(esp_eth_set_default_handlers(eth_netif));
Moved GPIO initialization from MAC to EMAC configuration.
// Initialize MAC and PHY configs to default
eth_esp32_emac_config_t emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
mac_config.sw_reset_timeout_ms = 250; // Required for some Ethernet controllers to initiate
emac_config.smi_mdc_gpio_num = CONFIG_MICRO_ROS_ETH_MDC_GPIO;
emac_config.smi_mdio_gpio_num = CONFIG_MICRO_ROS_ETH_MDIO_GPIO;
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&emac_config, &mac_config);
Consideration for adding an EventGroupHandle_t
so that app_main
only exits if an IP was obtained. This concept is already implemented in the WiFi code. Currently, I've applied a workaround by adding a 5-second delay in the main after network initialization, which hasn't caused any failures so far.
Changed esp_eth_phy_new_lan8720
to esp_eth_phy_new_lan87xx
as the support was extended to the entire 87 family of chips.
Please note that I do not have a W5500 on hand to test and fix the rest.
The final version of uros_ethernet_netif.c
reflects these changes:
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_netif.h"
#include "esp_eth.h"
#include "esp_event.h"
#include "esp_log.h"
#include "sdkconfig.h"
#if CONFIG_ETH_USE_SPI_ETHERNET
#include "driver/spi_master.h"
#endif
#include "uros_network_interfaces.h"
#ifdef CONFIG_MICRO_ROS_ESP_NETIF_ENET
uint8_t IP_ADDRESS[4];
static const char *TAG = "eth_interface";
static void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
uint8_t mac_addr[6] = {0};
/* 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(TAG, "Ethernet Link Up");
ESP_LOGI(TAG, "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(TAG, "Ethernet Link Down");
break;
case ETHERNET_EVENT_START:
ESP_LOGI(TAG, "Ethernet Started");
break;
case ETHERNET_EVENT_STOP:
ESP_LOGI(TAG, "Ethernet Stopped");
break;
default:
break;
}
}
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(TAG, "Ethernet Got IP Address");
ESP_LOGI(TAG, "~~~~~~~~~~~");
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
ESP_LOGI(TAG, "~~~~~~~~~~~");
IP_ADDRESS[0] = esp_ip4_addr_get_byte(&event->ip_info.ip, 0);
IP_ADDRESS[1] = esp_ip4_addr_get_byte(&event->ip_info.ip, 1);
IP_ADDRESS[2] = esp_ip4_addr_get_byte(&event->ip_info.ip, 2);
IP_ADDRESS[3] = esp_ip4_addr_get_byte(&event->ip_info.ip, 3);
}
esp_err_t uros_network_interface_initialize(void)
{
// Initialize TCP/IP network interface (should be called only once in application)
ESP_ERROR_CHECK(esp_netif_init());
// Create default event loop that running in background
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&cfg);
// Set default handlers to process TCP/IP stuffs
//ESP_ERROR_CHECK(esp_eth_set_default_handlers(eth_netif));
// Register user defined event handers
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = CONFIG_MICRO_ROS_ETH_PHY_ADDR;
phy_config.reset_gpio_num = CONFIG_MICRO_ROS_ETH_PHY_RST_GPIO;
#if CONFIG_MICRO_ROS_USE_INTERNAL_ETHERNET
// Init MAC and PHY configs to default
eth_esp32_emac_config_t emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
mac_config.sw_reset_timeout_ms = 250; // Needed for some ethernet controllers to initiate
emac_config.smi_mdc_gpio_num = CONFIG_MICRO_ROS_ETH_MDC_GPIO;
emac_config.smi_mdio_gpio_num = CONFIG_MICRO_ROS_ETH_MDIO_GPIO;
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&emac_config, &mac_config);
#if CONFIG_MICRO_ROS_ETH_PHY_IP101
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
#elif CONFIG_MICRO_ROS_ETH_PHY_RTL8201
esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config);
#elif CONFIG_MICRO_ROS_ETH_PHY_LAN8720
esp_eth_phy_t *phy = esp_eth_phy_new_lan87xx(&phy_config);
#elif CONFIG_MICRO_ROS_ETH_PHY_DP83848
esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
#elif CONFIG_MICRO_ROS_ETH_PHY_KSZ8041
esp_eth_phy_t *phy = esp_eth_phy_new_ksz8041(&phy_config);
#endif
#elif CONFIG_ETH_USE_SPI_ETHERNET
gpio_install_isr_service(0);
spi_device_handle_t spi_handle = NULL;
spi_bus_config_t buscfg = {
.miso_io_num = CONFIG_MICRO_ROS_ETH_SPI_MISO_GPIO,
.mosi_io_num = CONFIG_MICRO_ROS_ETH_SPI_MOSI_GPIO,
.sclk_io_num = CONFIG_MICRO_ROS_ETH_SPI_SCLK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
};
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_MICRO_ROS_ETH_SPI_HOST, &buscfg, 1));
#if CONFIG_MICRO_ROS_USE_DM9051
spi_device_interface_config_t devcfg = {
.command_bits = 1,
.address_bits = 7,
.mode = 0,
.clock_speed_hz = CONFIG_MICRO_ROS_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
.spics_io_num = CONFIG_MICRO_ROS_ETH_SPI_CS_GPIO,
.queue_size = 20
};
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_MICRO_ROS_ETH_SPI_HOST, &devcfg, &spi_handle));
/* dm9051 ethernet driver is based on spi driver */
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
dm9051_config.int_gpio_num = CONFIG_MICRO_ROS_ETH_SPI_INT_GPIO;
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
#elif CONFIG_MICRO_ROS_USE_W5500
spi_device_interface_config_t devcfg = {
.command_bits = 16, // Actually it's the address phase in W5500 SPI frame
.address_bits = 8, // Actually it's the control phase in W5500 SPI frame
.mode = 0,
.clock_speed_hz = CONFIG_MICRO_ROS_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
.spics_io_num = CONFIG_MICRO_ROS_ETH_SPI_CS_GPIO,
.queue_size = 20
};
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_MICRO_ROS_ETH_SPI_HOST, &devcfg, &spi_handle));
/* w5500 ethernet driver is based on spi driver */
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
w5500_config.int_gpio_num = CONFIG_MICRO_ROS_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);
#endif
#endif // CONFIG_ETH_USE_SPI_ETHERNET
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
ESP_ERROR_CHECK(esp_eth_driver_install(&config, ð_handle));
#if CONFIG_ETH_USE_SPI_ETHERNET
/* The SPI Ethernet module might doesn't have a burned factory MAC address, we cat to set it manually.
02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control.
*/
ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, (uint8_t[]) {
0x02, 0x00, 0x00, 0x12, 0x34, 0x56
}));
#endif
/* attach Ethernet driver to TCP/IP stack */
ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)));
/* start Ethernet driver state machine */
ESP_ERROR_CHECK(esp_eth_start(eth_handle));
return ESP_OK;
}
#endif
@uLipe, regarding compatibility with version 4.4, we might not necessarily need to break compatibility. One approach could be parsing the CONFIG_IDF_INIT_VERSION and checking if the ASCII value of the first character is greater than 52. This way, we could differentiate between versions 4 and beyond, enabling us to handle compatibility gracefully.
Issue template
Steps to reproduce the issue
Create a new project using the pub/sub example. Configure project to use W5500
Expected behavior
Code compiles and is able to run on the ESP32
Actual behavior
I instead get the following when compling:
Additional information
Only change to the basic component it to allow pin 35 to be selected for MISO.