tcpstm32ethernetlwip

STM32 LwIP Delay in netconn_write


I implemented a small tcp client on STM32F7 with freeRtos and LwIP and netconn api. I can establish a connection with the server and send some data to the network. My problem is a huge delay between the command and when I can actually see the ethernet data on the network (seconds..). Seems like the data is buffered before sending it in one go.

I'm aware of the TCP_NODELAY flag and I set it (with tcp_nagle_disable(conn->pcb.tcp)), but it doesn't make a difference. Ethernet payload is around 50 bytes, TCP_MSS is 1460. The netconn api sees the data as sent (netbuffer structure is updated, tcp_write() and tcp_output() are called with no errors), but I have the impression that after low_level_output() is called and the data buffer is passed to the DMA (with HAL_ETH_TransmitFrame()) it stays there until something happened and 3 or 4 ethernet packets are sent in a go.

I don't want to wait forever for a reply and I set a timeout on netconn_recv(), enabling LWIP_SO_RCVTIMEO and calling netconn_set_recvtimeout(). I set up the server to answer with an echo but even with a timeout of 500ms I loose most of the replies.

Here some code:

conn = netconn_new(NETCONN_TCP);
if (conn != NULL)
{
    err = netconn_bind(conn, IP_ADDR_ANY, 0);
    if (err == ERR_OK)
    {
        connect_error = netconn_connect(conn, &dest_addr, SRV_PORT);
        if (connect_error == ERR_OK)
        {
            // set a timeout to avoid waiting forever
            netconn_set_recvtimeout(conn, 500);  
            //TCP_NODELAY
            tcp_nagle_disable(conn->pcb.tcp);
            
            osSemaphoreRelease(tcpsem); // signal tcpsend
            if (netconn_recv(conn, &buf) == ERR_OK)
            {
                //Parse message
                do
                {
                     // do stuff..
                }
                while (netbuf_next(buf) >0);
                netbuf_delete(buf);

            } else {
                // TIMEOUT
                
            }
        }
   
        /* Close connection */
        netconn_close(conn);
    } 
    netconn_delete(conn);
}
vTaskDelete(tcpsendTaskHandle);
vTaskDelete(NULL);

tcpsend

void tcpsend (void *data, size_t len)
{
    // send the data to the connected connection
    netconn_write(conn, data, len, NETCONN_NOFLAG);
}

tcpsend

static void tcpsend_thread (void *arg)
{
    for (;;)
    {
        // semaphore must be taken before accessing the tcpsend function
        osSemaphoreAcquire(tcpsem, portMAX_DELAY);

        // build msg
        if (ethPrepare(&ethMsg) == ERR_OK)
        {
            // send the data to the server
            tcpsend(&ethMsg, ethMsg.ncSize);
        }
        vTaskDelay(100);
    }
}

Solution

  • Found the problem: I forgot to set also the TxBuffer memory as not cacheable bufferable..

    Once I added the memory configuration on the loader script and in ethernetif.c also for the tx buffer (I had it only for he rx) I could see the ethernet packets right away.