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(ðMsg) == ERR_OK)
{
// send the data to the server
tcpsend(ðMsg, ethMsg.ncSize);
}
vTaskDelay(100);
}
}
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.