cancel
Showing results for 
Search instead for 
Did you mean: 

Streaming buffers of float numbers via ETH (STM32H7 nucleo)

Marina Brener
Associate III

Posted on December 07, 2017 at 22:04

Hello, 

I have created via the cubeMX project for my stm32H7 nucleo board, it has Eth + lwip+ freeRTos + dhcp + dma + tcpServer.

I updated the linker file and changed the cube generated code related to the ETH pins, added dhcp thread and added a TCP server thread. 

PS: my MPU is set to 1500, and I do not use cache.

Now I want to stream buffers of float numbers via ethernet,

the tcp server in the example code uses netconn_write to send data, so I used this method as well with the flag NO_COPY, but then, if I send the data to fast the write hangs. If I use vTaskDelay(200) between my writes, all works fine.

I would prefer to perform writes with a callback, so i want to use this callback HAL_ETH_TxCpltCallback but it is not fired, I can see that the packet is transmitted and I can perform async read from the tcp client, after that HAL_ETH_IRQHandler is firing and this code should be executed but it never does: 

/* Packet transmitted */

if (__HAL_ETH_DMA_GET_IT(heth, ETH_DMACSR_TI) && __HAL_ETH_DMA_GET_IT_SOURCE(heth, ETH_DMACIER_TIE))

{

/* Transfer complete callback */

HAL_ETH_TxCpltCallback(heth);

/* Clear the Eth DMA Tx IT pending bits */

__HAL_ETH_DMA_CLEAR_IT(heth, ETH_DMACSR_TI | ETH_DMACSR_NIS);

heth->ErrorCode = HAL_ETH_ERROR_NONE;

heth->gState = HAL_ETH_STATE_READY;

}

I saw that it was investigated here:

https://community.st.com/message/172318-re-example-using-hal-eth-without-lwip-for-raw-ethernet-frames?commentID=172318&sharpcomment-172318

 aleksandar.radulovic

‌ 

Any help/advise is appreciated! 

Marina

null

4 REPLIES 4
Joerg Wagner
Senior III
Posted on December 08, 2017 at 19:03

Hi Marina.

You use TCP/IP, what should be the advantage to use a Callback or to know the DMA processed the data?

In case of UDP it makes sense, but with TCP/IP you will have a manager for the communication.

A different sequence order, spurious, retransmission, delay or timeout, all will be managed.

You don't know which data is currently processed. Other questions: who is the receiver, is it a keep alive

connection, and if not who will close the connection? Will it be in a FIN packet or the receiver closes it?

Greetings, Joerg

Posted on December 08, 2017 at 21:51

Hi Joerg,

Agree, I get your point about TCP connection and callback relevance.

As you suggested, will explore my alternatives, a different sequence order, spurious, re transmission, delay or timeout.

I am adding a print screen of my cubeMX lwip key options tab.

Can you please take a look?

This is the code I want to execute from my tcp server only without the Delay between the writes:

for(int i= 0; i< 256; i++)

{

buffFloat[i] = 1.0*i;

}

while(1)

{

err = netconn_write(newconn, buffFloat, 1024, NETCONN_NOCOPY);

vTaskDelay(200);

err = netconn_write(newconn, buffFloat, 1024 , NETCONN_NOCOPY);

vTaskDelay(200);

err = netconn_write(newconn, buffFloat, 1024 , NETCONN_NOCOPY);

vTaskDelay(200);

}

About the TCP client,

it will continue to read values until it decides to close the connection.

So the client closes the connection.

I guess, it is also possible that the client is too slow.

Thanks for the help,

Marina

0690X000006096bQAA.png
Posted on December 09, 2017 at 00:11

Hey ho Marina.

You send 1024 Bytes (netconn_write) but you have a tiny segment size of 536 bytes? Pump it up.

Some parameters should be tweaked to have a better performance.

It's also a good idea to turn on LWIP_DEBUG to see what's going on with the traffic.

Go to the Debug tab and turn on: LWIP_DBG_TYPES_ON, TCP_DEBUG, TCP_OUTPUT_DEBUG, TCPIP_DEBUG.

Turn on LWIP_Stats (Tab Statistics) to get a feeling for the memory pool buffers (pbuf).

Take a look at the maximum usage, like a peak, if you need more.

Do not forget providing enough space on the FreeRTOS Heap as well.

If you do not use a printf for output you can simply run your code in debug mode, wait for some actions pause it

and in the Expressions tab analyse the variable lwip_stats. It's a structure with all the statistic information.

Another good tool for you would be Systemview from Segger for profiling the execution over the time.

Greetings,  Joerg

PS: I do not set the LWIP settings in CubeMX anymore, I modify lwiptopts.h later.

Here are my settings without debug and statistics activated:

* STM32CubeMX Specific Parameters (not defined in opt.h) ---------------------*/

/* Parameters set in STM32CubeMX LwIP Configuration GUI -*/

/*----- WITH_RTOS enabled (Since FREERTOS is set) -----*/

♯ define WITH_RTOS 1

/*----- CHECKSUM_BY_HARDWARE enabled -----*/

♯ define CHECKSUM_BY_HARDWARE 1

/*-----------------------------------------------------------------------------*/

/* LwIP Stack Parameters (modified compared to initialization value in opt.h) -*/

/* Parameters set in STM32CubeMX LwIP Configuration GUI -*/

/*----- Default Value for MEMP_NUM_UDP_PCB: 4 ---*/

♯ define MEMP_NUM_UDP_PCB 6

/*----- Default Value for MEMP_NUM_TCP_PCB: 5 ---*/

♯ define MEMP_NUM_TCP_PCB 10

/*----- Value in opt.h for MEM_ALIGNMENT: 1 -----*/

♯ define MEM_ALIGNMENT 4

/*----- Default Value for MEM_SIZE: 1600 ---*/

♯ define MEM_SIZE 10240

/*----- Default Value for MEMP_NUM_PBUF: 16 ---*/

♯ define MEMP_NUM_PBUF 10

/*----- Default Value for MEMP_NUM_TCP_PCB_LISTEN: 8 ---*/

♯ define MEMP_NUM_TCP_PCB_LISTEN 5

/*----- Default Value for MEMP_NUM_TCP_SEG: 16 ---*/

♯ define MEMP_NUM_TCP_SEG 8

/*----- Default Value for PBUF_POOL_BUFSIZE: 592 ---*/

♯ define PBUF_POOL_BUFSIZE 1524

/*----- Value in opt.h for LWIP_ETHERNET: LWIP_ARP || PPPOE_SUPPORT -*/

♯ define LWIP_ETHERNET 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

//*----- Default Value for MEMP_OVERFLOW_CHECK: 0 ---*/

♯ define MEMP_OVERFLOW_CHECK 1

/*----- Default Value for MEMP_SANITY_CHECK: 0 ---*/

♯ define MEMP_SANITY_CHECK 0

/*----- Default Value for TCP_WND: 5840 ---*/

♯ define TCP_WND 5840

/*----- Default Value for TCP_QUEUE_OOSEQ: 1 ---*/

♯ define TCP_QUEUE_OOSEQ 0

/*----- Default Value for TCP_MSS: 536 ---*/

♯ define TCP_MSS 1460

/*----- Default Value for TCP_SND_BUF: 2920 ---*/

♯ define TCP_SND_BUF (4*TCP_MSS)

/*----- Default Value for TCP_SND_QUEUELEN: 17 ---*/

♯ define TCP_SND_QUEUELEN (2* TCP_SND_BUF/TCP_MSS)

/*----- Default Value for MEMP_NUM_RAW_PCB: 4 ---*/

♯ define MEMP_NUM_RAW_PCB 16

/*----- Default Value for MEMP_NUM_FRAG_PBUF: 15 ---*/

♯ define MEMP_NUM_FRAG_PBUF 16

/*----- Default Value for MEMP_NUM_SYS_TIMEOUT: 3 ---*/

♯ define MEMP_NUM_SYS_TIMEOUT 16

/*----- Default Value for MEMP_NUM_NETBUF: 2 ---*/

♯ define MEMP_NUM_NETBUF 16

/*----- Default Value for MEMP_NUM_NETCONN: 4 ---*/

♯ define MEMP_NUM_NETCONN 16

/*----- Default Value for MEMP_NUM_TCPIP_MSG_INPKT: 8 ---*/

♯ define MEMP_NUM_TCPIP_MSG_INPKT 32

/*----- Default Value for MEMP_NUM_API_MSG: 8 ---*/

♯ define MEMP_NUM_API_MSG 16

/*----- Default Value for MEMP_NUM_DNS_API_MSG: 8 ---*/

♯ define MEMP_NUM_DNS_API_MSG 16

/*----- Default Value for MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA: 8 ---*/

♯ define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA 16

/*----- Default Value for MEMP_NUM_NETIFAPI_MSG: 8 ---*/

♯ define MEMP_NUM_NETIFAPI_MSG 16

/*----- Default Value for PBUF_POOL_SIZE: 16 ---*/

♯ define PBUF_POOL_SIZE 8

/*----- Value in opt.h for TCP_SND_QUEUELEN: (4*TCP_SND_BUF + (TCP_MSS - 1))/TCP_MSS -----*/

// ♯ define TCP_SND_QUEUELEN TCP_SND_QUEUELEN: (4*TCP_SND_BUF + (TCP_MSS - 1))/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 5

/*----- Default Value for LWIP_NETIF_API: 0 ---*/

♯ define LWIP_NETIF_API 1

/*----- Value in opt.h for TCPIP_THREAD_STACKSIZE: 0 -----*/

♯ define TCPIP_THREAD_STACKSIZE 1024

/*----- Value in opt.h for TCPIP_THREAD_PRIO: 1 -----*/

♯ define TCPIP_THREAD_PRIO 3

/*----- Value in opt.h for TCPIP_MBOX_SIZE: 0 -----*/

♯ define TCPIP_MBOX_SIZE 6

/*----- Value in opt.h for SLIPIF_THREAD_STACKSIZE: 0 -----*/

♯ define SLIPIF_THREAD_STACKSIZE 1024

/*----- Value in opt.h for SLIPIF_THREAD_PRIO: 1 -----*/

♯ define SLIPIF_THREAD_PRIO 3

/*----- Value in opt.h for DEFAULT_THREAD_STACKSIZE: 0 -----*/

♯ define DEFAULT_THREAD_STACKSIZE 1024

/*----- Value in opt.h for DEFAULT_THREAD_PRIO: 1 -----*/

♯ define DEFAULT_THREAD_PRIO 3

/*----- Value in opt.h for DEFAULT_UDP_RECVMBOX_SIZE: 0 -----*/

♯ define DEFAULT_UDP_RECVMBOX_SIZE 6

/*----- Value in opt.h for DEFAULT_TCP_RECVMBOX_SIZE: 0 -----*/

♯ define DEFAULT_TCP_RECVMBOX_SIZE 6

/*----- Value in opt.h for DEFAULT_ACCEPTMBOX_SIZE: 0 -----*/

♯ define DEFAULT_ACCEPTMBOX_SIZE 6

/*----- 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_STATS_DISPLAY: 0 ---*/

♯ define LWIP_STATS_DISPLAY 0

/*----- Value in opt.h for LINK_STATS: 0 or 1 -*/

♯ define LINK_STATS 0

/*----- Value in opt.h for ETHARP_STATS: 0 or LWIP_ARP -----*/

♯ define ETHARP_STATS 0

/*----- Value in opt.h for ICMP_STATS: 0 or LWIP_ICMP -----*/

♯ define ICMP_STATS 0

/*----- Value in opt.h for MIB2_STATS: 0 or SNMP_LWIP_MIB2 -----*/

♯ define MIB2_STATS 0

/*----- 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_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

/*-----------------------------------------------------------------------------*/

/* USER CODE BEGIN 1 */

♯ define ETHARP_SUPPORT_STATIC_ENTRIES   1

♯ define LWIP_DEBUG    0

// ♯ define TCP_DEBUG LWIP_DBG_ON

/*----- Default Value for TCP_QUEUE_OOSEQ: 1 ---*/

♯ define TCP_QUEUE_OOSEQ 0

/* USER CODE END 1 */

Posted on December 12, 2017 at 18:56

Hi Joerg,

As you advised,

updated the TCP_MSS buffer to max value 1460,

changed the MEM_SIZE, TCP_SND_BUFF,  TCP_SND_QUEUELEN and the rest of their friends.

It sends all 1024 bytes now but still the writes from the TCP Server task happening to fast (the stack did not finish with the previous writings) and writing is blocked at some point.

Found a solution though:

I used another lwip api to create the TCP connection, it has a callback func:

conn = netconn_new_with_callback(NETCONN_TCP, callbackConnection);

callback func will look like this (work in progress):

void

callbackConnection

(

struct

netconn

* conn,

enum

netconn_evt ev,

u16_t

len)

{

      

switch

(ev)

       {

      

case

NETCONN_EVT_RCVPLUS

:

            

break

;

      

case

NETCONN_EVT_RCVMINUS

:

            

break

;

      

case

NETCONN_EVT_SENDPLUS

:

       xTaskNotify(handle,0,

eNoAction

);

            

break

;

      

case

NETCONN_EVT_SENDMINUS

:

            

break

;

      

case

NETCONN_EVT_ERROR

:

            

break

;

       

default

:

            

break

;

       }

}

When the infrastructure is done and we have enough space to write more 1024 bytes, we are notifying the TCP Server task to resume writing.

Like that:

static

void

tcp_thread(

void

*arg)

{

      

/* Create a new connection identifier. */

        

/* Bind connection to well known port number 7. */

      conn = netconn_new_with_callback(

NETCONN_TCP

, callbackConnection);

      err =

netconn_bind

(conn, IP_ADDR_ANY,80);

      LWIP_ERROR(

'

tcpecho

: invalid

conn

'

, (conn != NULL),

return

;);

        

/* Tell connection to go into listening mode. */

      netconn_listen(conn);

        

while

(1) {

            

/* Grab new connection. */

             err = netconn_accept(conn, &newconn);

            

/*

printf

('accepted new connection %p\n',

newconn

);*/

            

/* Process the new connection. */

            

if

(err ==

ERR_OK

) {

          

for

(

int

i= 0; i< 256; i++)

      {

             buffFloat[i] = 1.0*i;

      }

         

uint32_t

val;

          

while

(1)

      {

                  

                     err = netconn_write(newconn, buffFloat, 1024, NETCONN_NOCOPY);

                     xTaskNotifyWait(0x00, ULONG_MAX, &val ,portMAX_DELAY);

                   

                     err = netconn_write(newconn, buffFloat, 1024 , NETCONN_NOCOPY);

                     xTaskNotifyWait(0x00, ULONG_MAX, &val ,portMAX_DELAY);

                   

                     err = netconn_write(newconn, buffFloat, 1024 , NETCONN_NOCOPY);

                     xTaskNotifyWait(0x00, ULONG_MAX, &val ,portMAX_DELAY);

                  

        }

     

/* Close connection and discard connection identifier. */

      netconn_close(newconn);

      netconn_delete(newconn);

}

}

Thanks for the help with the debug flags and statistics, I did not notice them before!

Best regards,

Marina