2023-09-18 09:36 AM
Hi everyone,
I own a nucleoH743ZI2 board trying to implement a Modbus TCP/IP protocol over a LwIP package. It's crucial for my application not to add FreeRTOS or any other OSs. The software used for the FW development and configuration is CubeIDE 1.13.1 and CubeMX 6.9.1.
There is a number of examples around the internet describing how to set correctly the project, some of them are not even coherent one to another. I'm aware I am missing some notions, some very low level ones about memory management and most likely those notions prevent me from solving my issue.
I successfully implemented the LwIP stack on the nucleo board, ping is performing correctly. Now I'm trying to operate the modbus protocol as well, the nucleo operates as server and I use my laptop with a dedicated SW tool as client. The connection and data exchange starts for a few seconds, then it goes directly in "Write error" and "Read error". The nucleo board can't be pinged from that moment on.
I believe it is a memory management wrongly configured. I guess the DMA might be pointng to the wrong address or something since it works for a few requests.
Have you encountered the same issue while implementing this peripheral? Maybe you have found some workaround that could be helpful. I've seen some old threads about it, but i expect the drivers to be well fixed as of today.
I'll attach what I believe are the three main files for this kind of debug.
Zack
2023-09-18 09:53 AM
Let me add a comment on why I think the issue is concerning the memory and DMA usage.
I tried multple times to enlarge the MEM_SIZE define, the more I enlarge it, the more time the communication stays on. Is it possibile it the DMA doesn't go back to the start of the RxBuffer?
2023-09-18 10:20 PM
Memory management is a very good start with a H7 and lwIP.
In a H723/H735 (I think that one has another memory layout than the H743) I created some extra sections:
linker file:
/* Specify the memory areas */
MEMORY
{
ITCMRAM (xrw): ORIGIN = 0x00000000, LENGTH = 64K
FLASH (rx): ORIGIN = 0x08000000, LENGTH = 1024K
/* DTCM: 128 kB
* 0x2000 0000 - 0x2001FFFF
* used as "general" RAM
* !!! no DMA access !!!
*/
DTCM_HPST(xrw) : ORIGIN = 0x20000000, LENGTH = 5K /* DTCM heap & stack */
DTCM_NOINIT(xrw) : ORIGIN = 0x20001400, LENGTH = 1K /* DTCM no init */
DTCMRAM(xrw) : ORIGIN = 0x20001800, LENGTH = 122K /* DTCM */
SRAXI_D1(xrw) : ORIGIN = 0x24000000, LENGTH = 128K
SRAXI_D1_LWIP(xrw) : ORIGIN = 0x24020000, LENGTH = 128K
SRAXI_D1_A2IP(xrw) : ORIGIN = 0x24040000, LENGTH = 64K
SRAM1_D2(xrw) : ORIGIN = 0x30000000, LENGTH = 16K
SRAM2_D2(xrw) : ORIGIN = 0x30004000, LENGTH = 16K
SRAM4_D3(xrw) : ORIGIN = 0x38000000, LENGTH = 16K /* only D3 access */
OSPI2_D1(xrw) : ORIGIN = 0x70000000, LENGTH = 0x1000000 /* OCTOSPI 2 */
}
...
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* lwIP in SRAXI_D1 */
/* lwIP HEAP section */
.LwipHeapSection (NOLOAD):
{
. = ALIGN(4);
*(.LwipHeapSection)
*(.LwipHeapSection*)
. = ALIGN(4);
} >SRAXI_D1_LWIP
/* lwIP POOL section */
.LwipPoolSection (NOLOAD):
{
. = ALIGN(4);
*(.LwipPoolSection)
*(.LwipPoolSection*)
. = ALIGN(4);
} >SRAXI_D1_LWIP
then in lwIP's arch.h I placed RX pool and lwIP heap in these AXI SRAM areas:
/** Allocates a memory buffer of specified size that is of sufficient size to align
* its start address using LWIP_MEM_ALIGN.
* You can declare your own version here e.g. to enforce alignment without adding
* trailing padding bytes (see LWIP_MEM_ALIGN_BUFFER) or your own section placement
* requirements.\n
* e.g. if you use gcc and need 32 bit alignment:\n
* \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] \_\_attribute\_\_((aligned(4)))\n
* or more portable:\n
* \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u32_t variable_name[(size + sizeof(u32_t) - 1) / sizeof(u32_t)]
*/
#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
2023-09-18 10:21 PM
PS: make also sure that the ETH descriptors are in the correct RAM section.
2023-09-20 01:19 AM - edited 2023-09-20 01:21 AM
Hi LCE,
thanks for your quick response. Let me start replying to the latest point. Being an H7 board, I'm using (depends on the attempt I'm trying) addresses in the range 0x30020000 up to 0x30040000, therefore SRAM 2 and 3, as I understand. They should be reasonable memory areas with a reasonable available space.
I have some questions on the memory allocation on your first reply though. CubeMX 6.9.1 does't allow to provide RxBuffer length:
For this reason I had to define in the ethernetif.c file the dedicated RxBufferLength (Rx_PoolSection in my case) and then allocate a share of SRAM memory to it in the linker script. I don't get the need to add the heap section which is aready defined in the LwIP section:
Is the usage of AXI RAM mandatory? I must say I don't know what the liker script you posted is doing with those instructions.
All of these configurations must be coherently aligned with the MPU, is that correct?
My first doubt is the .ioc configuration, if all the registers have been confgured correctly. That is the first thing I must make sure of. Secondly, the area memory.
Thanks in advance,
Zaack
2023-09-20 01:58 AM
Concerning AXI RAM:
Check the DS and RM, I think ETH DMA cannot access AXI RAM in H74x, but I'm not sure.
I have no idea about MPU, and also about cache handling, which might be another problem source if caches are activated.
2023-09-27 01:47 AM
The latest ST examples, built for the latest variant of STM32H7 ETH "HAL" driver and LwIP, are here.
Unfortunately part of known issues still is not resolved. Start with cache disabled to avoid at least cache related issues.
2023-10-06 04:48 AM
I see there are not implementations in which the M4 only is used for the lwIP management.
It is not clear to me if the decision is driven by implementation issues, therefore it cannot be done, or just because nobody though of doing it.
Additionally, the MPU settings in dual core MCUs is not clear. Do I need to implement the same MPU configs for both M7 and M4? Should i set MPUs only for one of the cores and it applies to both? Should I apply the MPUs only to the core that is actually using that peripheral? But then, how can the other core know that the memory is "not avalable"?
Thanks in advance for the help,
Zack
2023-10-06 11:02 AM
@Zzaaack STM32H743 is a single core H7, there is no M4. Have you moved to other model? Anyway, a MPU is a part of its core so in dual core STM32 each core has its own MPU and own "background" settings.
2023-10-06 11:48 AM
Hi @Pavel A.
I'm sorry, I have moved in the meantime to stm32h755, applying what I had discovered on this MCU to a dual core.
I'm very sorry for the mistake, but I admit the issue is still the same, configuring correctly the MPU, the dual core adds some more complexity to the problem.
Thanks for pointing out to me.
Zack