Skip to main content
Associate II
July 5, 2026
Question

STM32 Nucleo-H725ZG Ethernet LWIP without FreeRTOS

  • July 5, 2026
  • 23 replies
  • 347 views

I am attempting to use the Nucleo-H723ZG with Ethernet and LWIP but without FreeRTOS.
I am currently using STM32CubeMX 6.18.0 and STM32CubeIDE 2.2.0.
I have spent weeks attempting to get this working following the various youtube videos and topics on here.
I am currently attempting a simple UDP message that can be viewed on wireshark along the lines o “H723ZG with an incrementing counter”. I am unable to get any ARP or UDP currently.
Any help is greatly appreciated - thanks.

23 replies

mbarg.1
Senior III
July 6, 2026

Latest LWIP is built on top of FREERTOS.

You can re-write all FreeRtos functions or take LWIP functions and re-write with your proprietary OS calls.

In both cases therer is a large effort involved; do you have a budget for that ?

Reinventing hot water is a common hobby nowdays, but there are better ways to spend yout time.

Associate II
July 6, 2026

Is it purely the later versions that LWIP is build on top of FREERTOS? If so, which version would suit LWIP without FREERTOS? Or is LWIP even needed? I’m not particularly interested in seeing ARPs just the UDP message.

mbarg.1
Senior III
July 6, 2026

Any library will leverage an OS - FreeRtos + or ThreadX or CMsis…

Ethernet is a real time job, OS does provide basic services to use it, HAL drivers alone are not enough.

Andrew Neil
Super User
July 6, 2026

 

 

 

 

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
LCE
Principal II
July 6, 2026

FreeRTOS is absolutely not required for lwIP.

I started with a Nucleo F767 and a CubeMX example without any OS, later I switched to Nucleo H723, then got my own hardware.

 

Anyway, lots of stuff going on there.

I recommend starting with an example from ST for that board with ethernet.

Just checking my CubeMx examples - there’s no Nucleo H725, you probably mean H723?

Try these:
STM32CubeH7/Projects/NUCLEO-H723ZG/Applications/LwIP at master · STMicroelectronics/STM32CubeH7


I haven’t trued these for some years now, so no guarantee from my side…

 

Edit: typical mistake: STM32 and PC not in the same netweork address space

Associate II
July 7, 2026

@LCE thanks, I have tried these with no luck…

I came across the below post which I am also unable to get working. Is there a correlation with the crdb.zip being unavailable at the moment?

 

Pavel A.
July 6, 2026

Here are the LwIP examples for this board. The last two are for the raw API (no RTOS)

https://github.com/STMicroelectronics/STM32CubeH7/tree/master/Projects/NUCLEO-H723ZG/Applications/LwIP

These examples are not perfect but at least you should get ARP and ping working.

Associate II
July 7, 2026

@Pavel A. thanks, I have tried these with no luck…

I came across the below post which I am also unable to get working. Is there a correlation with the crdb.zip being unavailable at the moment?

Pavel A.
July 7, 2026

> Is there a correlation with the crdb.zip being unavailable at the moment?

Hmm. Not likely.

 

Try to use the simplest easiest network setup: connect the Nucleo to a powered ethernet switch 100 Mb/s, so that the PHY always stays connected. Plug the other host (PC) into the same switch.

LCE
Principal II
July 7, 2026

Well, show some code (please use source code formatting, in the menu “…” ):

  • lwIP init okay?
  • noOS flag set in some lwip options file?
  • calling lwIP process in the main loop?
  • activate lwIP statistics and check these via UART

And again:

  • how do you connect the Nucleo to the PC? Directly or via a switch? Mind: the standar Windows PC doesn’t work as a DHCP-server.
  • so what IP address is your Nucleo set to ?
  • and the IP address at the connected ethernet adapter for the PC ? Check in Windows with command terminal / ipconfig

 

 

Associate II
July 7, 2026

I am using the Ethernet_H723_Fixed.zip from https://community.st.com/stm32-mcus-embedded-software-32/stm32h723zg-ethernet-not-responding-to-ping-no-rtos-164549

 

  • lwIP init is fine
  • noOS is set
  • lwIP is called in main loop
  • Nucleo is connected to laptop via ethernet to usb-c adapter 
  • nucleo is set to 192.168.1.20 (same as original from attached post)
  • adapter ip is 192.168.1.10. subnet is 255.255.255.0 and gateway is 192.168.1.1

 

Andrew Neil
Super User
July 7, 2026
A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
LCE
Principal II
July 8, 2026

Okay…

Have you checked:

  • Wireshark: anything going on in that network? For any ethernet stuff, Wireshark is the debug tool no. 1, helped me a lot
  • Nucleo: maybe some solder bridge or resistor wrongly assembled? Maybe try with another Nucleo if possible.
  • Nucleo: power supply? Probably the on-board USB / ST-Link

 

Further debugging:

  • make some UART IO functions to read / write the PHY registers directly
  • use the CubeIDE debugging and check what the lwip_process() is doing

 

Associate II
July 8, 2026

Out of interest does the Ethernet_H723_Fixed work for you?

LCE
Principal II
July 8, 2026

Never used it. After quick check using HAL, I re-wrote the ETH driver completely, no HAL anymore.

Associate II
July 8, 2026

Yeah, I’ve been using wireshark to monitor communications. I get a link between the Nucleo and the pc but see no ARP from 1.10 asking for 1.20. I can see the pings for 1.20 but get no response.

I have check the configuration of the Nucleo and the links are correct.

Yes it is supplied via the ST-Link onboard USB.

 

LCE
Principal II
July 8, 2026

Here is some code that (I think) worked once, an UDP echo server.

I have no time to comment any more on that.


#if LWIP_UDP

static struct udp_pcb *pPcbUdpEcho = NULL;

uint16_t u16UdpEchoPort = 0;
uint8_t u8UdpEchoActive = 0;


void UdpEchoRecvCb(void *pArg, struct udp_pcb *pPcbUe, struct pbuf *pPbufUe, const ip_addr_t *pIpAddr, uint16_t u16Port)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(pArg);

if( pPbufUe != NULL )
{
#if DEBUG_UDP_ECHO
*(uint8_t *)(pPbufUe->payload + pPbufUe->len) = 0;
uart_printf("pPbufUe->payload:\n\r%s\n\r", (char *)pPbufUe->payload);
#endif
/* send received packet back to sender */
udp_sendto(pPcbUe, pPbufUe, pIpAddr, u16Port);
/* free the pbuf */
pbuf_free(pPbufUe);
}
}


uint8_t UdpEchoStart(void)
{
err_t eErr = ERR_OK;

u8UdpEchoActive = 0;
u16UdpEchoPort = DEBUG_UDP_ECHO_PORT;

/* create new UDP PCB structure */
pPcbUdpEcho = udp_new();
if( pPcbUdpEcho == NULL )
{
#if DEBUG_UDP_ECHO
uart_printf("# ERR: UdpEchoStart() - udp_new()\n\r");
#endif
return 1;
}

/* bind to specified port */
eErr = udp_bind(pPcbUdpEcho, IP_ADDR_ANY, u16UdpEchoPort);
if( eErr != ERR_OK )
{
#if DEBUG_UDP_ECHO
uart_printf("# ERR: UdpEchoStart() - udp_bind(), port %d: eErr = %d\n\r", u16UdpEchoPort, eErr);
#endif
return 1;
}

/* set UDP receive callback */
udp_recv(pPcbUdpEcho, (udp_recv_fn)UdpEchoRecvCb, NULL);

#if DEBUG_UDP_ECHO
uart_printf("UDP echo server started @ port %d\n\r", u16UdpEchoPort);
#endif

u8UdpEchoActive = 1;

return 0;
}


/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */

#define DEBUG_UDP_STREAM 1

struct udp_pcb *pPcbUdpStream = NULL;

uint16_t u16UdpStreamPort = 0;
uint8_t u8UdpStreamActive = 0;
uint32_t u32UdpStreamRxdPkts = 0;
uint64_t u64UdpStreamRxdBytes = 0;

struct ip4_addr ipUdpRecv;


/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* UdpStreamSend(): sends UDP data packet */
err_t UdpStreamSend(uint8_t *pu8TxBuf, uint16_t u16TxLen)
{
err_t eRetVal = ERR_OK;
struct pbuf *pPbufTx;

/* allocate the tx pbuf
* type: PBUF_ROM for non-copy payload
* layer: PBUF_TRANSPORT leaves room for UDP header
*/
pPbufTx = pbuf_alloc(PBUF_TRANSPORT, u16TxLen, PBUF_ROM);
if( pPbufTx == NULL )
{
#if DEBUG_UDP_STREAM
uart_printf("#ERR: UdpStreamSend() failed to allocate Tx Buffer\n\r");
#endif
return ERR_MEM;
}

/* set pbuf payload pointer to incoming data pointer */
pPbufTx->payload = pu8TxBuf;

/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* send the buffer to specific IP address and port */
eRetVal = udp_sendto(pPcbUdpStream, pPbufTx, &ipUdpRecv, pPcbUdpStream->local_port);

#if DEBUG_UDP_STREAM
if( ERR_OK != eRetVal )
uart_printf("#ERR: UdpStreamSend() failed to send data (%d)\n\r", eRetVal);
#endif

/* release pbuf */
pbuf_free(pPbufTx);

return eRetVal;
}


void UdpStreamRecvCb(void *pArg, struct udp_pcb *pPcbUs, struct pbuf *pPbufUsRx, const ip_addr_t *pIpAddr, uint16_t u16Port)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(pArg);

if( pPbufUsRx != NULL )
{
#if DEBUG_UDP_STREAM
#if( 0 )
uart_printf("pPbufUsRx->payload:\n\r");
// *(uint8_t *)(pPbufUsRx->payload + pPbufUsRx->len) = 0;
// uart_printf("%s\n\r", (char *)pPbufUsRx->payload);
uint8_t *pu8data = (uint8_t *)pPbufUsRx->payload;
for( uint16_t i = 0; i < pPbufUsRx->len; i++ )
{
if( i % 8 == 0 ) uart_printf("\n\r%02d: ", i);
uart_printf("%02X ", pu8data[i]);
}
uart_printf("\n\r");
#endif
u32UdpStreamRxdPkts++;
u64UdpStreamRxdBytes += pPbufUsRx->len;
// uart_printf("%d\n\r", pPbufUsRx->len);
#endif

/* free the pbuf */
pbuf_free(pPbufUsRx);
}
}


err_t UdpStreamStart(uint8_t u8StartSai)
{
err_t eRetErr = ERR_OK;
uint8_t u8IpAddrUdpHost[4] = { 192, 168, 178, 39 };

u8UdpStreamActive = 0;
u16UdpStreamPort = DEBUG_UDP_STREAM_PORT;
u32UdpStreamRxdPkts = 0;
u64UdpStreamRxdBytes = 0;

/* create new UDP PCB structure */
pPcbUdpStream = udp_new();
if( pPcbUdpStream == NULL )
{
#if DEBUG_UDP_STREAM
uart_printf("# ERR: UdpStreamStart() - udp_new()\n\r");
#endif
return ERR_MEM;
}

/* bind to specified port */
eRetErr = udp_bind(pPcbUdpStream, IP_ADDR_ANY, u16UdpStreamPort);
if( eRetErr != ERR_OK )
{
#if DEBUG_UDP_STREAM
uart_printf("# ERR: UdpStreamStart() - udp_bind(), port %d: eRetErr = %d\n\r", u16UdpStreamPort, eRetErr);
#endif
return eRetErr;
}

/* set UDP receive callback */
udp_recv(pPcbUdpStream, (udp_recv_fn)UdpStreamRecvCb, NULL);

#if DEBUG_UDP_STREAM
uart_printf("UDP STREAM server started\n\r");
uart_printf("u16UdpStreamPort = %d\n\r", u16UdpStreamPort);
uart_printf("pPcb->local_port = %d\n\r", pPcbUdpStream->local_port);
#endif

/* set receiver's IP address */
IP4_ADDR(&ipUdpRecv, u8IpAddrUdpHost[0], u8IpAddrUdpHost[1], u8IpAddrUdpHost[2], u8IpAddrUdpHost[3]);

u8UdpStreamActive = 1;


return eRetErr;
}

#endif //LWIP_UDP

 

sergey23
Associate
September 1, 2026

@Aaron_1402 Can you elaborate on the intended use case ?

 

lwIP supports 3 different APIs:
a) raw API - callback based, can be used without RTOS​​​​​​,
b) netconn API - a connection-oriented API based on raw API, can be used without RTOS​​​​​​,
c) BSD sockets API - cannot be used without RTOS, cause BSD API calls can block.

If your intention is to use UDP only, then lwIP with netconn API is a good choice.
If you plan anything TCP, then it can be more difficult.

The common reason why ethernet does not work on H7, is the wrong linker script placement: the driver uses DMA controller, and DMA buffers must be placed in the DMA-accessible area. E.g. D2. 


ST’s Ethernet driver does not declare DMA buffers but leaves that to the application developer, and that leads to many different code snippets using different section names. In the example referenced above, here is the netconn example declaring buffers:

https://github.com/STMicroelectronics/STM32CubeH7/blob/9cf51fd8273f12ea7ddbe3d072bf954c0ceb6358/Projects/NUCLEO-H723ZG/Applications/LwIP/LwIP_HTTP_Server_Netconn_RTOS/Src/ethernetif.c#L104-L105

Notice the .RxDescripSection and .TxDescripSection names? And see the corresponding linker script snippet that places those buffers in DMA-accessible D2 region:
https://github.com/STMicroelectronics/STM32CubeH7/blob/9cf51fd8273f12ea7ddbe3d072bf954c0ceb6358/Projects/NUCLEO-H723ZG/Applications/LwIP/LwIP_HTTP_Server_Netconn_RTOS/STM32CubeIDE/STM32H723ZGTX_FLASH.ld#L170-L179

So make sure your code does that, too.

If you’re considering using lwIP alternative, you can download a ready-to-build .zip project for H723 from https://mongoose.ws/#try