Close

Networking with ESP32 and STM32H563 without ESP-AT

A project log for BenchPod

An open hardware bench tool that plugs into your CI: sensor sim, CAN, analog I/O, power control, and a Python SDK with pytest integration

edward-viaeneEdward Viaene 07/03/2026 at 16:490 Comments

The BenchPod v1.0.0 setup was pretty simple: RP2350B with AT commands over UART to the ESP32 module for WiFi. In v2.0.0, I needed a different approach because we added Ethernet and wanted a streamlined solution.

The STM32H563 has an Ethernet MAC, so the obvious solution would be to do lwIP in the firmware. That's all pretty well-documented, so it's easy to implement. We communicate over RMII to the LAN8742 PHY, and from that point, it's all physical layer. Doing AT at this point with the ESP32 sounds like maintaining 2 different approaches to networking.

This brings us to esp-hosted-mcu (https://github.com/espressif/esp-hosted-mcu). Using this, we can keep lwIP, use 2 interfaces, and maintain 1 codebase for both WiFi and wired Ethernet. The lwIP interface for WiFi flattens the packet, wraps it in the esp-hosted framing, and puts it on the SPI bus to the ESP32, which then sends it out over WiFi. This gives us 1 IP layer inside the STM32, with the ESP32 just forwarding the packets. The AT protocol is no longer needed (esp-hosted has its own binary control channel for scan/connect instead), and the WiFi link shows up as just another native netif to lwIP.

Still had to chase down some non-obvious bugs. IP packets have checksums, and in lwIP, checksum generation was disabled because it'd be handled by the STM32's Ethernet MAC in hardware. The catch is that lwIP's checksum setting is global by default, so when I brought up WiFi, those packets went out with zero checksums too. The ESP32 side of the SPI link has no hardware to generate them. I had to sniff the DHCP packets to figure out why nothing was coming back (a missing checksum on the outgoing frame):

e8:3d:c1:21:2e:70 ... length 336, bad cksum 0 (->ba75)! 

That "bad cksum" is the IP header checksum, which is mandatory, so the frame is dropped, and no DHCP offer ever comes back. The fix was to enable per-netif checksum control (LWIP_CHECKSUM_CTRL_PER_NETIF): the Ethernet netif keeps offloading to the MAC, while the WiFi netif computes IP/UDP/TCP checksums in software. That solved it.

Also worth mentioning: the ESP32-C3 ships blank, and we only wire UART, EN, and BOOT lines to reach the STM32, because we want to flash over USB (which is connected to the STM32). That means the STM32 has to flash the ESP-hosted slave firmware into the ESP32 itself over its ROM bootloader before any of this networking works. The MCU bootstraps its own WiFi chip by loading the ESP32 binary from its flash and flashing it over UART.

Discussions