2026-01-19 3:12 AM
Hello everyone,
I am working with the NUCLEO-H723ZG board and attempting to establish Ethernet communication using TCP/IP. The firmware was built and flashed successfully using STM32CubeIDE version 1.19.0.
However, I am facing issues with basic network connectivity. Below are the details of my setup and observations:
Board: NUCLEO-H723ZG
IDE: STM32CubeIDE v1.19.0
Ethernet stack: LwIP
PHY interface: RMII
Flashing tool: ST-LINK (onboard)
Test performed: Ping test from PC
The Ethernet port LEDs (orange and green) remain solid ON after connecting the Ethernet cable.
Ping requests consistently fail (Request timed out).
No response is received from the board.
Tested both Static IP and Dynamic IP (DHCP) configurations.
Verified IP address, subnet mask, and gateway settings.
Tried multiple Ethernet cables to rule out cable-related issues.
Rebuilt and reflashed the project multiple times.
Verified that the firmware flashes successfully and runs without build errors.
Despite these steps, the board does not respond to ping requests.
Does solid ON state of both Ethernet LEDs indicate a known PHY or clock configuration issue?
Are there any known issues with RMII_REF_CLK configuration on the NUCLEO-H723ZG?
Are there specific CubeMX clock, MPU, or cache settings required for reliable Ethernet operation on STM32H723?
Any recommended minimal or verified example project for Ethernet ping testing on this board?
I need some guidance or suggestions to identify and resolve this issue.
2026-01-19 3:33 AM
2026-01-19 3:37 AM
Hello @Srivatsan and welcome to the ST community;
This knowledge base may help you: How to create a project for STM32H7 with Ethernet and LwIP stack working
2026-01-19 10:06 PM
I have downloaded the ZIP file from the link you provided:
Link: https://github.com/stm32-hotspot/STM32H7-LwIP-Examples
I also installed STM32CubeIDE version 1.9.0 and flashed the firmware onto the board. After flashing the code, I tested whether the assigned IP address responds to ping requests; however, the ping test still fails.
While flashing the project the memory locations are
The CubeMX parameter settings are,
The ping test result is,
For your reference, I have attached the project folder used for this test.
2026-01-19 10:21 PM
Hi,
Your MPU configuration is incorrect, and the Rx_PoolSection must not be placed in SRAM2.
For STM32H7 Ethernet + LwIP, RX buffers must be located in D1 RAM (address range 0x24000000–0x30007FFF).
1) Update the linker script:
2) Configure the MPU as described in the following ST article:
https://community.st.com/t5/stm32-mcus/how-to-create-a-project-for-stm32h7-with-ethernet-and-lwip-stack/ta-p/49308
~Aj
2026-01-20 4:36 AM
If you want to try an alternative to LWIP, go to https://mongoose.ws/wizard/#/output?board=h723&ide=CubeIDE&rtos=FreeRTOS&file=README.md , choose the destination directory in the settings tab, , click generate button - then load the saved project in your Cube IDE.
That uses Mongoose TCP/IP stack instead of LWIP, and gives you a ready-to-use Web UI, MQTT, and remote firmware updates.
Regardless of the TCP/IP stack you use, the trick with STM32H7 is that Ethernet DMA controller can access only certain memory regions. The driver code defines DMA buffers with a special flag, __attribute__ section ..., which places those buffers in a specific ELF section, and your linker script must place that section in the region accessible by the Ethernet DMA controller. That what ajmw_' s suggestion is about.
The H723 has the following regions;
MEMORY
{
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 320K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 32K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 16K
}
You can get the same info from the https://www.st.com/resource/en/datasheet/stm32h723zg.pdf datasheet, section 3.3.2. Ethernet controller is on D2 domain, thus place DMA buffers in any of the D2 domain region, for example ITCMRAM, or RAM_D1 or RAM_D2
2026-01-20 4:47 AM - edited 2026-01-20 5:08 AM
Board: NUCLEO-H723ZG
STM32CubeIDE version 1.9.0
Configure clock tree:
ETH_MDC speed couldn't be changed
Finally, I am able to receive a response when performing the ping test, as shown below.
However, after following all of your instructions earlier, I was initially unable to ping the IP address. Could you please help clarify why the ping was not successful at that stage?
2026-01-20 5:12 AM - last edited on 2026-01-20 5:14 AM by mƎALLEm
I have attached my FLASH.ld file below for you reference:
/*
******************************************************************************
**
** File : LinkerScript.ld
**
** Author : STM32CubeIDE
**
** Abstract : Linker script for STM32H7 series
** 1024Kbytes FLASH and 560Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
** Copyright (c) 2022 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1); /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200 ; /* required amount of heap */
_Min_Stack_Size = 0x400 ; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM_D1 AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM_D1
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM_D1
/* Modification start */
.lwip_sec (NOLOAD) :
{
. = ALIGN(32);
*(.RxDecripSection)
. = ALIGN(32);
*(.TxDecripSection)
. = ALIGN(32);
*(.Rx_PoolSection)
} >RAM_D2
/* Modification end */
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
Kindly review it.
2026-01-20 5:26 AM
Refer to the following article carefully instead of directly copy-pasting the configuration:
https://community.st.com/t5/stm32-mcus/how-to-create-a-project-for-stm32h7-with-ethernet-and-lwip-stack/ta-p/49308
Your current configuration targets STM32H74x/H75x devices, but you are using STM32H723ZGT6, which has only 32 KB of SRAM2.Therefore, the RX buffers must be placed in AXI SRAM at 0x24000000, not in SRAM2. Also, the lwip_sec linker section is incorrect. Please refer to my previous reply for the correct linker script configuration.
1) " LWIP_RAM_HEAP_POINTER (RAM Heap Pointer) should be in SRAM2 @0x30000200"
2) MEM_SIZE (Heap Memory Size) = 32232
~ AJ
2026-01-20 5:53 AM
The shared article contains the memory allocation for the STM32H74x/H75x devices only, Whenever I'm using the STM32H723ZGT6, I have some confusions.
I have done the configuration/code & allocation with the help of the article: https://community.st.com/t5/stm32-mcus/how-to-create-a-project-for-stm32h7-with-ethernet-and-lwip-stack/ta-p/49308.
Now with your guidance, I've changed the LWIP_RAM_HEAP_POINTER & MEM_SIZE (Heap Memory Size) respectively.
and also updated the Flash.ld with your guidance. Review it.
/*
******************************************************************************
**
** File : LinkerScript.ld
**
** Author : STM32CubeIDE
**
** Abstract : Linker script for STM32H7 series
** 1024Kbytes FLASH and 560Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
** Copyright (c) 2022 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1); /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200 ; /* required amount of heap */
_Min_Stack_Size = 0x400 ; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM_D1 AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM_D1
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM_D1
/* Modification start */
.lwip_sec (NOLOAD) :
{
. = ABSOLUTE(0x30000000);
*(.RxDecripSection)
. = ABSOLUTE(0x30000100);
*(.TxDecripSection)
} >RAM_D2 AT> FLASH
/* Modification end */
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}