2025-09-01 3:29 AM
I'm running the CubeMX-generated lwIP implementation on an STM32H723. Memory addresses and configuration has been modified according to what is described at https://community.st.com/t5/stm32-mcus/how-to-create-a-project-for-stm32h7-with-ethernet-and-lwip-stack/ta-p/49308
Now when running this implementation, I stumble upon different illegal memory accesses where data is located in memory areas outside of the addresses of range 0x30000200 .. 0x30000200+32232.
This happens more or less randomly. When I add some own address-checks at one position in code to ensure a pointer is in that area, lwIP crashes at an other position. So this looks like some memory leak or some other fundamental problem.
Next I enabled MEMP_SANITY_CHECK in lwIP settings to track down these problems. With that, immediately on connection of an external client to my server, I end up in a failed MEMP-sanity check:
HardFault_Handler() at stm32h7xx_it.c:85 0x8002f10
<signal handler called>() at 0xffffffe9
memp_sanity() at memp.c:108 0x800d920
do_memp_free_pool() at memp.c:389 0x800dafa
memp_free_pool() at memp.c:410 0x800db5a
pbuf_free_custom() at ethernetif.c:446 0x800cb18
pbuf_free() at pbuf.c:768 0x800e8cc
tcp_input() at tcp_in.c:382 0x80106a8
ip4_input() at ip4.c:709 0x8017756
ethernet_input() at ethernet.c:186 0x8018a66
ethernetif_input() at ethernetif.c:351 0x800ca8c
MX_LWIP_Process() at lwip.c:144 0x800c786
So for me this looks like some problem with the lwIP-implementation provided by ST or with the configuration.
Any ideas how I fix or at least track down this issue?
Thanks!
Solved! Go to Solution.
2025-09-05 8:07 AM
After reviewing the project with @HMüll.4, it was confirmed that the memory corruption was caused by using 12 Rx buffers while MEM_SIZE in lwipopts.h was set for only 10 buffers (15,360 bytes). This mismatch exceeded the allocated 16 KB memory and led to the issue.
2025-09-01 4:12 AM
To make this all really work, Cube is not up to that complex task. (And the HAL ETH stuff is terrible...).
Make sure that all reserved RAM for LWIP is in AXI D1 RAM. This works for me.
Reminder: ETH DMA cannot access flash or DTCM.
Linker file:
...
/* RAM internal */
SRAXI_D1(xrw) : ORIGIN = 0x24000000, LENGTH = 320K
SRAM1_D2(xrw) : ORIGIN = 0x30000000, LENGTH = 16K
SRAM2_D2(xrw) : ORIGIN = 0x30004000, LENGTH = 16K
SRAM4_D3(xrw) : ORIGIN = 0x38000000, LENGTH = 16K /* only D3 access */
...
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* lwIP in SRAXI_D1 */
/* lwIP HEAP section */
.LwipHeapSection (NOLOAD):
{
. = ALIGN(4);
*(.LwipHeapSection)
*(.LwipHeapSection*)
. = ALIGN(4);
} >SRAXI_D1
/* } >SRAXI_D1_LWIP */
/* lwIP POOL section */
.LwipPoolSection (NOLOAD):
{
. = ALIGN(4);
*(.LwipPoolSection)
*(.LwipPoolSection*)
. = ALIGN(4);
} >SRAXI_D1
/* } >SRAXI_D1_LWIP */
in LWIP file arch.h :
#ifndef LWIP_DECLARE_MEMORY_ALIGNED
#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] __attribute__((section(".LwipPoolSection")))
#endif
#ifndef LWIP_DECLARE_MEMORY_ALIGNED_HEAP
#define LWIP_DECLARE_MEMORY_ALIGNED_HEAP(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] __attribute__((section(".LwipHeapSection")))
#endif
and here's LWIP/Target/lwip.opts.h :
/**
******************************************************************************
* File Name : Target/lwipopts.h
* Description : This file overrides LwIP stack default configuration
* done in opt.h file.
******************************************************************************
*/
/* Define to prevent recursive inclusion --------------------------------------*/
#ifndef __LWIPOPTS__H__
#define __LWIPOPTS__H__
/* user stuff */
#include "main.h"
/* STM32CubeMX Specific Parameters (not defined in opt.h) ---------------------*/
/* Parameters set in STM32CubeMX LwIP Configuration GUI -*/
/*----- WITH_RTOS disabled (Since FREERTOS is not set) -----*/
#define WITH_RTOS 0
/*----- CHECKSUM_BY_HARDWARE enabled -----*/
#define CHECKSUM_BY_HARDWARE 1
/*-----------------------------------------------------------------------------*/
/* LwIP Stack Parameters (modified compared to initialization value in opt.h)
* #### opt.h is overwritten! ####
*/
/*----- Value in opt.h for NO_SYS: 0 = no operating system -----*/
#define NO_SYS 1
/*----- Value in opt.h for LWIP_DHCP: 0 -----*/
#define LWIP_DHCP 1
/*----- Default Value for LWIP_DNS: 0 ---*/
#define LWIP_DNS 1
/*----- Default Value for LWIP_IGMP: 0 ---*/
#define LWIP_IGMP 1
/*----- Value in opt.h for SYS_LIGHTWEIGHT_PROT: 1 -----*/
#define SYS_LIGHTWEIGHT_PROT 0
/*----- Value in opt.h for MEM_ALIGNMENT: 1 -----*/
#define MEM_ALIGNMENT 4
//#define MEM_ALIGNMENT 8
/*----- Value in opt.h for MEM_SIZE: lwIP heap size ----- */
#define MEM_SIZE (16 * 1024)
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/*
* #### IMPORTANT #### zero-copy RX uses PBUF_POOL,
* -> must be > ETH_RX_DESC_CNT, see ethernetif.h
* PBUF_POOL_SIZE: the number of buffers in the pbuf pool.
*/
#if !defined PBUF_POOL_SIZE || defined __DOXYGEN__
#define PBUF_POOL_SIZE 64
#endif
/*----- Default Value for PBUF_POOL_BUFSIZE: 592 ---*/
/* must have same size as TCP TX buffer */
#define PBUF_POOL_BUFSIZE 1528 /* max frame length + 4B CRC */
/* ------------------------------------------------------------------------------------ */
/*----- Value in opt.h for LWIP_ETHERNET: LWIP_ARP || PPPOE_SUPPORT -*/
#define LWIP_ETHERNET 1
/*----- Default Value for LWIP_RAW: 0 ---*/
#define LWIP_RAW 1
/*----- Value in opt.h for LWIP_DNS_SECURE: (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) -*/
#define LWIP_DNS_SECURE 7
#if( 1 )
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* TCP settings */
/* LWIP_TCP_SACK_OUT==1: TCP will support sending selective acknowledgements (SACKs) */
#define LWIP_TCP_SACK_OUT 0
//#define LWIP_TCP_SACK_OUT 1
/*----- Default Value for TCP_MSS: 536, MAX is 1460 --- */
#define TCP_MSS 1460 /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */
/*----- Default Value for TCP_WND: (2 * TCP_MSS) --- */
#define TCP_WND (4 * TCP_MSS)
/*----- Default Value for TCP_SND_BUF: (2 * TCP_MSS) --- */
#define TCP_SND_BUF (4 * TCP_WND)
/*----- Value in opt.h for TCP_SND_QUEUELEN: (4*TCP_SND_BUF + (TCP_MSS - 1))/TCP_MSS -----*/
#define TCP_SND_QUEUELEN (2 * (TCP_SND_BUF / TCP_MSS)) // 248
//#define TCP_SND_QUEUELEN (2 * (TCP_SND_BUF / TCP_MSS))
/*----- Value in opt.h for TCP_SNDLOWAT: LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) -*/
#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1)
/*----- Value in opt.h for TCP_SNDQUEUELOWAT: LWIP_MAX(TCP_SND_QUEUELEN)/2, 5) -*/
#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5)
/*----- Value in opt.h for TCP_WND_UPDATE_THRESHOLD: LWIP_MIN(TCP_WND/4, TCP_MSS*4) -----*/
#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4))
//#define TCP_WND_UPDATE_THRESHOLD 536
#endif
/*----- Value in opt.h for LWIP_NETIF_LINK_CALLBACK: 0 -----*/
#define LWIP_NETIF_LINK_CALLBACK 1
/*----- Value in opt.h for LWIP_NETCONN: 1 -----*/
#define LWIP_NETCONN 0
/*----- Value in opt.h for LWIP_SOCKET: 1 -----*/
#define LWIP_SOCKET 0
/*----- Value in opt.h for RECV_BUFSIZE_DEFAULT: INT_MAX -----*/
#define RECV_BUFSIZE_DEFAULT 2000000000
/*----- Default Value for LWIP_SNTP: 0 ---*/
#define LWIP_SNTP 1
/*----- Default Value for SNTP_CHECK_RESPONSE: 0 ---*/
#define SNTP_CHECK_RESPONSE 1
/*----- Default Value for SNTP_COMP_ROUNDTRIP: 0 ---*/
#define SNTP_COMP_ROUNDTRIP 0
/*----- Default Value for LWIP_HTTPD: 0 ---*/
#define LWIP_HTTPD 1
/*----- Default Value for LWIP_HTTPD_CGI: 0 ---*/
#define LWIP_HTTPD_CGI 1
/*----- Default Value for LWIP_HTTPD_SSI: 0 ---*/
#define LWIP_HTTPD_SSI 1
/*----- Value in opt.h for HTTPD_USE_CUSTOM_FSDATA: 0 -----*/
#define HTTPD_USE_CUSTOM_FSDATA 1
/*----- Value in opt.h for LWIP_STATS: 1 -----*/
#define LWIP_STATS 1
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* checksums by software */
/*----- Value in opt.h for CHECKSUM_GEN_IP: 1 -----*/
#define CHECKSUM_GEN_IP 0
/*----- Value in opt.h for CHECKSUM_GEN_UDP: 1 -----*/
#define CHECKSUM_GEN_UDP 0
/*----- Value in opt.h for CHECKSUM_GEN_TCP: 1 -----*/
#define CHECKSUM_GEN_TCP 0
/*----- Value in opt.h for CHECKSUM_GEN_ICMP: 1 -----*/
#define CHECKSUM_GEN_ICMP 0
/*----- Value in opt.h for CHECKSUM_GEN_ICMP6: 1 -----*/
#define CHECKSUM_GEN_ICMP6 0
/*----- Value in opt.h for CHECKSUM_CHECK_IP: 1 -----*/
#define CHECKSUM_CHECK_IP 0
/*----- Value in opt.h for CHECKSUM_CHECK_UDP: 1 -----*/
#define CHECKSUM_CHECK_UDP 0
/*----- Value in opt.h for CHECKSUM_CHECK_TCP: 1 -----*/
#define CHECKSUM_CHECK_TCP 0
/*----- Value in opt.h for CHECKSUM_CHECK_ICMP: 1 -----*/
#define CHECKSUM_CHECK_ICMP 0
/*----- Value in opt.h for CHECKSUM_CHECK_ICMP6: 1 -----*/
#define CHECKSUM_CHECK_ICMP6 0
/*-----------------------------------------------------------------------------*/
#endif /*__LWIPOPTS__H__ */
/* EOF */
2025-09-01 4:45 AM
Hello @HMüll.4 ,
the .rar project of tuna1 may be able to help you (last answer of page 2 of this link)
https://community.st.com/t5/stm32-mcus-embedded-software/h723-ethernet-lwip-ping-problem/td-p/758419/page/2
2025-09-01 8:01 AM
Thank you for both your feedback. But for both of them I see a problem (or something I do not understand): There are RAM-positions defined for DMATxDscrTab and DMARxDscrTab, both located directly after each other and on front of the PBuf-pool. Now when I have a look at thernetif.c, low_level_init(), there I can see this code:
heth.Init.TxDesc = DMATxDscrTab;
heth.Init.RxDesc = DMARxDscrTab;
heth.Init.RxBuffLen = 1536;
Doesn't this RxBuffLen mean, both DMATxDscrTab and DMARxDscrTab should have a size of 1536 bytes/0x600 each?
2025-09-01 8:09 AM
RxBuffLen is the size of 1 Rx buffer.
You have :
ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection"))); /* Ethernet Rx DMA Descriptors */
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection"))); /* Ethernet Tx DMA Descriptors */
By default ETH_RX_DESC_CNT is 4 (it's in stm32h7xx_hal_conf.h)
But RxBuffLen is more related to
__attribute__((section(".Rx_PoolSection"))) extern u8_t memp_memory_RX_POOL_base[];
this memory is done by this macro :
LWIP_MEMPOOL_DECLARE(RX_POOL, ETH_RX_BUFFER_CNT, sizeof(RxBuff_t), "Zero-copy RX PBUF pool");
2025-09-01 8:28 AM
Hello @HMüll.4 ,
As explained by @MA4, the RxBufferLen is used to define the size of Ethernet frames and is used to calculate the size of the RxBytePool that stores received frames.
Could you please attach your project so I can review the issue, or provide a minimal version that reproduces the problem? If the project is private, feel free to contact me privately, and I will provide a secure file transfer method.
Best regards,
2025-09-01 8:34 AM
The descriptors are only used by the ETH driver, and they only have pointers to buffers.
The descriptors have nothing to do with lwIP, and they must be placed in the mentioned RAM sections for the ETH peripheral.
And the RX buffers themselves only have the requirement that they must be placed in some RAM accessible by the ETH DMA, which is all RAM (incl. memory-mapped OCTOSPI / HyperRAM) except TCM.
And for everything else... you are using the ugly HAL_ETH driver, which I didn't like (and partly not understand) for several reasons and thus built my own.
2025-09-01 9:08 AM
> RxBuffLen is the size of 1 Rx buffer.
OK...but where do I define the size of the buffers DMARxDscrTab and DMATxDscrTab belong to?
2025-09-01 11:55 PM
It's a type ETH_DMADescTypeDef, you can't define its size only the number of DMADesc that you want (ETH_RX_DESC_CNT and ETH_TX_DESC_CNT in stm32h7xx_it.h)
typedef struct
{
__IO uint32_t DESC0;
__IO uint32_t DESC1;
__IO uint32_t DESC2;
__IO uint32_t DESC3;
uint32_t BackupAddr0; /* used to store rx buffer 1 address */
uint32_t BackupAddr1; /* used to store rx buffer 2 address */
} ETH_DMADescTypeDef;
If you want to know their sizes easily, you can check it in your .map file (YourProjectLoc/Debug/ProjectName.map) open it with text editor and search for your variable (DMARxDscrTab for example) and there you can see its localization and next to it its size.
2025-09-02 12:07 AM
they are Ethernet DMA descriptors not buffers