From 0cb2ea05f5228530f688a4635d6dd11f5effa477 Mon Sep 17 00:00:00 2001 From: M256-Automation <76175329+M256-Automation@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:12:50 +0200 Subject: [PATCH 1/2] Olimex ESP32-POE-ISO support --- examples/slaveinfo/slaveinfo.ino | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/examples/slaveinfo/slaveinfo.ino b/examples/slaveinfo/slaveinfo.ino index eb2166d..f94cb17 100644 --- a/examples/slaveinfo/slaveinfo.ino +++ b/examples/slaveinfo/slaveinfo.ino @@ -16,6 +16,18 @@ #include +// ESP32 boards with internal EMAC (e.g. Olimex ESP32-POE-ISO) need the ETH +// stack brought up in setup() before ec_init() can open the HAL. The event +// flag lets setup() block until the PHY reports link-up without any busy-wait +// in the SOEM layer itself. +#if defined(ARDUINO_ESP32_POE_ISO) || defined(ARDUINO_ESP32_POE) || defined(SOEM_INTERNAL_ETH) +#include +static volatile bool eth_ready = false; +static void onEthEvent(arduino_event_id_t e) { + if (e == ARDUINO_EVENT_ETH_CONNECTED) eth_ready = true; +} +#endif + char IOmap[4096]; ec_ODlistt ODlist; ec_OElistt OElist; @@ -657,6 +669,15 @@ void app_loop() void setup() { Serial.begin(115200); +// On ESP32 boards with internal EMAC the ETH stack must be started here so +// the PHY is powered and the link is up before the first ec_init() call. +// ETH_PHY_* constants come from the board's pins_arduino.h (e.g. Olimex +// ESP32-POE-ISO sets ETH_PHY_POWER=12 and ETH_CLK_MODE=ETH_CLOCK_GPIO17_OUT). +#if defined(ARDUINO_ESP32_POE_ISO) || defined(ARDUINO_ESP32_POE) || defined(SOEM_INTERNAL_ETH) + Network.onEvent(onEthEvent); + ETH.begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_POWER, ETH_CLK_MODE); + while (!eth_ready) delay(10); +#endif } void loop() From 9aabf6a7a2541c4467c56ece8cac3a139fef0c59 Mon Sep 17 00:00:00 2001 From: M256-Automation <76175329+M256-Automation@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:13:34 +0200 Subject: [PATCH 2/2] Olimex ESP32-POE-ISO support --- src/SOEM.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/SOEM.cpp b/src/SOEM.cpp index c46a69a..3e74290 100644 --- a/src/SOEM.cpp +++ b/src/SOEM.cpp @@ -352,6 +352,83 @@ void hal_ethernet_recv_rel(void) } #endif +#elif defined(ARDUINO_ESP32_POE_ISO) || \ + defined(ARDUINO_ESP32_POE) || \ + defined(SOEM_INTERNAL_ETH) +/************************************************** + for ESP32 with internal EMAC (e.g. Olimex ESP32-POE-ISO) + ETH must be initialised in setup() before ec_init() is called. +**************************************************/ + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "esp_eth.h" + +#define HAL_RX_QSIZE 4 +static esp_eth_handle_t s_eth = NULL; +static QueueHandle_t s_rxq = NULL; +struct HalRxFrame { uint8_t *buf; uint32_t len; }; +static unsigned char s_rx_static[1536]; + +static esp_err_t s_rx_cb(esp_eth_handle_t, uint8_t *buf, uint32_t len, void*) +{ + uint8_t *copy = (uint8_t*)malloc(len); + if (copy) { + memcpy(copy, buf, len); + HalRxFrame f = {copy, len}; + xQueueSend(s_rxq, &f, 0); + } + free(buf); + return ESP_OK; +} + +#ifdef __cplusplus +extern "C" { +#endif + +int hal_ethernet_open(void) +{ + if (s_eth) return 0; + if (!s_rxq) { s_rxq = xQueueCreate(HAL_RX_QSIZE, sizeof(HalRxFrame)); if (!s_rxq) return -1; } + s_eth = ETH.handle(); + if (!s_eth) return -2; + if (!ETH.linkUp()) return -3; + esp_eth_update_input_path(s_eth, s_rx_cb, NULL); + return 0; +} + +void hal_ethernet_close(void) +{ + s_eth = NULL; // allow re-open after ec_close() + ec_init() +} + +int hal_ethernet_send(unsigned char *data, int len) +{ + if (!s_eth) return -1; + return (esp_eth_transmit(s_eth, data, (size_t)len) == ESP_OK) ? 0 : -1; +} + +int hal_ethernet_recv(unsigned char **data) +{ + if (!s_rxq) return 0; + HalRxFrame f; + if (xQueueReceive(s_rxq, &f, 0) == pdTRUE) { + uint32_t len = (f.len < sizeof(s_rx_static)) ? f.len : sizeof(s_rx_static); + memcpy(s_rx_static, f.buf, len); + free(f.buf); + *data = s_rx_static; + return (int)len; + } + return 0; +} + +void hal_ethernet_recv_rel(void) {} + +#ifdef __cplusplus +} +#endif + #else /************************************************** for Ethernet Shield (W5500)