Skip to main content
Adam BERLINGER
ST Employee
March 11, 2020

How to create a project for STM32H7 with Ethernet and LwIP stack working

  • March 11, 2020
  • 54 replies
  • 295352 views

Summary

This article is intended for STM32CubeIDE version 1.18.1 and STM32CubeH7 version 1.12.1. For older tool versions, please see the older version of the readme in the GitHub repository

If you have any questions regarding Ethernet topics in general, visit our MCU forum and create a topic. Doing so provides you with a shorter response time. 

Example project code and older version of this article is provided on GitHub: https://github.com/stm32-hotspot/STM32H7-LwIP-Examples. Detailed how to step by step is provided below.

1. Features

  • Fixed IP address 192.168.1.10
  • The code should work even when regenerating the code in STM32CubeMX
  • Changes in code can be found by searching for the ETH_CODE keyword

2. Release notes

 

Version STM32CubeIDE version STM32CubeH7 version Description/Update Date
1.3 1.18.1 1.12.1 Ported to new IDE/library version. Change configuration to use cache maintenance. Fixed iperf code. August 19, 2026
1.2 1.9.0 1.10.0 Ported to new IDE/library version. Ethernet driver reworked in new library release. Added iperf measurement and TCP/IP settings tuned. Published on GitHub August 9, 2022
1.1 1.6.1 1.9.0 Added Cortex®-M4 base examples July 19, 2021
1.0 1.6.1 1.9.0 Initial release on ST Community (with minor changes on GitHub) June 21, 2021

Use GIT tags to find examples for a particular version of STM32CubeIDE and HAL library.

3. TCP/IP configuration in LwIP

The configuration below is necessary to achieve good TCP/IP performance.

Parameter Value Formula Needs to be changed in MX
TCP_MSS 1460
1500-40
yes
TCP_SND_BUF 5840
4 * TCP_MSS
yes
TCP_WND 5840
4 * TCP_MSS
no
TCP_SND_QUEUELEN 16
UPPER((4 * TCP_SND_BUF) / TCP_MSS)
yes

4. Memory layout

On STM32H74x/H75x devices, all data related to Ethernet and LwIP are placed in D2 SRAM memory (288 kB). The first 128 kB of this memory are reserved for Cortex®-M4 on dual-core devices. On single core devices, this part can be used for other purposes.

Variable STM32H74x/H75x address Cortex®-M4 alias Size Source file
DMARxDscrTab 0x30040000 0x10040000 96 (256 max.) ethernetif.c
DMATxDscrTab 0x30040100 0x10040100 96 (256 max.) ethernetif.c
memp_memory_RX_POOL_base 0x30040200 0x10040200 12*(1536 + 24) ethernetif.c
LwIP heap 0x30020000 0x10020000 131048 (128 kB - 24) lwipopts.h

For STM32H72x/H73x devices, the D2 SRAM is more limited (only 32 kB). The Rx buffers need to be placed in AXI SRAM, since they do not fit to D2 RAM, together with LwIP heap. The LwIP heap is reduced to fit the rest of D2 RAM together with DMA descriptors.

Variable STM32H72x/H73x address Size Source file
DMARxDscrTab 0x30000000 96 (256 max.) ethernetif.c
DMATxDscrTab 0x30000100 96 (256 max.) ethernetif.c
memp_memory_RX_POOL_base AXI SRAM (32 byte aligned) 12*(1536 + 24) ethernetif.c
LwIP heap 0x30000200 32224 (32 kB - 512 - 32) lwipopts.h

The values provided here are an example of implementation. Other configurations are also possible to optimize memory usage. When changing the memory layout, the MPU configuration needs to be updated accordingly.

For performance, it is better to keep packet buffers cacheable and manage memory coherency through cache maintenance operations. This means that the packet buffers need to be aligned to 32- bytes (the size of cache line). In LwIP, the pbuf struct contains both packet buffer and additional metadata.

To force alignment of 32-bytes between metadata and packet buffer the, MEM_ALIGNMENT option needs to be configured properly. For RX, the packet buffer should be invalidated both before and after the reception. This is to avoid corrupting data by cache line eviction.

5. License

Libraries and middleware are taken from the STM32CubeH7 package. The same licenses apply to these examples. There is minimum code added on top of STM32CubeMX and HAL libraries, this code is provided AS-IS.

6. How to create the project from scratch


6.1 Goal of the example

The goal of this example is to:

  • Configure project in STM32CubeMX for STM32H750-Discovery
  • Configure FreeRTOS™ and LwIP middlewares correctly
  • Send a UDP message periodically (optional)

Although the example is using STM32H750-Discovery, use the same steps for other STM32H7 based boards. The main differences are usually pinout and clock configuration. You might also need to check board solder bridges to make sure that the Ethernet is connected to the MCU.

6.2 STM32CubeMX project configuration

  • Create a new project in STM32CubeMX, select the STM32H750-Discovery board, and select [No] to "Initialize all peripherals in default mode?" pop-up.
    • This helps with pin assignment.

6.3 Basic configuration

Configure the clock tree:

  • In pinout/RCC, configure HSE in bypass mode.
  • In the clock tree, configure 400 MHz for the core.
Clock tree
  • In pinout/SYS, configure a different timebase than SysTick (recommended when using FreeRTOS™)
    • TIM6 is usually a good option, since it is a simple timer.

6.4 Ethernet configuration

  • Enable Ethernet peripheral in pinout view in MII mode (MII used on the board).
  • Enable Ethernet interrupt and set preemption priority to 5. This is required by FreeRTOS™ to call its functions from the interrupt handler.
  • Relocate Ethernet CRS and COL signals from PH2/PH3 to PA0/PA3.
    • These signals are optional in full-duplex mode and not connected in the default configuration.
    • This also allows using PH2/PH3 for QSPI.
  • Other pins should be correctly placed, since we create the project from the board selector.
Pinout
  • Set the GPIO pin speed to “Very High”.

94.png ​

The ETH_MDC speed could not be changed, but it does not affect the application and is fixed in new versions.

6.5 Cortex®-M7 configuration

This step can be skipped when using a Cortex®-M4 core.

  • Enable ICache and DCache.
  • Enable memory protection unit (MPU) in “Background Region Privileged access only + MPU. Disabled ...” mode. Configure regions according to the picture below:
  •  

The example above is intended for the STM32H743 device. For other devices or Cortex®-M4 core on dual-core devices, different addresses and size might be necessary. Please refer to the section 4. Memory layout.

When using a dual-core device and running Ethernet on Cortex®-M7 core, ensure that memory used by Ethernet is not used by Cortex®-M4. Also note that the Cortex®-M4 can use a different address alias for D2 RAM

6.6 FreeRTOS™ configuration

  • Enable the FreeRTOS™ with CMSIS_V1 API.
  • Increase the size of the defaultTask stack to 512 words.
  • Lower stack values cause memory corruptions.
  • Check that the generated code is correct, since there is a bug when increasing the MINIMAL_STACK_SIZE.
  • There might be an old value in the code (this should be fixed in new versions).
FreeRTOS™ stack configuration

6.7 LwIP configuration

  • Enable LwIP in the middleware.
  • In the "General settings" tab, disable the DHCP server and configure the fixed IP address (unless you know how to configure and use DHCP).
LwIP IP address configuration

In the attached examples, the 192.168.1.10 IP address is used (instead of 192.168.0.10 shown on the screenshot).

In the "Platform settings" tab, select "LAN8742" in both boxes. The LAN8742 driver is also compatible with LAN8740 device, which is present on the STM32H750-Discovery board. The main difference between these devices is the support of the MII interface. On other boards, the LAN8742 PHY chip is used.

LwIP BSP selection

In the "Key options" tab:

  • Select “Show Advanced Parameters” in the top-right corner. This is required for MEM_ALIGNMENT configuration.
  • Configure MEM_ALIGNMENT to 32 bytes. This is the size of cache line and this is needed for proper cache maintenance of LwIP buffers.
  • Configure MEM_SIZE to 16352 = 16 KB minus 32 bytes for allocator metadata. This specifies the heap size, which we relocated to D2 SRAM.
  • Also enable LWIP_NETIF_LINK_CALLBACK (needed for cable plugging/unplugging detection).
  • Set the LWIP_RAM_HEAP_POINTER to the proper address.
  • Set the MEM_SIZE parameter to the proper size.
LwIP heap configuration
  • In the "Checksum" tab enable CHECKSUM_BY_HARDWARE. Other options should automatically reconfigure and you can leave them in this state.
LwIP checksum selection

7. Generate the project

Save the project to a folder of your selection. Now, you can generate the project for IDE. We use STM32CubeIDE in this example, but it should work with other IDEs.

7.1 Modifying the code (STM32CubeIDE)

There are several places where some additional code should be placed, also depending on the selected device. In the examples, all these places are marked with a comment containing ETH_CODE along with a basic explanation. Searching for ETH_CODE can show all these places.

The main points are mentioned below:

  • Placement of the RX_POOL buffers (although we configured the address in CubeMX) in ethernetif.c
/* USER CODE BEGIN 2 */
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma location = 0x30040200
extern u8_t memp_memory_RX_POOL_base[];
#elif defined ( __CC_ARM ) /* MDK ARM Compiler */
__attribute__((at(0x30040200)) extern u8_t memp_memory_RX_POOL_base[];
#elif defined ( __GNUC__ ) /* GNU Compiler */
__attribute__((section(".Rx_PoolSection"))) extern u8_t memp_memory_RX_POOL_base[];
#endif
/* USER CODE END 2 */

In STM32CubeIDE v1.9.0 ,the GCC was updated to version 10. This changes the default handling of COMMON sections (https://gcc.gnu.org/gcc-10/changes.html). This can lead to compilation errors with the errno variable being defined multiple times. This can happen when FreeRTOS™ and LwIP are enabled. To work around this issue,  put the following code in lwipopts.h (https://github.com/STMicroelectronics/stm32_mw_lwip/issues/1.

/* USER CODE BEGIN 1 */
#undef LWIP_PROVIDE_ERRNO
#define LWIP_ERRNO_STDINCLUDE
/* USER CODE END 1 */
  • Add DATA_IN_D2_SRAM to the macro definitions in the project:
Define symbols in STM32CubeIDE

7.2 Modify the linker script (not valid for Keil/IAR)

This step should be skipped for Keil® and IAR, since they support placing variables at specific address in C code. Modify the linker script (*.ld) so that the ETH descriptors and buffers are located in D2 SRAM.

It is recommended to place all RAM to RAM_D1. In STM32CubeMX generated project, the "_FLASH" suffix linker script should be modified, which is used by default (for example, the STM32H750XBHx_FLASH.ld file).

The "_RAM" suffix linker script is a template for executing code from internal RAM memory.

} >RAM_D1
/* Modification start */
.lwip_sec (NOLOAD) :
{
. = ABSOLUTE(0x30040000);
*(.RxDecripSection)
. = ABSOLUTE(0x30040060);
*(.TxDecripSection)
. = ABSOLUTE(0x30040200);
*(.Rx_PoolSection)
} >RAM_D2
/* Modification end */
/* Remove information from the compiler libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}

The memory definitions at the beginning of the linker script should look like:

MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
}

For dual-core devices, it is best to restrict the RAM_D2 section to avoid collision with Cortex®-M4. Refer to the linker scripts in examples.

7.3 (Optional) Adding a simple “Hello UDP” message

  • Add the following include files at the beginning of main.c:
#include “lwip/udp.h”
#include <string.h>
  • Modify the StartDefaultTask in main.c with the following code:
/* USER CODE BEGIN 5 */
const char* message = "Hello UDP message!\n\r";
osDelay(1000);
ip_addr_t PC_IPADDR;
IP_ADDR4(&PC_IPADDR, 192, 168, 1, 1);
struct udp_pcb* my_udp = udp_new();
udp_connect(my_udp, &PC_IPADDR, 55151);
struct pbuf* udp_buffer = NULL;
/* Infinite loop */
for (;;) {
osDelay(1000);
/* !! PBUF_RAM is critical for correct operation !! */
udp_buffer = pbuf_alloc(PBUF_TRANSPORT, strlen(message), PBUF_RAM);
if (udp_buffer != NULL) {
memcpy(udp_buffer->payload, message, strlen(message));
udp_send(my_udp, udp_buffer);
pbuf_free(udp_buffer);
}
}
/* USER CODE END 5 */

Now, you should be able to ping the device and receive UDP messages. This assumes that you configure IP address 192.168.1.1 for the receiving device (the 192.168.1.0/24 network is used by attached examples). On Linux operating systems you can observe the messages with the following command:

netcat –ul 55151

8. Tips and common mistakes

  1. For STM32H72x/H73x devices, the Ethernet buffers cannot be placed in the address range 0x30040000 - 0x30048000, since that range is not valid. D2 SRAM on those devices is much smaller, so the buffers need to be placed starting at 0x30000000. This affects RX & TX descriptors and RX buffer addresses (ETH configuration in CubeMX) and LWIP_RAM_HEAP_POINTER used for TX buffers (LWIP > Key options in CubeMX).
     
  2. When running the stack on Cortex-M4, the buffers can be placed at the same address (0x30040000), but it is better to place them at 0x10040000, which is the alias for the same address. This alias is accessible by Cortex®-M4 D-bus and helps to utilize the Harvard architecture.
     
  3. When not using FreeRTOS™, the Ethernet interrupt should be disabled and MX_LWIP_Process should be called periodically (in the main loop).
     
  4. On STM32H747-Discovery boards, modification needs to be done to the default solder bridge configuration. SB8 should be closed and SB21 should be open for Ethernet to work, otherwise the MDC signal is not properly connected.

When facing issues with your own project:

  1. Try the example and see if there is a proper configuration on the PC side. With corporate firewalls and restrictions, it might be difficult to perform a simple ping to a specific IP address. In some cases, it is easier to test from a personal PC, or a PC with firewalls disabled.
  2. Check if the Ethernet interrupt is called and if the RX callback is called
    • If not, GPIOs are set to proper speed (very high).
    • ETH global interrupt is enabled (only for FreeRTOS™)
      • Interrupt priority should be 5 - preemption and 0 - subpriority. This is required by the default FreeRTOS™ configuration.
  3. If a Hardfault is called, the problem might be in the MPU configuration.
    • Check the values carefully (for example, a slight mistake like having "256KB" instead "256B" can make a significant difference)
  4. RX callback is called but pinging does not work.
    • Check that the buffers are properly placed in the linker script (the one ending with "_FLASH.ld").
    • In STM32CubeIDE, you can use the "Build analyzer" window.
  5. When allocating buffers via pbuf_alloc (or similar), PBUF_RAM must be used as the 3rd parameter. This is necessary to ensure that the allocated buffer is placed in D2 SRAM and synchronized with DMA
  6. A nonsufficient stack size for a different thread can cause issues.

9. Questions and feedback

If you see any issue with these examples please fill an issue inside the dedicated GitHub repository. If you face difficulties, but are not sure if this is an issue you can discuss in the repository, or create a topic in our product forums.

  1. The exact size required for different stacks might depend on used compiler and optimization flags. The same goes for FreeRTOS™ heap size, since thread stacks are allocated from this heap.

  2. Some addresses and sizes depend on the device or core used. Please refer to section 4. Memory layout.

If you have any questions regarding Ethernet topics in general, please visit our MCU forum and create a thread. Doing so will provide you with a shorter response time. 

This topic has been closed for replies.

54 replies

JYI
Associate II
June 29, 2023

Hi, Adam,

I am referencing you and others posts for the STM32Hx Ethernet issues to try to make my own board to work.

Unfortunately, my board is still not working after about two weeks debugging.

Basically, I am using STM32H723VG with LAN8740 for MII with development tools STM32CubeIde Version 1.11.2 and STM32Cube_FW_H7_V1.11.0 + LWIP without RTOS.

Referencing the posts here, I've made some adjustments for MPU and _Flash.ld.

The Rx Buffer is located at D1(0x2400C000) and set LWIP_RAM_HEAP_POINTER to 0x30000400.

I have tested the hardware interface by verification LAN8740 registers and cable connection indicating that hardware is working since link status and auto-negotiation working properly and Rx and Tx signals are observed once the DHCP is starting. But STM has not received the message from the router since DHCP will be time out.

I've reviewed lots of posts about H7 ethernet issue, but still couldn't figure out what is missing.

Any suggestions will be appreciated.

I've posted some info below for the reference.

Thanks.

Junbo

 

// MPU setting

static void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct;
 
/* Disable the MPU */
HAL_MPU_Disable();
 
/* Configure the MPU as Strongly ordered for not defined regions
* Disable speculative access to unused memories
*/
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x00;
MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
MPU_InitStruct.SubRegionDisable = 0x87;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
 
HAL_MPU_ConfigRegion(&MPU_InitStruct);
 
/* Configure the MPU attributes as Device not cacheable
   for ETH DMA descriptors */
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x30000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_1KB;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
 
HAL_MPU_ConfigRegion(&MPU_InitStruct);
 
/* Configure the MPU attributes as Normal Non Cacheable
     for LwIP RAM heap which contains the Tx buffers  */
MPU_InitStruct.Number = MPU_REGION_NUMBER2;
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x30000400;
MPU_InitStruct.Size = MPU_REGION_SIZE_32KB;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
    HAL_MPU_ConfigRegion(&MPU_InitStruct);
*/
    /*
     * Enable the MPU
     */
    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
 
// _Flash.ld 
 
// RX buffer
.lwip_rx_pool_sec (NOLOAD) :
{
. = ABSOLUTE(0x2400C000);
*(.Rx_PoolSection)
} >RAM_D1 AT> FLASH

/* lwip: add placement of DMA descriptors */
.lwip_dma_desc_sec (NOLOAD) :
{
. = ABSOLUTE(0x30000000);
*(.RxDecripSection)

. = ABSOLUTE(0x30000200);
*(.TxDecripSection)
} >RAM_D2 AT> FLASH
 
// .map

.lwip_rx_pool_sec
0x000000002400b740 0x5453 load address 0x0000000008030454
0x000000002400c000 . = ABSOLUTE (0x2400c000)
*fill* 0x000000002400b740 0x8c0
*(.Rx_PoolSection)
.Rx_PoolSection
0x000000002400c000 0x4b93 ./LWIP/Target/ethernetif.o
0x000000002400c000 memp_memory_RX_POOL_base

.lwip_dma_desc_sec
0x0000000030000000 0x2c0 load address 0x0000000008030454
0x0000000030000000 . = ABSOLUTE (0x30000000)
*(.RxDecripSection)
.RxDecripSection
0x0000000030000000 0xc0 ./LWIP/Target/ethernetif.o
0x0000000030000000 DMARxDscrTab
0x0000000030000200 . = ABSOLUTE (0x30000200)
*fill* 0x00000000300000c0 0x140
*(.TxDecripSection)
.TxDecripSection
0x0000000030000200 0xc0 ./LWIP/Target/ethernetif.o
0x0000000030000200 DMATxDscrTab

// DHCP log

Hard Reset PHY LAN8740....
LWIP Init....
netif: added interface st IP
addr
0.0.0.0
netmask
0.0.0.0
gw
0.0.0.0


netif: setting default interface st

Link UP(5)
FULL-DUPLEX(10M)
dhcp_start(netif=0x2400507c) st0

dhcp_start(): mallocing new DHCP client

dhcp_start(): allocated dhcp
dhcp_start(): starting DHCP configuration

udp_bind(ipaddr =
0.0.0.0
, port = 68)

udp_bind: bound to
0.0.0.0
, port 68)

udp_connect: connected to
0.0.0.0
, port 67)

dhcp_discover()

dhcp_create_msg()

transaction id: xid(4bb5f646)

dhcp_discover: making request

dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER)

udp_send: added header in given pbuf 0x24009958

udp_send: sending datagram of length 316

udp_send: UDP packet length 316

udp_send: UDP checksum 0xf701

udp_send: ip_output_if (,,,,0x11,)

ip4_output_if: st0

IP header:

+-------------------------------+

| 4 | 5 | 0x00 | 336 | (v, hl, tos, len)

+-------------------------------+

| 0 |000| 0 | (id, flags, offset)

+-------------------------------+

| 255 | 17 | 0xba9d | (ttl, proto, chksum)

+-------------------------------+

| 0 | 0 | 0 | 0 | (src)

+-------------------------------+

| 255 | 255 | 255 | 255 | (dest)

+-------------------------------+

ip4_output_if: call netif->output()

etharp_output()

ethernet_output()

ethernet_output: sending packet 0x24009958

dhcp_discover: deleting()ing

dhcp_discover: SELECTING

dhcp_discover(): set request timeout 2000 msecs

dhcp_fine_tmr(): request timeout

dhcp_timeout()

dhcp_timeout(): restarting discovery

 

HLe.2
Visitor II
July 14, 2023

Hello Mr. Adam BERLINGER

Thank you so much for the very helpful article.

I'm making a simple board based on STM32H7 and LAN8720 (currently I don't have LAN8742). I just started using STM32, I follow your tutorial and samples code on github, ping is OK but it disconnects after some time (please see the log below).

Do I need to change any parameters? Please give me some suggestions.

 

Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=2ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=2ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=2ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=3ms TTL=255
Reply from 192.168.1.123: bytes=32 time=7ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=3ms TTL=255
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Reply from 192.168.1.123: bytes=32 time=2ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=3ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=3ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time<1ms TTL=255
Reply from 192.168.1.123: bytes=32 time=1ms TTL=255

Associate II
August 17, 2023

Bumping this.

I have the exact issue others are talking about in this thread with the pbuf assert

Assertion "pbuf_free: p->ref > 0" failed at line 753 in ../Middlewares/Third_Party/LwIP/src/core/pbuf.c 

 There is so much conflicting information and so many different memory configurations being discussed on these forums and in the ST code. The information from ST has been extremely hard to follow. For example, why does the memory config from this repo differ from the CubeH7 V1.11? 

I am using CubeH7 V1.11.0 with the exact memory layout it recommends:

"

.lwip_sec (NOLOAD) :
{
. = ABSOLUTE(0x30000000);
*(.RxDescripSection)

. = ABSOLUTE(0x30000200);
*(.TxDescripSection)

. = ABSOLUTE(0x30000400);
*(.Rx_PoolSection)

} >RAM_D2

"

@Adam BERLINGER @STOne-32 Can we please get an update with a working setup, which does not have pbuf assert issues, with v1.11? *Have the CubeH7 Stm32H723 examples ever actually been seen to work without memory issues?*

Thanks,

Snm.1
Associate III
August 17, 2023

Hello I want to use stm32h747 s ethernet periferal. But ı have to use Rmii and without rtos mode. I gues can you help me?? 

STOne-32
ST Technical Moderator
August 17, 2023

Dear @arena_chris1seto ,

Our technical teams are working on it right now in the Opened ticket and will be back to you shortly,  we need absolutely to replicate the behavior using our environment of board and thank you again for your patience and collaboration to go to the end.

Ciao

STOne-32

Adam BERLINGER
ST Employee
August 18, 2023

Dear all, @HLe.2, @arena_chris1seto 

unfortunately when LAN8720 is used in REF_CLK_OUT mode (RMII clocks generated by PHY), the timing is not compatible with STM32H7. In that case the RXD output hold is 1.4ns minimum on PHY side, while STM32H7 requires at least 2ns.

Also the datasheets of LAN8720 warns about this compatibility issue.

lan8720_phytiming.png

Such issue is not present when using LAN8742, or supplying 50MHz RMII clock externally. Also please note that STM32H7 PLL output through MCO (Micro-controller clock output) is not suitable for such signal, due to long-term jitter requirements.

Note: STM32F2/F4 and STM32F7 should be still compatible with LAN8720, since they have different timing constraints than STM32H7. But it is better to double-check the particular device.

Best regards,

Adam Berlinger

Associate II
August 22, 2023

Thanks @Adam BERLINGER , yeah I will admit we were caught by this. I'll rework a new RMII reference clock onto the board. Any thoughts on the pbuf issues? 

I bought some STM32 Nucleo dev boards to hopefully replicate the issue on official ST hardware with completely unmodified example code.

Laurids_PETERSEN
ST Community Manager
August 22, 2023

Hi everyone! I'm excited to see all the comments and questions regarding this article.
 
However, to prevent bloating the comment section and to give you the best possible guidance to your question, I strongly recommend creating a post in our STM32 MCU forum (click here). 

This gives you the best possible opportunity to get the answer you need. We have active members that are happy to answer your questions. 

Best regards,
Laurids

Associate III
September 29, 2023

Hello everyone, 

I know it's been some time since the beginning of the discussion, but the topic is as hot as the first time it was shared.

@IOvch already solved my issues a long time ago, but i couldn't find the uploaded files he talks about in one of his replies. I'm developing the lwip stack on M4 device (stm32H755 nucleo) and it seems to be very tricky, also listening all the relpies and comments, the memory allocation. I have one question especially: is MPU mandatory for M4 config? They are still out of my understanding the definitions of cacheable, bufferable and shareable, could you providwe some documentation about it please?

Thanks in advance

Zaaack

victagayun
Senior III
October 16, 2023

Hello,

It is best to provide IOC files on your next release of the CubeMX update.