Ethernet interface for MCU - Page 1
Forum section: electronics / general

author: ulix
author_rank: Regular Contributor
timestamp: January 01, 2025, 06:17:46 pm
content: Hi Everyone,I’m planning to transfer some data captured with an MSP430 MCU via LAN. Does anyone have any recommendations for modules to get started with LAN communication? I’ve seen a lot of ENC28J60 modules on AliExpress, but it seems that this chip is quite unreliable and buggy. Do any forum members have other or better recommendations?Thanks a lot!

author: Siwastaja
author_rank: Super Contributor
timestamp: January 01, 2025, 06:21:23 pm
content: Wiznet (W5500, W6100) is The Easy Way and pretty good. Additionally to Ethernet MAC+PHY, it integrates TCP, IP, UDP and ARP on-chip, you need software implementations for DHCP and DNS if you need them, but they do have (seriously buggy, of course, but that's part of the deal) examples you can use.Time-to-product was not too bad, and probably easier than trying to integrate lwip for example.Compared to that, ENC28J60 only is MAC/PHY, so you need full TCP/IP software implementation if you want that.What protocols are you expecting to use?

author: coppice
author_rank: Super Contributor
timestamp: January 01, 2025, 06:24:14 pm
content: Is the chip really buggy, or is there just a lot of buggy software trying to use it? I have no experience with this part, but I do have a lot of experience of people complaining about buggy hardware in the MCU world that is actually a buggy software problem. That said, there are plenty of real hardware bugs in the MCU world that never get fixed.

author: nctnico
author_rank: Super Contributor
timestamp: January 01, 2025, 06:29:18 pm
content: I strongly second the suggestion for the W5500 or W6100 (the latter also supporting IPv6). Life just doesn't get any easier. The ENC28J60 supports 10Mbit only which might not even be supported by switches in the very near future. 100Mbit/s is also deemed obsolete and not all ethernet equipment supports 100Mbit/s these days, let alone 10Mbit/s.

author: phil from seattle
author_rank: Super Contributor
timestamp: January 01, 2025, 07:02:38 pm
content: Another vote for the W5500. You can get complete modules that run off of SPI and a couple of extra pins. WIZ820io is a nice compact version that I have used a number of times. $5 or less from China. $8ish on Amazon in the US. Probably similar in the EU.

author: coppice
author_rank: Super Contributor
timestamp: January 01, 2025, 08:02:04 pm
content: To experiment quickly with the W6100 there are modules with the W6100 and an RP2040 MCU available from many places now. There appear to be load and go demo projects for that.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: January 01, 2025, 08:05:01 pm
content: +1 for W5500. The thing I could do with them improving is support for longer (fragmented) UDP packets.

author: kripton2035
author_rank: Super Contributor
timestamp: January 01, 2025, 09:56:15 pm
content: https://www.aliexpress.com/item/1005006900921262.htmlESP32 with a LAN8270 on a small pcb, you can use it with arduino code.or a W5500 like others said, mounted on a small pcb with the ethernet plug.https://www.aliexpress.com/item/1005004679288698.html

author: nctnico
author_rank: Super Contributor
timestamp: January 01, 2025, 10:24:09 pm
content: I would be careful with recommending random modules. The W5500 requires a careful PCB layout. It is doable on two layers if you are experienced. Otherwise use or try finding a board / module with 4 layers so power and ground are decoupled properly.

author: ejeffrey
author_rank: Super Contributor
timestamp: January 01, 2025, 11:01:41 pm
content: I don't love having Ethernet or TCP/IP on small micros in the first place, but the wiznet chips are a pretty good way to do it. It's easy to set up and mostly just works.

author: fchk
author_rank: Frequent Contributor
timestamp: January 01, 2025, 11:28:10 pm
content: Quote from: ulix on January 01, 2025, 06:17:46 pmWhy MSP430? This is not an ideal platform for an Ethernet system. You are limited to SPI-NICs (Recommendation: Microchip KSZ8851SNL), these Wiznet chips or external bridges. MSP430 does not have enough RAM for a decent TCP implementation.If you like to stick with TI, my suggestion is:https://www.ti.com/product/TM4C1294NCPDTThere is also a suitable launchpad for this:https://www.ti.com/tool/EK-TM4C1294XLMuch more power, good driver library, and there is still the TI-RTOS you can use.

author: coppice
author_rank: Super Contributor
timestamp: January 02, 2025, 12:01:23 am
content: Quote from: fchk on January 01, 2025, 11:28:10 pmGreat idea. because some random MCU is sure to have the mix of qualities that will suit the OP's application. I assume this is an add on to an existing application, or the MSP430 has just the right peripherals for some particular application.

author: nctnico
author_rank: Super Contributor
timestamp: January 02, 2025, 12:31:26 am
content: Quote from: fchk on January 01, 2025, 11:28:10 pmActually that is a good thing! Running a TCP stack on a microcontroller is far from ideal. Even with a RTOS. I've been around the block a couple of times (including using Lwip) and the Wiznet chips are a really good solution. The BOM cost and part count don't increase (the Wiznet chips are cheaper from Digikey compared to the KSZ8851SNL) but the R&D time gets a massive reduction.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: January 02, 2025, 12:43:41 am
content: BTW with the W5500 use a proper crystal oscillator, not a MEMS one - took me a couple of days to figure out why I was losing about 1% of receive packets.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: January 02, 2025, 01:58:40 am
content: There's also the CH390 from WCH -SPI or parallel port versions, internal unique MAC address, but no protocols built in. UDP ought to be easy enough - I don't know if they supply a software stack for it.Parallel I/F might be useful if you need something faster than the W5500, and it comes in smaller package options like DFN20.

author: woofy
author_rank: Frequent Contributor
timestamp: January 02, 2025, 09:14:36 am
content: I've kinda used the ENC28J60 in the past, its the same peripheral built in to the PIC18F67J60. Its ok but very old now, and its 10BASE-T only.If your not absolutely stuck on the MPS430 then STM32+Mongoose is an easy way in.

author: tellurium
author_rank: Frequent Contributor
timestamp: January 03, 2025, 12:10:00 pm
content: Quote from: nctnico on January 02, 2025, 12:31:26 amWhat's wrong with running TCP stack on a micro?Here's Arduino Nano every, 8-bit, 6k RAM, 48k flash, running simple web server and MQTT client.The stack is in software, using W5500 as ethernet frame sender/receiver.

author: qqclient
author_rank: Newbie
timestamp: January 03, 2025, 04:36:45 pm
content: have fun with CH32V307, CH32V208, CH579M, cost effective RISC-V or cortexM core MCU with Ethernet MAC+PHY and ,for more, there are many examples, which style is similar to the STM standard lib, thats whats important.

author: nctnico
author_rank: Super Contributor
timestamp: January 03, 2025, 07:58:46 pm
content: Quote from: tellurium on January 03, 2025, 12:10:00 pmThe part you cut away. Life gets a lot easier if you don't have to deal with ethernet packets coming in at random points in time in unspecified quantities. And hackers are quite crafty so having a dedicated chip in between which isolates your own code (which might do something safety related) from anything which deals with the network directly is a bonus.QuoteI did far more with less 20 odd years ago. I get that you want to push your Mongoose product but frankly I'd go with Lwip because that has way more eyes going over it making it a safer bet in terms of security & reliability. But both make me unhappy looking at the source code (example: mapping structs onto void pointers which the compiler might choke on and/or give alignment issues depending on settings) which for me is also a reason to go for a Wiznet chip or similar product by lack of a better alternative.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 04, 2025, 07:54:39 am
content: Quote from: nctnico on January 03, 2025, 07:58:46 pmWell, with Wiznet you can't do that. It does not implement the full basic set of protocols required, and what's worse, the software DNS implementation they supply (that runs on customer MCU) has glaring security holes, for example it overindexes a stack-allocated buffer. You can of course implement or find something safer, but really that's textbook example of "false sense of security": thinking that Wiznet gives you a secure solutioneasilyis dangerous.So, while the idea of isolation is nice in theory, it would need a good implementation, which Wiznet is not. At least with Mongoose/lwip/whatever stack you can evaluate the code, with Wiznet the internal stack is what it is, and probably done by the same guys who did the DNS/DHCP implementations that are pure horror.My excuse for not using Mongoose is that I haven't had time to try it. If it really is as good as tellurium makes it sound like, I would prefer it as a solution over an external locked-down chip. In the meantime, Wiznet chip simplifies my life.

author: nctnico
author_rank: Super Contributor
timestamp: January 04, 2025, 10:20:16 am
content: Quote from: Siwastaja on January 04, 2025, 07:54:39 amNo, you are now going the 'glass half full' road while in reality the glass is still 90% full. The local MCU doesn't need to deal with the TCP / UDP stack and it can fortify the protocols running on top of TCP / UDP. That is a whole lot easier to do compared to analysing every nook and cranny of TCP / UDP protocol stack and dealing with ethernet packets in realtime. Having the source code for a TCP / UDP protocol stack doesn't do you any good as implementing TCP/ UDP correctly and doing the verification is an art in itself. Talking about false sense of securityThere are many pitfalls due to all the features which got bolted on later and various levels of OS interoperability. Been there, done that. There is a very good reason there are so few TCP / UDP stacks out there! The Wiznet chip OTOH does provide a very clear interface between your own code and the network. To the point where I don't care how the Wiznet chips works internally. If the Wiznet chip locks up, just reset it. I still assume that the 'Wiznet' stack itself has been written & tested by people who know what they are doing as this can't be fixed after the chip has been sold. When dealing with code from China I typically see that the base architecture has been designed & implemented by people who know what they are doing but then the junior engineers come in to add / change extra features which are very poorely implemented.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 04, 2025, 10:29:37 am
content: Quote from: nctnico on January 04, 2025, 10:20:16 amNo, just pointing out there is no magic here, and obvious false sense of security. It is true that DHCP+DNS is probably two orders of magnitude easier to do right and verify than the whole stack, but temptation to use readily provided example without verifying it is high, especially given the advice (e.g. in my post above) that using W5500/W6100 is really simple.Besides, separation alone isn't nearly a sufficient level of protection. If the chip offered TLS,thenthat would be pretty significant, but because it does not, attacker can still use malformed payloads to trigger bugs in firmware. The attack surface is smaller, but not by orders of magnitude.For a complete safe and secure implementation, you are still at mercy of libraries like mbedTLS, integrating them right, and doing your own code right. I claim that Wiznet chip does not offersignificantimprovement in time-to-market. If it feels like it does, you are very likely overlooking something and relying on the false sense of security it offers.

author: nctnico
author_rank: Super Contributor
timestamp: January 04, 2025, 10:47:04 am
content: Have you tried using Lwip? I have and I can assure you that dealing with the Wiznet chip is easier and saves lots of time.Using TLS opens up another can of worms as you will want to use a pre-emptive multitasking RTOS. Processing the keys during connection initialisation takes such a long time that your criticial tasks will be starved long before if you are using a single threaded super-loop / round robin scheduler. I have done some work on that as well in the past but realistically, if you application needs TLS, then you also need to be able to do firmware (security) updates as well. All in all, I'm not so sure a standard microcontroller is a good choice if you need TLS. I'd either run Linux or use a VPN router.

author: Karel
author_rank: Super Contributor
timestamp: January 04, 2025, 10:57:37 am
content: Quote from: ulix on January 01, 2025, 06:17:46 pmI would use a Raspberry Pi as an " ethernet module".Much easier to deal with and it's much more secure and stable.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 04, 2025, 01:05:24 pm
content: Quote from: nctnico on January 04, 2025, 10:47:04 amMaybe you do, maybe not. For the current project I chose not to, and it has scaled up just fine even beyond initial expectations. That's because since I discovered how handy ARM pre-emptive prioritized interrupts are some 10 years ago, I have transitioned into fully interrupt-driven designs with normally empty while(1) loop (or calls to put CPU in sleep when power matters), basically wasting the "main thread" and running everything in interrupt context, triggered by timers or peripheral events. This has worked for me really well, and in TLS/Wiznet design currently I utilized that otherwise wasted main thread so that it handles networking and can deal with the blocking calls to existing networking code (e.g. mbedtls).But I recognize it does not work for everyone, and addinganotherlayer of blocking calls (concurrently to blocking networking calls) is not possible without adding an OS with a task scheduler. Then again, adding an OS is not a big deal, I just prefer not having it when I can survive without.

author: nctnico
author_rank: Super Contributor
timestamp: January 04, 2025, 01:08:16 pm
content: That is another way of doing things (which I have promoted several times before) as the interrupt controller is essentially a pre-emptive task scheduler.

author: tellurium
author_rank: Frequent Contributor
timestamp: January 04, 2025, 05:19:09 pm
content: Quote from: Siwastaja on January 04, 2025, 01:05:24 pmIt is debatable what calls are "blocking". It is possible to make a TLS-enabled application totally non-blocking (i.e. no blocking IO functions) , it's just verification routines during the TLS handshake could be damn slow, so the app will be stuck for a long time in a slow crypto function (but not waiting for some condition, as usually blocking functions do).For example, a non-tuned mbedTLS example shipped with Cube gives ~2.7 seconds handshake time on STM32F756 board. A non-tuned Zephyr example on the same board gives ~4.2 seconds (also uses mbedTLS, but Zephyr's stack instead of LWIP). Mongoose on the same board gives ~0.4 seconds handshake time (Mongoose built-in TCP/IP and TLS). See this TLS explainer video for details:All these are too slow, so yeah, either an interrupt - based code would be needed, or an RTOS . Both solutions use interrupts to preempt CPU that is executing a long and expensive crypto function.

author: ulix
author_rank: Regular Contributor
timestamp: January 07, 2025, 03:56:06 pm
content: Thank you to everyone for their contributions to my question. I had already looked at the W5500, but I was not familiar with Wiznet. I will be getting some modules from them.

author: tellurium
author_rank: Frequent Contributor
timestamp: January 07, 2025, 07:39:12 pm
content: Quote from: ulix on January 07, 2025, 03:56:06 pmI have used W5500 modules produced by Wiznet (so both W5500 chip and the module are by Wiznet), sourced from mouser and digikey:https://eu.mouser.com/ProductDetail/WIZnet/WIZ850io?qs=W0yvOO0ixfFLSlENQWBCKg%3D%3DThey are quite pricey (even more expensive than their rpi pico devboards with integrated w5500)And also I've used Aliexpress clones of the aforementioned modules (around 4 bucks or less), e.g.https://www.aliexpress.com/item/1005006942624924.htmlAnd Wiznet's devboards with integrated W5500, both rp2040 and rp2350:https://eu.mouser.com/ProductDetail/WIZnet/W5500-EVB-Pico2?qs=iLKYxzqNS77FKgrqfXqzIQ%3D%3Dhttps://eu.mouser.com/ProductDetail/WIZnet/W5500-EVB-PICO?qs=t7xnP681wgXCanyLhrM3cQ%3D%3D

author: peter-h
author_rank: Super Contributor
timestamp: January 07, 2025, 08:37:21 pm
content: But surely the OP is just doing something like reading remotely located electricity meters. He is not (I hope) building remotely controlled electricity substations in UkraineHe could just use UDP and a very simple custom protocol. Very likely he can afford to lose some data. TCP gives you error correction and implicit flow control but if there is an actual wire break etc that won't help.TLS (X509) is a massively complicated way to get security, and in the self signed cert business (implicit in mass production) it doesn't get you much more than a simple shared key setup.But "capture via LAN" means a lot of things. If you want to use a modern browser then your customer (being an internet security expert) may "need" TLS. But you probably still can't avoid browser warnings. For now, plain HTTP works... but there are other ways to do this. If you can assemble the retrieving end, it can be much simpler.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 08, 2025, 10:45:26 am
content: Well of course if the data is not sensitive in itself, the device can't do much harm even if broken into, then why indeed add security if it's not needed.And UDP is really fine, added benefit is that it's packetized so generating and parsing it is much simpler. You don't have to sync to a stream of bytes. If you take care of lost packets by just periodically sending new values (and losing some does not matter), then no point in using TCP.

author: peter-h
author_rank: Super Contributor
timestamp: January 08, 2025, 04:26:24 pm
content: Just picking up this older pointQuoteand how true this is. On my product I had a whole lot of fun with MbedTLS blocking various things, even though FreeRTOS is pre-emptive. It turned out to be peripheral stuff e.g. TLS was walking through the certificates in cacert.pem, one by one, which (even with a 21MHz SPI FLASH FAT12 FatFS file system) was taking quite some time, plus the software implementations of RSA or EC not being exactly fast (the 32F4 has hardware AES, but nothing else what's useful (it has DES/3DES). I had to mutex the FLASH API (obviously) but also separately had to mutex around TLS so the HTTP server (which runs on top of LWIP's netconn API) was blocked during TLS, which takes roughly 3 seconds (168MHz).How do you get say 3 secs down to 0.4 sec? I watched your whole video but - apart from marketing Mongoose- it doesn't say how. Is there some super fast EC algorithm? I am not surprised the crypto suites in MbedTLS are perhaps nothing special; I think they basically trawled the internet for what they could find and stuffed it in there. There are so many, they could hardly do anything else. But their software AES256 is not bad, at 800kbytes/sec which is faster than most "IOT" boxes need (the 32F417 hardware AES is much faster).QuoteHow about getting rid of LWIP too and using the 32F4's (etc) ETH controller alone? The solution will be MAC# based and thus not routable but in the right application (wired, with a hub or a switch) it should work.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 08, 2025, 05:24:41 pm
content: Quote from: peter-h on January 08, 2025, 04:26:24 pmUDP/IP is simple enough you can implement it from scratch! Same for ARP. I mean, I did that on hardware (VHDL on FPGA) in a project which had totally different focus, but I needed them for data collection and it was easier to just write them than to try to cobble something together from Opencores or whatever. It was small enough of a diversion that I just did that and it didn't stall the project too much. DHCP would be nice addition though to avoid static IP allocation and that isn't excessively complex either.In any case much simpler than full TCP/IP stack.

author: peter-h
author_rank: Super Contributor
timestamp: January 08, 2025, 06:35:53 pm
content: Yes but you are super clever.For me, it would be a choice between- understanding the ETH interface (basically working out ST's "low level input/output" code, interfacing to LWIP) and using that directly- if one has the above debugged (as I have), using LWIP for UDP, or anything higher upI can see that probably implementing UDP on top of the ETH interface (the Synopsis stuff) is not much more than adding a header onto the ETH packet. If you did it in an FPGA, what ETH controller did you use?

author: coppice
author_rank: Super Contributor
timestamp: January 08, 2025, 06:41:09 pm
content: Quote from: peter-h on January 08, 2025, 06:35:53 pmYou don't need to be super clever. If you only want to handle small UDP packets its basically just a matter of constructing a header and trailer and sending, and analysing a header and trailer and delivering. If you want to handle big packets you have to deal with fragmentation, which pushes up the complexity a fair amount, since things can arrive out of order, even if they seldom do. TCP increases the complexity a lot. However, sticking to small UDP packets does lead to a pretty simple job.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 08, 2025, 06:59:07 pm
content: No, I mean UDP+IPisa really simple protocol. If you are clever enough to set up STM32 ETH peripheral, you most certainly can generate the UDP and IP headers which just contain stuff like destination IP address and port number. No state management, nothing like that. Even a struct containing this metadata and memcpying it on the buffer is enough.Just choose not to support large packets (I think the usual limit is around 1500 bytes) and it's very simple.

author: coppice
author_rank: Super Contributor
timestamp: January 08, 2025, 07:12:22 pm
content: Quote from: Siwastaja on January 08, 2025, 06:59:07 pmI forgot about the separation of UDP and IP. IP just a bit more header and trailer. It adds no real complexity. If you are really RAM constrained, which is often a problem with comms protocols on MCUs, you can limit yourself to something smaller than the normal 1500 byte MTU.

author: peter-h
author_rank: Super Contributor
timestamp: January 08, 2025, 07:12:43 pm
content: OK; I get that. Keep it below the worst case MTU on the LAN; I'd say 1200 bytes to be sure.The interface to the ST ETH subsystem is complex though - unless there is a very simple way of using it for just 1 packet at a time. It runs a linked list of packets.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 08, 2025, 07:21:41 pm
content: Quote from: coppice on January 08, 2025, 07:12:22 pmYou don't need to separate UDP and IP for a simple implementation. Both are just a few header fields, so no need to complicate it by any generic layering idea.The ethernet MAC peripheral in any microcontroller (I admit I have never used STM32's peripheral) would have a RAM buffer of some sort, either DMAing from main memory or a separate piece of memory addressable by the CPU, so you would just directly generate your desired frame there, with the header and trailer and then signal the MAC to send it.For truly easy-to-setup system you would also need ARP but that's still simple. DHCP is already a bit more complex, but if user can deal with static IP addresses then don't do it. On the other hand, then you need some other way than Ethernet to configure the static IP address (e.g., UART or LCD pushbutton interface) which might bemorework than using DHCP to obtain IP address from the router.

author: peter-h
author_rank: Super Contributor
timestamp: January 08, 2025, 07:34:08 pm
content: QuoteOh for surebut the following is just one little bit of it...Code:// ********************************************************************************// Functions extracted from stm32f4xx_hal_eth.c and simplified// The original HAL_BUSY lock mechanism was no good// https://community.st.com/s/question/0D50X0000BOtUflSQF/bug-stm32-lwip-ethernet-driver-rx-deadlockvoid IF_HAL_ETH_TransmitFrame(ETH_HandleTypeDef *heth, uint32_t FrameLength){uint32_t bufcount = 0U, size = 0U, i = 0U;if (FrameLength == 0U){return;}/* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */if(((heth->TxDesc)->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET){return;}/* Get the number of needed Tx buffers for the current frame */if (FrameLength > ETH_TX_BUF_SIZE){bufcount = FrameLength/ETH_TX_BUF_SIZE;if (FrameLength % ETH_TX_BUF_SIZE){bufcount++;}}else{bufcount = 1U;}if (bufcount == 1U){/* Set LAST and FIRST segment */heth->TxDesc->Status |=ETH_DMATXDESC_FS|ETH_DMATXDESC_LS;/* Set frame size */heth->TxDesc->ControlBufferSize = (FrameLength & ETH_DMATXDESC_TBS1);/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA *///__DMB();heth->TxDesc->Status |= ETH_DMATXDESC_OWN;/* Point to next descriptor */heth->TxDesc= (ETH_DMADescTypeDef *)(heth->TxDesc->Buffer2NextDescAddr);}else{for (i=0U; i< bufcount; i++){/* Clear FIRST and LAST segment bits */heth->TxDesc->Status &= ~(ETH_DMATXDESC_FS | ETH_DMATXDESC_LS);if (i == 0U){/* Setting the first segment bit */heth->TxDesc->Status |= ETH_DMATXDESC_FS;}/* Program size */heth->TxDesc->ControlBufferSize = (ETH_TX_BUF_SIZE & ETH_DMATXDESC_TBS1);if (i == (bufcount-1U)){/* Setting the last segment bit */heth->TxDesc->Status |= ETH_DMATXDESC_LS;size = FrameLength - (bufcount-1U)*ETH_TX_BUF_SIZE;heth->TxDesc->ControlBufferSize = (size & ETH_DMATXDESC_TBS1);}/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA *///__DMB();heth->TxDesc->Status |= ETH_DMATXDESC_OWN;/* point to next descriptor *///__DMB();heth->TxDesc = (ETH_DMADescTypeDef *)(heth->TxDesc->Buffer2NextDescAddr);}}/* When Tx Buffer unavailable flag is set: clear it and resume transmission */if (((heth->Instance)->DMASR & ETH_DMASR_TBUS) != (uint32_t)RESET){/* Clear TBUS ETHERNET DMA flag */(heth->Instance)->DMASR = ETH_DMASR_TBUS;/* Resume DMA transmission*///__DMB();(heth->Instance)->DMATPDR = 0U;// Any value issues a descriptor list poll demand.}// Make this function blocking, otherwise following code (very rarely) overwrites// the last DMA buffer!// The reason why the calling code doesn't take care of this is unexplained, but this// hack has no effect on tx speed// Removed 23/7/22 due to// https://community.st.com/s/question/0D73W000001P2M3SAK/detail//if ( (((heth->Instance)->DMASR) & (0x7 << 20)) != 0 ) {}return;}HAL_StatusTypeDef IF_HAL_ETH_GetReceivedFrame(ETH_HandleTypeDef *heth){uint32_t framelength = 0U;/* Check if segment is not owned by DMA *//* if (((heth->RxDesc->Status & ETH_DMARXDESC_OWN) == (uint32_t)RESET) && ((heth->RxDesc->Status & ETH_DMARXDESC_LS) != (uint32_t)RESET)) *///__DMB();if(((heth->RxDesc->Status & ETH_DMARXDESC_OWN) == (uint32_t)RESET)){/* Check if last segment */if(((heth->RxDesc->Status & ETH_DMARXDESC_LS) != (uint32_t)RESET)){/* increment segment count */(heth->RxFrameInfos).SegCount++;/* Check if last segment is first segment: one segment contains the frame */if ((heth->RxFrameInfos).SegCount == 1U){(heth->RxFrameInfos).FSRxDesc =heth->RxDesc;}heth->RxFrameInfos.LSRxDesc = heth->RxDesc;/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */framelength = (((heth->RxDesc)->Status & ETH_DMARXDESC_FL) >> ETH_DMARXDESC_FRAMELENGTHSHIFT) - 4U;heth->RxFrameInfos.length = framelength;/* Get the address of the buffer start address */heth->RxFrameInfos.buffer = ((heth->RxFrameInfos).FSRxDesc)->Buffer1Addr;/* point to next descriptor */heth->RxDesc = (ETH_DMADescTypeDef*) ((heth->RxDesc)->Buffer2NextDescAddr);/* Return function status */return HAL_OK;}/* Check if first segment */else if((heth->RxDesc->Status & ETH_DMARXDESC_FS) != (uint32_t)RESET){(heth->RxFrameInfos).FSRxDesc = heth->RxDesc;(heth->RxFrameInfos).LSRxDesc = NULL;(heth->RxFrameInfos).SegCount = 1U;/* Point to next descriptor */heth->RxDesc = (ETH_DMADescTypeDef*) (heth->RxDesc->Buffer2NextDescAddr);}/* Check if intermediate segment */else{(heth->RxFrameInfos).SegCount++;/* Point to next descriptor */heth->RxDesc = (ETH_DMADescTypeDef*) (heth->RxDesc->Buffer2NextDescAddr);}}/* Return function status */return HAL_ERROR;}// ********************************************************************************/*** @brief This function should do the actual transmission of the packet. The packet is* contained in the pbuf that is passed to the function. This pbuf* might be chained.** @param netif the lwip network interface structure for this ethernetif* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)* @return ERR_OK if the packet could be sent* an err_t value if the packet couldn't be sent** @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to* strange results. You might consider waiting for space in the DMA queue* to become available since the stack doesn't retry to send a packet* dropped because of memory failure (except for the TCP timers).*/static err_t low_level_output(struct netif *netif, struct pbuf *p){err_t errval;struct pbuf *q;uint8_t *buffer = (uint8_t *)(EthHandle.TxDesc->Buffer1Addr);__IO ETH_DMADescTypeDef *DmaTxDesc;uint32_t framelength = 0;uint32_t bufferoffset = 0;uint32_t byteslefttocopy = 0;uint32_t payloadoffset = 0;DmaTxDesc = EthHandle.TxDesc;bufferoffset = 0;/* copy frame from pbufs to driver buffers */for(q = p; q != NULL; q = q->next){/* Is this buffer available? If not, goto error */if((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET){errval = ERR_USE;goto error;}/* Get bytes in current lwIP buffer */byteslefttocopy = q->len;payloadoffset = 0;/* Check if the length of data to copy is bigger than Tx buffer size*/// This code never runs. See// https://www.eevblog.com/forum/microcontrollers/anyone-here-familiar-with-lwip/msg4693118/#msg4693118while( (byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE ){//osDelay(2); - was a buffer overwrite issue, not possible to reproduce later// see mod at the end of IF_HAL_ETH_TransmitFrame() which is a better fix// Copy data to Tx buffer - should use DMA but actually the perf diff is negligible#ifdef SPEED_TESTTopLED(true);#endifmemcpy_fast( (uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset) );#ifdef SPEED_TESTTopLED(false);#endif/* Point to next descriptor */DmaTxDesc = (ETH_DMADescTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);/* Check if the buffer is available */if((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET){errval = ERR_USE;goto error;}buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);bufferoffset = 0;}/* Copy the remaining bytes */#ifdef SPEED_TESTTopLED(true);#endifmemcpy_fast( (uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), byteslefttocopy );#ifdef SPEED_TESTTopLED(false);#endifbufferoffset = bufferoffset + byteslefttocopy;framelength = framelength + byteslefttocopy;}/* Prepare transmit descriptors to give to DMA */IF_HAL_ETH_TransmitFrame(&EthHandle, framelength);errval = ERR_OK;error:/* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */if ((EthHandle.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET){/* Clear TUS ETHERNET DMA flag */EthHandle.Instance->DMASR = ETH_DMASR_TUS;/* Resume DMA transmission*///__DMB();EthHandle.Instance->DMATPDR = 0;// Any value issues a descriptor list poll demand.}return errval;}/*** @brief Should allocate a pbuf and transfer the bytes of the incoming* packet from the interface into the pbuf.** @param netif the lwip network interface structure for this ethernetif* @return a pbuf filled with the received packet (including MAC header)* NULL on memory error*/static struct pbuf * low_level_input(struct netif *netif){struct pbuf *p = NULL, *q = NULL;uint16_t len = 0;uint8_t *buffer;__IO ETH_DMADescTypeDef *dmarxdesc;uint32_t bufferoffset = 0;uint32_t payloadoffset = 0;uint32_t byteslefttocopy = 0;uint32_t i=0;/* get received frame */HAL_StatusTypeDef status = IF_HAL_ETH_GetReceivedFrame(&EthHandle);if (status != HAL_OK){return NULL;// Return if no RX data}else{rxactive=true;// set "seen rx data" flag}/* Obtain the size of the packet and put it into the "len" variable. */len = EthHandle.RxFrameInfos.length;buffer = (uint8_t *)EthHandle.RxFrameInfos.buffer;// Dump unwanted multicasts, unless g_eth_multi=true.if (should_accept_ethernet_packet(buffer, len)){/* We allocate a pbuf chain of pbufs from the Lwip buffer pool */p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);}// Load the packet (if not rejected above) into LWIP's bufferif (p != NULL){dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc;bufferoffset = 0;for(q = p; q != NULL; q = q->next){byteslefttocopy = q->len;payloadoffset = 0;/* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size */// This code never runs. See// https://www.eevblog.com/forum/microcontrollers/anyone-here-familiar-with-lwip/msg4693118/#msg4693118while( (byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE ){/* Copy data to pbuf */#ifdef SPEED_TESTTopLED(true);#endifmemcpy_fast( (uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));#ifdef SPEED_TESTTopLED(false);#endif/* Point to next descriptor */dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);buffer = (uint8_t *)(dmarxdesc->Buffer1Addr);byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);bufferoffset = 0;}/* Copy remaining data in pbuf */#ifdef SPEED_TESTTopLED(true);#endifmemcpy_fast( (uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), byteslefttocopy);#ifdef SPEED_TESTTopLED(false);#endifbufferoffset = bufferoffset + byteslefttocopy;}}/* Release descriptors to DMA. This tells the ETH DMA that the packet has been read *//* Point to first descriptor */dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc;/* Set Own bit in Rx descriptors: gives the buffers back to DMA */for (i=0; i< EthHandle.RxFrameInfos.SegCount; i++){//__DMB(); - fossil code for the 32F417, apparently.dmarxdesc->Status |= ETH_DMARXDESC_OWN;dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);}/* Clear Segment_Count */EthHandle.RxFrameInfos.SegCount =0;/* When Rx Buffer unavailable flag is set: clear it and resume reception */if ((EthHandle.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET){/* Clear RBUS ETHERNET DMA flag */EthHandle.Instance->DMASR = ETH_DMASR_RBUS;/* Resume DMA reception */EthHandle.Instance->DMARPDR = 0;}return p;}Enjoy

author: tellurium
author_rank: Frequent Contributor
timestamp: January 08, 2025, 10:59:42 pm
content: Quote from: peter-h on January 08, 2025, 04:26:24 pmIt would be a very long video if it explains all ins and outs.But here are some points that make it fast:1. The speed of TCP/IP stack itself. It depends on many things, but most crucial are - are sockets used or not. Sockets introduces extra buffering layer, plus it demands TCP/IP stack be in a separate task. Each IO call would then translate into RTOS queue call between app task and TCP/IP task. Here are some old benchmark numbers on F746 Nucleo board:Zephyr: < 10 QPS (HTTP queries per second)LWIP + sockets: 16 QPSLWIP + no sockets (raw API): 286 QPSMongoose (no sockets): 1084 QPSAs you can see, numbers differ in 2 orders of magnitude.2. RSA vs EC. EC is less RAM hungry and more performant. There are a lot of nuances, and generally, that's the rule3. If EC is used, then verification step does not use HW acceleration (EC curve math does not use RSA, SHA, etc).4. TLS 1.3 vs TLS 1.2 - version matters. TLS 1.3 handshake is ~30% faster, cause client sends everything necessary during the handshake, server verifies and responds - and that's it. One back and forth, and not multiple back and forths like in TLS 1.2.It is possible to tune mbedTLS to perform as fast, but it takes time and expertise. Mongoose is tuned to max performance and minimum RAM usage by default, there is no need to tune it.

author: tellurium
author_rank: Frequent Contributor
timestamp: January 08, 2025, 11:15:44 pm
content: Peter,STM32 ethernet driver implementation is famous for its bloat and low quality. It is infested with bugs which ST does not manage to fix for years.

author: dietert1
author_rank: Super Contributor
timestamp: January 09, 2025, 02:30:03 am
content: I got quick results using a STM32H743 Disco board with their web server example. It was easy to add telnet connectivity using a web find. I also managed to implement fiber connectivity using a TI phy chip.W5500 was easy to use, too. I spent one or two weeks to convert their library into interrupt driven for better integration with other processes. Of course performance will be limited by the SPI interface clock.An important part in all this was a cheap way of sniffing ethernet packets at 100 MHz. I used some old Netgear DS104 hub that would do the job as soon as some nodes were configured as half duplex.Regards, Dieter

author: nctnico
author_rank: Super Contributor
timestamp: January 09, 2025, 12:15:04 pm
content: Quote from: tellurium on January 08, 2025, 10:59:42 pmNot necessarily; a round-robin (super loop) setup will work just fine for as long as the sockets are non-blocking. IMHO BSD style sockets are a hard requirement as this allows to evaluate / test code on a PC and use existing code which is based on sockets. If BSD sockets are slow, you are doing something wrong because the BSD sockets where designed in the days when computers where significantly slower compared to modern day micro controllers.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: January 09, 2025, 12:51:45 pm
content: QuoteIf you like to see your ethernet packets scope/logic analyzer style, I still have a few of these left:www.etherdecode.com

author: peter-h
author_rank: Super Contributor
timestamp: January 09, 2025, 02:26:24 pm
content: TelluriumI simply do not believe those numbers are meaningful.Something else is going on.My target is doing 1MB/sec on file transfers, and that is with a very sub-optimal low level input implementation whereby I have an RTOS task polling for inputCode:/*** This function is the ethernetif_input task. It uses the function low_level_input()* that handles the actual reception of bytes from the network interface.** This is a standalone RTOS task so is a forever loop.* Could be done with interrupts but then we have the risk of hanging the xxx with fast input* (unlikely if ETH is via a switch, but you could have a faulty LAN with lots of* broadcasts) plus we have the issue of link status change detection in a thread-safe way.**/void ethernetif_input( void * argument ){struct pbuf *p;struct netif *netif = (struct netif *) argument;uint32_t link_change_check_count = ETH_LINK_CHANGE_COUNT;// Define RX activity timer, for dropping fast poll down to slow pollTimerHandle_t *rxactive_timer = xTimerCreate("ETH RX active timer", pdMS_TO_TICKS(ETH_SLOW_POLL_DELAY), pdFALSE, NULL, RXactiveTimerCallback);// Start "rx active" timerxTimerStart(rxactive_timer, 20);// 20 is just a wait time for timer allocationdo{p = low_level_input( netif );// This sets rxactive=true if it sees dataif (p!=NULL){if (netif->input( p, netif) != ERR_OK ){pbuf_free(p);}}if (rxactive){rxactive=false;// Seen rx data - reload timeoutxTimerReset(rxactive_timer, 20);// Reload "rx active" timeout (with ETH_SLOW_POLL_DELAY)// and get osDelay below to run fastrx_poll_period=ETH_RX_FAST_POLL_INTERVAL;}// This has a dramatic effect on ETH speed, both ways (TCP/IP acks all packets)osDelay(rx_poll_period);// Do ETH link status change checklink_change_check_count--;if (link_change_check_count==0){// reload counterlink_change_check_count = ETH_LINK_CHANGE_COUNT;// Get most recently recorded link statusbool net_up = netif_is_link_up(&g_xxx_netconf_netif);// Read the physical link statusethernetif_set_link(&g_xxx_netconf_netif);// Has the link status changedif (net_up != netif_is_link_up(&g_xxx_netconf_netif)){ethernetif_update_config(&g_xxx_netconf_netif);if (net_up) {// Link was up so must have droppeddebug_thread_printf("Ethernet link down");}else {// Link was down so must be up - restart DHCPdebug_thread("Ethernet link up");xxx_network_restart_DHCP();}}}} while(true);}There simply aren't several seconds' worth ofinternet transactionsinvolved in the TLS setup. The CPU time is spent firmly in the RSA or EC crypto. So your 10x difference could well be RSA versus EC.This is a very old issue, which is why there are chips which do hardware RSA, in ~100ms. If you could do it in 400ms, then a modern 500MHz arm32 would do RSA in 100ms in software, EC much faster, and nobody would be using those coprocessor chips (well except for "secure" private key storage).Can you supply actual numbers for your RSA and EC code, and at what MHz.Other apps I have running that use sockets show no performance issues. For example an MbedTLS application (HTTPS client) does a file download at a decent speed. I personally use the Netconn API of LWIP which is below the socket layer but still...QuoteWhere exactly is the "bloat and low quality"? The 32F4 ETH subsystem runs a linked list of packets (I've not studied it in detail; it is very complicated and I have better things to do). The code I posted interfaces between the buffer structure of LWIP and this packet list. It doesn't look like it can be made much shorter.There are zero-copy versions posted on the ST forum, from "Piranha", but I am not sure anybody understands them, and he appears to have vanished.I too was concerned about the data moving, so did done timing measurements with a scope and the software copy my (ST) code uses takes an insignificant time. It's hard to see where much time can be saved. Replacing the memcpy() with DMA would have made no difference in any likely IOT application.As regards bugs, the guy who did this project originally spent maybe a month full time equivalent patching the code from bug reports found all over the internet, which indeed is crap from ST, but that is historical.Regarding LWIP config, yes, very true, it is poorly documented - symptomatic of a project which started ~17 years ago, the devs have long ago got themselves girlfriends and moved onand nobody wrote up a "how to get started quick" guide for it. But the 17 years also works in its favour: bugs should have been worked out of it, over literally millions of devices in the field. And it is very unlikely that everybody is using the same 10% of the functionality i.e. concealing major bugs.That could well be true for MbedTLS though.I spent ages googling for info on how to set up the buffer sizes etc, testing and documenting it. It's actually easy if you throw a lot of RAM at it (say 50k) but I am not doing that. A google for lwipopts.h yields loads of hits and eventually you find some useful info... A crap situation but typical of open source software! The alternative is closed commercial sources, or low deployment number sources where one doesn't really know how well they have been tested.

author: SCSKITS
author_rank: Regular Contributor
timestamp: January 09, 2025, 03:30:40 pm
content: Its wired Ethernet, but the Lantronix X-Ports are easy to use. From what I remember though, they are a bit expensive, about $50 to $70 depending on version. The ones I used were a simple serial interface. No special PCB requirements either.

author: tellurium
author_rank: Frequent Contributor
timestamp: January 09, 2025, 06:36:56 pm
content: Quote from: nctnico on January 09, 2025, 12:15:04 pmI am not doing anything wrong.In the benchmark I mentioned , I took a board, a stock examples for Zephyr and ST Cube (which used LWIP and LWIP's httpd), built and measured the QPS using "siege" utility. I did not "do" anything wrong cause I did not touch the code.I know very well how BSD sockets were designed (I have a video about that), and I know how they are implemented in LWIP and Zephyr (see my note above).

author: peter-h
author_rank: Super Contributor
timestamp: January 09, 2025, 06:46:41 pm
content: I don't think HTTPD which comes with LWIP (in ST Cube IDE) works as it is. I paid someone to do something with it and it turned out to be largely broken.It would be great to find out where the 10:1 speed difference comes from.

author: peter-h
author_rank: Super Contributor
timestamp: January 10, 2025, 09:15:46 am
content: This is a fairly typical case with MbedTLS pinging the well known hc-ping.com device failure notification service. The numbers on the left are ms, so you are looking at 6 secondsCode:2595367457: healthcheck url= https://hc-ping.com/8cd78cf4-eb2b-4844-b572-xxxxxxxxxxxxxxxxx2595367461:. Seeding the random number generator...2595367468: ok2595367469: . Connecting to tcp/hc-ping.com/443...2595367503: connect ok2595367509: . Setting up the SSL/TLS structure...2595367515: ok2595367523: . Performing the SSL/TLS handshake...Certificate verify (depth 2) for:cert. version : 3serial number : 5C:8B:99:C5:5A:94:C5:D2:71:56:DE:CD:89:80:CC:26issuer name : C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust ECC Certification Authoritysubject name : C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust ECC Certification Authorityissued on : 2010-02-01 00:00:00expires on : 2038-01-18 23:59:59signed using : ECDSA with SHA384EC key size : 384 bitsbasic constraints : CA=truekey usage : Key Cert Sign, CRL SignThis certificate has no flagsCertificate verify (depth 1) for:cert. version : 3serial number : F3:64:4E:6B:6E:00:50:23:7E:09:46:BD:7B:E1:F5:1Dissuer name : C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust ECC Certification Authoritysubject name : C=GB, ST=Greater Manchester, L=Salford, O=Sectigo Limited, CN=Sectigo ECC Domain Validation Secure Server CAissued on : 2018-11-02 00:00:00expires on : 2030-12-31 23:59:59signed using : ECDSA with SHA384EC key size : 256 bitsbasic constraints : CA=true, max_pathlen=0key usage : Digital Signature, Key Cert Sign, CRL Signext key usage : TLS Web Server Authentication, TLS Web Client AuthenticationThis certificate has no flagsCertificate verify (depth 0) for:cert. version : 3serial number : 33:6D:EC:80:31:F7:A3:44:B6:A1:0E:56:DB:7B:9B:CDissuer name : C=GB, ST=Greater Manchester, L=Salford, O=Sectigo Limited, CN=Sectigo ECC Domain Validation Secure Server CAsubject name : CN=hc-ping.comissued on : 2024-09-17 00:00:00expires on : 2025-10-16 23:59:59signed using : ECDSA with SHA256EC key size : 256 bitsbasic constraints : CA=falsesubject alt name : hc-ping.com, [url=http://www.hc-ping.com]www.hc-ping.comkey usage : Digital Signatureext key usage : TLS Web Server Authentication, TLS Web Client AuthenticationThis certificate has no flags2595373489: TLS handshake ok2595373495: . Verifying peer X.509 certificate...2595373501: ok2595373507: Using TLS ciphersuite: TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA2562595373513: > Write to server:2595373519: 72 initial bytes written:2595373525: < Read from server:2595373931: Headers length = 188, Content-Length = 22595373937: 190 bytes read:2595373943: HTTP/1.1 200 OKserver: nginxdate: Fri, 10 Jan 2025 09:12:02 GMTcontent-type: text/plain; chars...2595374063: http incoming connectionThere is a ~3 sec wait after the "Performing the SSL/TLS handshake..." and before the long certificate debugs come out. They come out in about 100ms.When doing these tests one must do it against a specific website and server configuration, obviously.