New FreeRTOS+TCP driver for STMF32F4

heinbali01 wrote on Monday, March 20, 2017:

Please find attached a new NetworkInterface.c for STM32F4. It has implemented the zero-copy feature in both directions, and therefore it is more efficient and faster than its earlier version.

I would like to invite anyone interested to try it out. Be aware that it may not be as stable yet as the existing driver. I tested it with UDP/TCP/ICMP/etc, and also with iperf.

The following settings are recommended for this driver:

    /* Add to your 'FreeRTOSIPConfig.h'. */
    #define ipconfigZERO_COPY_RX_DRIVER              1
    #define ipconfigZERO_COPY_TX_DRIVER              1
    #define ipconfigETHERNET_DRIVER_FILTERS_PACKETS	 1

    /* Add/change to your stm32f4xx_hal_conf.h : */

    #include "FreeRTOS.h"
    #include "task.h"
    #include "FreeRTOSIPConfig.h"

    #define ETH_RX_BUF_SIZE            ( ipconfigNETWORK_MTU + 36 )/* buffer size for receive */
    #define ETH_TX_BUF_SIZE            ( ipconfigNETWORK_MTU + 36 )/* buffer size for transmit */

By default, ETH_RX_BUF_SIZE / ETH_TX_BUF_SIZE are defined as ETH_MAX_PACKET_SIZE, which is hard-coded as 1536.

With a limited amount of RAM, it may be very profitable to reduce the value of ipconfigNETWORK_MTU to e.g. (1024+40).
So let tha value of ETH_RX_BUF_SIZE / ETH_TX_BUF_SIZE depend on ipconfigNETWORK_MTU.

The new driver will also filter incoming packets. That can be important in networks with many UDP broadcasts. These packets should be filtered-out as soon as possible in order not to occupy resources.

The following CUBE/HAL functions won’t be called any more:

HAL_ETH_DMATxDescListInit()
HAL_ETH_DMARxDescListInit()
HAL_ETH_TransmitFrame()
HAL_ETH_GetReceivedFrame()

For two reasons: they’re not compatible with zero-copy, and/or the in-line implementation is faster.

The interface will now work for two types of PHY’s: DP83848I ( found on STM324xG-EVAL ), and also LAN8720 ( found on STM32F4-DISCOVERY ).

heinbali01 wrote on Monday, March 20, 2017:

I pressed on Post too soon, hadn’t attached the driver yet. Here it is

heinbali01 wrote on Tuesday, March 21, 2017:

As xNetworkInterfaceInitialise() had become quite large and therefore less readable, I’ve split up some code into separate functions:

    /* Initialise TX-descriptors. */
    prvDMATxDescListInit();

    /* Initialise RX-descriptors. */
    prvDMARxDescListInit();

This time I also I included the latest iperf3 module. I tested on a STM3240G-EVAL, using the following defines for iperf:

    /* Some defines for iperf, optimised for speed. */
    /* Put these in your 'FreeRTOSIPConfig.h' */
    #define ipconfigIPERF_DOES_ECHO_UDP                0

    #define ipconfigIPERF_VERSION                   3
    #define ipconfigIPERF_STACK_SIZE_IPERF_TASK     680
    #define ipconfigIPERF_TX_BUFSIZE                ( 8 * ipconfigTCP_MSS )
    #define ipconfigIPERF_TX_WINSIZE                ( 6 )
    #define ipconfigIPERF_RX_BUFSIZE                ( 8 * ipconfigTCP_MSS )
    #define ipconfigIPERF_RX_WINSIZE                ( 6 )

    /* The iperf module declares a character buffer to store its send data. */
    #define ipconfigIPERF_RECV_BUFFER_SIZE          ( 2 * ipconfigTCP_MSS )

The above parameters are optimised for speed.

The iperf driver can be started by calling vIPerfInstall() once after the network is up ( vApplicationIPNetworkEventHook() is called with eNetworkUp ).

Here is an example optimised for memory usage:

    /* Defines for iperf, optimised for memory usage. */
    #define ipconfigIPERF_TX_BUFSIZE                ( 3 * ipconfigTCP_MSS )
    #define ipconfigIPERF_TX_WINSIZE                ( 2 )
    #define ipconfigIPERF_RX_BUFSIZE                ( 3 * ipconfigTCP_MSS )
    #define ipconfigIPERF_RX_WINSIZE                ( 2 )

Today I re-tested the memcpy() mode: it still functions. Using zero-copy is especially profitable when the device is sending data.