From 07ab7286ba8ea492ce3c6181633b207690ccd119 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Sat, 28 Sep 2024 19:48:11 +0800 Subject: [PATCH] STM32 Ethernet support --- EthernetInterface.cpp | 128 +++++++++++++++++++++++++----------------- EthernetInterface.h | 9 ++- I2CManager_STM32.h | 5 +- MotorDrivers.h | 10 +++- platformio.ini | 55 ++++++++++-------- version.h | 5 +- 6 files changed, 133 insertions(+), 79 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index c88a766..f8306cb 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -1,8 +1,10 @@ /* + * © 2024 Morten "Doc" Nielsen + * © 2023-2024 Paul M. Antoine * © 2022 Bruno Sanches * © 2021 Fred Decker * © 2020-2022 Harald Barth - * © 2020-2021 Chris Harlow + * © 2020-2024 Chris Harlow * © 2020 Gregor Baues * All rights reserved. * @@ -36,9 +38,14 @@ MDNS mdns(udp); #endif + +//extern void looptimer(unsigned long timeout, const FSH* message); +#define looptimer(a,b) + bool EthernetInterface::connected=false; EthernetServer * EthernetInterface::server= nullptr; EthernetClient EthernetInterface::clients[MAX_SOCK_NUM]; // accept up to MAX_SOCK_NUM client connections at the same time; This depends on the chipset used on the Shield +bool EthernetInterface::inUse[MAX_SOCK_NUM]; // accept up to MAX_SOCK_NUM client connections at the same time; This depends on the chipset used on the Shield uint8_t EthernetInterface::buffer[MAX_ETH_BUFFER+1]; // buffer used by TCP for the recv RingStream * EthernetInterface::outboundRing = nullptr; @@ -47,12 +54,13 @@ RingStream * EthernetInterface::outboundRing = nullptr; * */ -void EthernetInterface::setup() // STM32 VERSION +void EthernetInterface::setup() { - DIAG(F("Ethernet begin" + DIAG(F("Ethernet starting" #ifdef DO_MDNS - " with mDNS" + " (with mDNS)" #endif + " Please be patient, especially if no cable is connected!" )); #ifdef STM32_ETHERNET @@ -116,6 +124,47 @@ void EthernetInterface::setup() // STM32 VERSION connected=true; } +#if defined (STM32_ETHERNET) +void EthernetInterface::acceptClient() { // STM32 version + auto client=server->available(); + if (!client) return; + // check for existing client + for (byte socket = 0; socket < MAX_SOCK_NUM; socket++) + if (inUse[socket] && client == clients[socket]) return; + + // new client + for (byte socket = 0; socket < MAX_SOCK_NUM; socket++) + { + if (!inUse[socket]) + { + clients[socket] = client; + inUse[socket]=true; + if (Diag::ETHERNET) + DIAG(F("Ethernet: New client socket %d"), socket); + return; + } + } + DIAG(F("Ethernet OVERFLOW")); +} +#else +void EthernetInterface::acceptClient() { // non-STM32 version + auto client=server->accept(); + if (!client) return; + auto socket=client.getSocketNumber(); + clients[socket]=client; + inUse[socket]=true; + if (Diag::ETHERNET) + DIAG(F("Ethernet: New client socket %d"), socket); +} +#endif + +void EthernetInterface::dropClient(byte socket) +{ + clients[socket].stop(); + inUse[socket]=false; + CommandDistributor::forget(socket); + if (Diag::ETHERNET) DIAG(F("Ethernet: Disconnect %d "), socket); +} /** * @brief Main loop for the EthernetInterface @@ -124,7 +173,8 @@ void EthernetInterface::setup() // STM32 VERSION void EthernetInterface::loop() { if (!connected) return; - + looptimer(5000, F("E.loop")); + static bool warnedAboutLink=false; if (Ethernet.linkStatus() == LinkOFF){ if (warnedAboutLink) return; @@ -132,7 +182,8 @@ void EthernetInterface::loop() warnedAboutLink=true; return; } - + looptimer(5000, F("E.loop warn")); + // link status must be ok here if (warnedAboutLink) { DIAG(F("Ethernet link RESTORED")); @@ -142,6 +193,8 @@ void EthernetInterface::loop() #ifdef DO_MDNS // Always do this because we don't want traffic to intefere with being found! mdns.run(); + looptimer(5000, F("E.mdns")); + #endif // @@ -161,50 +214,22 @@ void EthernetInterface::loop() //DIAG(F("maintained")); break; } + looptimer(5000, F("E.maintain")); + + // get client from the server + acceptClient(); - // get client from the server - #if defined (STM32_ETHERNET) - // STM32Ethernet doesn't use accept(), just available() - auto client = server->available(); - if (client) { - // check for new client - byte socket; - bool sockfound = false; - for (socket = 0; socket < MAX_SOCK_NUM; socket++) - { - if (client == clients[socket]) - { - sockfound = true; - break; - } - } - if (!sockfound) - { // new client - for (socket = 0; socket < MAX_SOCK_NUM; socket++) - { - if (!clients[socket]) - { - clients[socket] = client; - sockfound=true; - if (Diag::ETHERNET) - DIAG(F("Ethernet: New client socket %d"), socket); - break; - } - } - } - if (!sockfound) DIAG(F("new Ethernet OVERFLOW")); - } - - #else - auto client = server->accept(); - if (client) clients[client.getSocketNumber()]=client; - #endif - + // handle disconnected sockets because STM32 library doesnt + // do the read==0 response. + for (byte socket = 0; socket < MAX_SOCK_NUM; socket++) + { + if (inUse[socket] && !clients[socket].connected()) dropClient(socket); + } // check for incoming data from all possible clients for (byte socket = 0; socket < MAX_SOCK_NUM; socket++) { - if (!clients[socket]) continue; // socket is not in use + if (!inUse[socket]) continue; // socket is not in use // read any bytes from this client auto count = clients[socket].read(buffer, MAX_ETH_BUFFER); @@ -216,14 +241,13 @@ void EthernetInterface::loop() if (Diag::ETHERNET) DIAG(F("Ethernet s=%d, c=%d b=:%e"), socket, count, buffer); // execute with data going directly back CommandDistributor::parse(socket,buffer,outboundRing); + //looptimer(5000, F("Ethloop2 parse")); return; // limit the amount of processing that takes place within 1 loop() cycle. } // count=0 The client has disconnected - clients[socket].stop(); - CommandDistributor::forget(socket); - if (Diag::ETHERNET) DIAG(F("Ethernet: disconnect %d "), socket); - } + dropClient(socket); + } WiThrottle::loop(outboundRing); @@ -245,9 +269,11 @@ void EthernetInterface::loop() tmpbuf[i] = outboundRing->read(); } tmpbuf[count]=0; - if (Diag::ETHERNET) DIAG(F("Ethernet reply s=%d, c=%d, b:%e"), + if (inUse[socketOut]) { + if (Diag::ETHERNET) DIAG(F("Ethernet reply s=%d, c=%d, b:%e"), socketOut,count,tmpbuf); - clients[socketOut].write(tmpbuf,count); + clients[socketOut].write(tmpbuf,count); + } } } diff --git a/EthernetInterface.h b/EthernetInterface.h index 9ea2718..16156fa 100644 --- a/EthernetInterface.h +++ b/EthernetInterface.h @@ -1,8 +1,10 @@ /* + * © 2023-2024 Paul M. Antoine * © 2021 Neil McKechnie * © 2021 Mike S * © 2021 Fred Decker - * © 2020-2021 Chris Harlow + * © 2020-2022 Harald Barth + * © 2020-2024 Chris Harlow * © 2020 Gregor Baues * All rights reserved. * @@ -35,6 +37,7 @@ #if defined (ARDUINO_TEENSY41) #include //TEENSY Ethernet Treiber #include + #define MAX_SOCK_NUM 4 #elif defined (ARDUINO_NUCLEO_F429ZI) || defined (ARDUINO_NUCLEO_F439ZI) || defined (ARDUINO_NUCLEO_F4X9ZI) #include // #include "STM32lwipopts.h" @@ -67,8 +70,12 @@ class EthernetInterface { static bool connected; static EthernetServer * server; static EthernetClient clients[MAX_SOCK_NUM]; // accept up to MAX_SOCK_NUM client connections at the same time; This depends on the chipset used on the Shield + static bool inUse[MAX_SOCK_NUM]; // accept up to MAX_SOCK_NUM client connections at the same time; This depends on the chipset used on the Shield static uint8_t buffer[MAX_ETH_BUFFER+1]; // buffer used by TCP for the recv static RingStream * outboundRing; + static void acceptClient(); + static void dropClient(byte socketnum); + }; #endif diff --git a/I2CManager_STM32.h b/I2CManager_STM32.h index 7e9e63e..109c89b 100644 --- a/I2CManager_STM32.h +++ b/I2CManager_STM32.h @@ -38,8 +38,9 @@ *****************************************************************************/ #if defined(I2C_USE_INTERRUPTS) && defined(ARDUINO_ARCH_STM32) #if defined(ARDUINO_NUCLEO_F401RE) || defined(ARDUINO_NUCLEO_F411RE) || defined(ARDUINO_NUCLEO_F446RE) \ - || defined(ARDUINO_NUCLEO_F412ZG) || defined(ARDUINO_NUCLEO_F413ZH) \ - || defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F446ZE) + || defined(ARDUINO_NUCLEO_F412ZG) || defined(ARDUINO_NUCLEO_F413ZH) || defined(ARDUINO_NUCLEO_F446ZE) \ + || defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F439ZI) || defined(ARDUINO_NUCLEO_F4X9ZI) + // Assume I2C1 for now - default I2C bus on Nucleo-F411RE and likely all Nucleo-64 // and Nucleo-144 variants I2C_TypeDef *s = I2C1; diff --git a/MotorDrivers.h b/MotorDrivers.h index d51ab16..defbfd4 100644 --- a/MotorDrivers.h +++ b/MotorDrivers.h @@ -75,11 +75,19 @@ #define SAMD_STANDARD_MOTOR_SHIELD STANDARD_MOTOR_SHIELD #define STM32_STANDARD_MOTOR_SHIELD STANDARD_MOTOR_SHIELD +#if defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F439ZI) || defined(ARDUINO_NUCLEO_F4X9ZI) +// EX 8874 based shield connected to a 3V3 system with 12-bit (4096) ADC +// The Ethernet capable STM32 models cannot use Channel B BRAKE on D8, and must use the ALT pin of D6, +// AND cannot use Channel B PWN on D11, but must use the ALT pin of D5 +#define EX8874_SHIELD F("EX8874"), \ + new MotorDriver( 3, 12, UNUSED_PIN, 9, A0, 1.27, 5000, A4), \ + new MotorDriver( 5, 13, UNUSED_PIN, 6, A1, 1.27, 5000, A5) +#else // EX 8874 based shield connected to a 3V3 system with 12-bit (4096) ADC #define EX8874_SHIELD F("EX8874"), \ new MotorDriver( 3, 12, UNUSED_PIN, 9, A0, 1.27, 5000, A4), \ new MotorDriver(11, 13, UNUSED_PIN, 8, A1, 1.27, 5000, A5) - +#endif #elif defined(ARDUINO_ARCH_ESP32) // STANDARD shield on an ESPDUINO-32 (ESP32 in Uno form factor). The shield must be eiter the diff --git a/platformio.ini b/platformio.ini index 2de9bed..6317372 100644 --- a/platformio.ini +++ b/platformio.ini @@ -202,7 +202,7 @@ monitor_speed = 115200 monitor_echo = yes [env:Nucleo-F411RE] -platform = ststm32 +platform = ststm32 @ 17.6.0 board = nucleo_f411re framework = arduino lib_deps = ${env.lib_deps} @@ -211,7 +211,7 @@ monitor_speed = 115200 monitor_echo = yes [env:Nucleo-F446RE] -platform = ststm32 +platform = ststm32 @ 17.6.0 board = nucleo_f446re framework = arduino lib_deps = ${env.lib_deps} @@ -223,7 +223,7 @@ monitor_echo = yes ; tested as yet ; [env:Nucleo-F401RE] -platform = ststm32 +platform = ststm32 @ 17.6.0 board = nucleo_f401re framework = arduino lib_deps = ${env.lib_deps} @@ -236,7 +236,7 @@ monitor_echo = yes ; installed before you can let PlatformIO see this ; ; [env:Nucleo-F413ZH] -; platform = ststm32 +; platform = ststm32 @ 17.6.0 ; board = nucleo_f413zh ; framework = arduino ; lib_deps = ${env.lib_deps} @@ -248,7 +248,7 @@ monitor_echo = yes ; installed before you can let PlatformIO see this ; [env:Nucleo-F446ZE] -platform = ststm32 +platform = ststm32 @ 17.6.0 board = nucleo_f446ze framework = arduino lib_deps = ${env.lib_deps} @@ -260,8 +260,8 @@ monitor_echo = yes ; installed before you can let PlatformIO see this ; ; [env:Nucleo-F412ZG] -; platform = ststm32 -; board = blah_f412zg +; platform = ststm32 @ 17.6.0 +; board = nucleo_f412zg ; framework = arduino ; lib_deps = ${env.lib_deps} ; build_flags = -std=c++17 -Os -g2 -Wunused-variable @@ -272,12 +272,12 @@ monitor_echo = yes ; Experimental - Ethernet work still in progress ; [env:Nucleo-F429ZI] -platform = ststm32 +platform = ststm32 @ 17.6.0 board = nucleo_f429zi framework = arduino lib_deps = ${env.lib_deps} - stm32duino/STM32Ethernet @ ^1.3.0 - stm32duino/STM32duino LwIP @ ^2.1.2 + stm32duino/STM32Ethernet @ ^1.4.0 + stm32duino/STM32duino LwIP @ ^2.1.3 MDNS_Generic lib_ignore = WiFi101 WiFi101_Generic @@ -289,18 +289,29 @@ monitor_speed = 115200 monitor_echo = yes upload_protocol = stlink -; [env:Nucleo-F429ZI] -; platform = ststm32 -; board = nucleo_f429zi -; framework = arduino -; lib_deps = ${env.lib_deps} -; arduino-libraries/Ethernet @ ^2.0.1 -; stm32duino/STM32Ethernet @ ^1.3.0 -; stm32duino/STM32duino LwIP @ ^2.1.2 -; build_flags = -std=c++17 -Os -g2 -Wunused-variable -; monitor_speed = 115200 -; monitor_echo = yes -; upload_protocol = stlink +; Experimental - Ethernet work still in progress +; +[env:Nucleo-F439ZI] +platform = ststm32 @ 17.6.0 +; board = nucleo_f439zi +; Temporarily treat it as an F429ZI (they are code compatible) until +; the PR to PlatformIO to update the F439ZI JSON file is available +; PMA - 28-Sep-2024 +board = nucleo_f429zi +framework = arduino +lib_deps = ${env.lib_deps} + stm32duino/STM32Ethernet @ ^1.4.0 + stm32duino/STM32duino LwIP @ ^2.1.3 + MDNS_Generic +lib_ignore = WiFi101 + WiFi101_Generic + WiFiEspAT + WiFiMulti_Generic + WiFiNINA_Generic +build_flags = -std=c++17 -Os -g2 -Wunused-variable +monitor_speed = 115200 +monitor_echo = yes +upload_protocol = stlink [env:Teensy3_2] platform = teensy diff --git a/version.h b/version.h index 36c07c7..269e47d 100644 --- a/version.h +++ b/version.h @@ -3,8 +3,9 @@ #include "StringFormatter.h" -#define VERSION "5.2.80" -// 5.2.80 - EthernetInterface upgrade +#define VERSION "5.2.81" +// 5.2.81 - STM32 Ethernet boards support, also now have specific EX8874 motor driver definition +// 5.2.80 - EthernetInterface upgrade, including STM32 Ethernet support // 5.2.79 - serial manager loop that handles quoted strings // - WiFiESP32 reconfig // 5.2.78 - NeoPixel support.