2017-09-15 10:00 AM
Hi guys,
I am developing software for Stm32F7 with ethernet intefrace (nucleo 144 board). I have prepared and compiled LWIP stack with netconn api enabled. I generated configuration files with cubemx using default settings. I start the stack in a separate thread and use a standard TCP/IP code to mirror incoming data (the RTOS echo example):
void EthernetTask(void const * argument)
{
/* USER CODE BEGIN EthernetTask */
LWIP_UNUSED_ARG(argument);
/* initialize LightWeight IP Stack */
MX_LWIP_Init();
/* Create variables needed for servicing a connection */
struct netconn *conn, *newconn;
err_t err, accept_err;
struct netbuf *buf;
void *data;
u16_t len;
/* Create a new connection identifier. */
conn = netconn_new(NETCONN_TCP);
if (conn != NULL)
{
/* Bind connection to well known port number 7. */
err = netconn_bind(conn, NULL, 7);
if (err == ERR_OK)
{
/* Tell connection to go into listening mode. */
netconn_listen(conn);
/* Infinite loop */
while (1)
{
/* Grab new connection. */
accept_err = netconn_accept(conn, &newconn);
/* Process the new connection. */
if (accept_err == ERR_OK)
{
while (netconn_recv(newconn, &buf) == ERR_OK)
{
do
{
netbuf_data(buf, &data, &len);
netconn_write(newconn, data, len, NETCONN_COPY);
}
while (netbuf_next(buf) >= 0);
netbuf_delete(buf);
}
/* Close connection and discard connection identifier. */
netconn_close(newconn);
netconn_delete(newconn);
}
}
}
else
{
netconn_delete(newconn);
}
}
/* USER CODE END EthernetTask */
}
The stack works fine and I can receive data and send it back to the user. The problem is that the reaction time of the stack is very long, in the sense that the echo takes like even 1 second to bounce back to the user. It does not seem that my uC is busy doing anything else, it more seems like the stack waits quite some time before reacting to data. It is even reflected in ping, every second time the answer seems to be coming too late:
Reply from 192.168.3.10: bytes=32 time<1ms TTL=255
Request timed out.Reply from 192.168.3.10: bytes=32 time<1ms TTL=255Request timed out.Reply from 192.168.3.10: bytes=32 time<1ms TTL=255Request timed out.Reply from 192.168.3.10: bytes=32 time<1ms TTL=255Request timed out.Reply from 192.168.3.10: bytes=32 time<1ms TTL=255Request timed out.Reply from 192.168.3.10: bytes=32 time<1ms TTL=255Request timed out.If I send big chunks of data, that fill up the receive buffer (my PBUF_POOL_SIZE is set to 592) the response come immediately (also when I keep sending the data ping arrives every time). To me its seems like the LWIP stack waits for some time to fill up the buffer and if nothing arrives for a certain time (which seems to be quite long to me) then he processes the buffer contents. Is there some configuration option for the LWIP / ETH where this behavior (timeout?!) can be controlled? It would need my device to react on a few ms basis, rather than ~1s one.
Thanks,
Jeremi
Solved! Go to Solution.
2018-01-03 06:29 AM
After quite some time of experimentation I discovered that the issue is in the ethernetif.c driver generated by cubeMX (thanks to the
thread, where they reported similar problem however due to a different reason, but the same file). Here I post my solution (even though I did not go too deeply in understanding what the problem exactly was it seem to be related to the location of the DMA descriptiors in the memory - SRAM1 or SRAM2 banks) so if sb would bump into a similar problem in the future, perhaps it will save him some time.Comparing ethernetif.c from cubeMX and from the firmware library I noticed that this part was missing:
/*
@Note: The DMARxDscrTab and DMATxDscrTab must be declared in a non cacheable memory region In this example they are declared in the first 256 Byte of SRAM1 memory, so this memory region is configured by MPU as a device memory (please refer to MPU_Config() in main.c).In this example the ETH buffers are located in the SRAM2 memory,
since the data cache is enabled, so cache maintenance operations are mandatory. */#if defined ( __CC_ARM )ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB] __attribute__((at(0x20010000)));/* Ethernet Rx MA Descriptor */ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB] __attribute__((at(0x20010080)));/* Ethernet Tx DMA Descriptor */
uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __attribute__((at(0x2004C000))); /* Ethernet Receive Buffer */
uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __attribute__((at(0x2004D7D0))); /* Ethernet Transmit Buffer */
#elif defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4#pragma location=0x20010000
__no_init ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB];/* Ethernet Rx MA Descriptor */#pragma location=0x20010080
__no_init ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB];/* Ethernet Tx DMA Descriptor */#pragma location=0x2004C000
__no_init uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE]; /* Ethernet Receive Buffer */#pragma location=0x2004D7D0
__no_init uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; /* Ethernet Transmit Buffer */#elif defined ( __GNUC__ ) /*!< GNU Compiler */
ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB] __attribute__((section('.RxDecripSection')));/* Ethernet Rx MA Descriptor */
ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB] __attribute__((section('.TxDescripSection')));/* Ethernet Tx DMA Descriptor */
uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __attribute__((section('.RxarraySection'))); /* Ethernet Receive Buffer */
uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __attribute__((section('.TxarraySection'))); /* Ethernet Transmit Buffer */
#endif
Adding it to my ethernetif.c fixed the problem of lost packets!
2018-01-03 06:29 AM
After quite some time of experimentation I discovered that the issue is in the ethernetif.c driver generated by cubeMX (thanks to the
thread, where they reported similar problem however due to a different reason, but the same file). Here I post my solution (even though I did not go too deeply in understanding what the problem exactly was it seem to be related to the location of the DMA descriptiors in the memory - SRAM1 or SRAM2 banks) so if sb would bump into a similar problem in the future, perhaps it will save him some time.Comparing ethernetif.c from cubeMX and from the firmware library I noticed that this part was missing:
/*
@Note: The DMARxDscrTab and DMATxDscrTab must be declared in a non cacheable memory region In this example they are declared in the first 256 Byte of SRAM1 memory, so this memory region is configured by MPU as a device memory (please refer to MPU_Config() in main.c).In this example the ETH buffers are located in the SRAM2 memory,
since the data cache is enabled, so cache maintenance operations are mandatory. */#if defined ( __CC_ARM )ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB] __attribute__((at(0x20010000)));/* Ethernet Rx MA Descriptor */ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB] __attribute__((at(0x20010080)));/* Ethernet Tx DMA Descriptor */
uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __attribute__((at(0x2004C000))); /* Ethernet Receive Buffer */
uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __attribute__((at(0x2004D7D0))); /* Ethernet Transmit Buffer */
#elif defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4#pragma location=0x20010000
__no_init ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB];/* Ethernet Rx MA Descriptor */#pragma location=0x20010080
__no_init ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB];/* Ethernet Tx DMA Descriptor */#pragma location=0x2004C000
__no_init uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE]; /* Ethernet Receive Buffer */#pragma location=0x2004D7D0
__no_init uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; /* Ethernet Transmit Buffer */#elif defined ( __GNUC__ ) /*!< GNU Compiler */
ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB] __attribute__((section('.RxDecripSection')));/* Ethernet Rx MA Descriptor */
ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB] __attribute__((section('.TxDescripSection')));/* Ethernet Tx DMA Descriptor */
uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __attribute__((section('.RxarraySection'))); /* Ethernet Receive Buffer */
uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __attribute__((section('.TxarraySection'))); /* Ethernet Transmit Buffer */
#endif
Adding it to my ethernetif.c fixed the problem of lost packets!
2018-02-06 03:04 AM
Thank you for posting your solution. I had the exact same problem, and this fixed it.
2018-06-06 03:12 AM
Thank you, had the same problem ! Nucleo-F746ZG and CubeMX.
Lots of TCP Out-of-Order and Dup-ACK.
Now wireshark notices no Errors anymore.
2018-06-20 08:54 AM
Hello
Wojcicki.Jeremi
,Unfortunately, we didn't reproduce the issue after check by our team with LwIP example and relocated ETH buffers and descriptors in DTCM-RAM.
It seems your code misses the relocation of ETH descriptor from DTCM-RAM to SRAM1/SRAM2. Because if this relocation is not done, the linker will locate them at the default memory location which is DTCM-RAM.
So, in your case the default config is ETH buffers and descriptors which are located in DTCM-RAM, and you relocated them in SRAM1/SRAM2.
In fact,CubeMx doesn't relocate these buffers to SRAM1/SRAM2, and when generated a code with CubeMx, the ETH buffers and descriptors are located in DTCM-RAM.
With Regards,
Imen.
2019-02-25 10:03 PM
hi
i am also facing the same issue of ping timeout even after moving the ethernet buf & descriptors to SRAM1/SRAM2. the example works f9 in stm32f769 eval board but i observe randon ping loss in custom board having same processor.
2019-09-13 02:49 AM
Jeremi, thanks a lot for this post! We experienced the same problem here with CubeMX generated code on a custom board that uses STM32F777VI. I would have never imagined that it's the ethernet driver causing these awfully slow response times. With your solution it works like a charm.
2020-08-03 01:31 AM
This is still broken in 2020!!
This fix still works, if it doesn't make sure the right area's are added to MPU_Config:
/* Configure the MPU as Normal Non Cacheable for Ethernet Buffers in the SRAM2 */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x2004C000;
MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Configure the MPU as Device for Ethernet Descriptors in the SRAM2 */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x2004C000;
MPU_InitStruct.Size = MPU_REGION_SIZE_256B;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
In combination with(Keil):
ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB] __attribute__((at(0x2004C000)));/* Ethernet Rx DMA Descriptors */
ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB] __attribute__((at(0x2004C080)));/* Ethernet Tx DMA Descriptors */
uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __attribute__((at(0x2004C100))); /* Ethernet Receive Buffers */
uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __attribute__((at(0x2004D8D0))); /* Ethernet Transmit Buffers */
2020-09-07 05:21 AM
Can you please show full MPU_Config functions? It does not work for me. What are other settings , like i.e. flash interface, art accelerator, instuction prefetch and CPU cache?