FreeRTOS TCP/IP with STM32F746 Discovery board ( LAN 8742A ). ARP transmit issue

I am trying to get FreeRTOS TCP/IP running an a STM32F746 Discovery board and am running into problems.

The receive path seems to work OK but the transmit path does not. I am going drectly from my PC to the device ( host 192.168.1.33 → 192.168.1.125 ). I have also tried going through a switch ( host 192.168.1.33 → 192.168.1.10 → 192.168.1.125 )

One of the first things that happens upon power on of the board is an ARP event, wherin my device attempts to send a broadcast ARP out. The ARP packet appears to be properly formed and the transmit TxDMA descriptors look correct in the xNetworkInterfaceOutput() function. HOWEVER, nothing physically appears the the output of EITHER the MAC or PHY output pins ( verified on OSCOPE and Wireshark ).

Next, If I send a packet from the host to the device, I see that the device correctly receives a request from the host to generate an ARP packet. The ARP packet is properly formed and has the correct host MAC Addr and IP addr, as well as my device MAC Addr and IP address, and other relevant ARP info - at xNetworkInterfaceOutput(). HOWEVER, nothing physically appears at the output of EITHER the MAC or PHY output pins.

Obviously I see no traffic being generated from my device using Wireshark.

I’m looking for ideas on what I am doing wrong.

I have shown below the ARP packets and the status of the DMA and MAC registers during the sending of the packet. I don’t really see anything abnormal.

Network info:

Host IP addr; 192.168.1.33
My device IP addr: 192.168.1.125

Host MAC addr: 90 E2 BA 84 DE 71
My device MAC address: 01 02 03 04 05 06

Here is some startup debug info showing the PHY register settings:

(null-format-string-pointer)prvIPTask started
PHY ID 7C130
xPhyReset: phyBMCR_RESET 0 ready
+TCP: advertise: 01E1 config 1000
prvEthernetUpdateConfig: LS mask 00 Force 1

Autonego ready: 00000004: full duplex 100 mbit high status
reg 0 1100
reg 1 782D
reg 2 0007
reg 3 C131
reg 4 01E1
reg 5 C1E1
reg 6 006F
reg 7 2001
reg 8 4000
reg 9 FFFF
reg 10 FFFF
reg 11 FFFF
reg 12 FFFF
reg 13 0000
reg 14 0000
reg 15 0000
reg 16 0041
reg 17 0002
reg 18 60E0
reg 19 FFFF
reg 20 0000
reg 21 0000
reg 22 0000
reg 23 0000
reg 24 9B9D
reg 25 0000
reg 26 0000
reg 27 000A
reg 28 4000
reg 29 00C8
reg 30 0000
reg 31 1058
Network buffers: 91 lowest 91
Link Status is high
Socket Created
IP Address: 192.168.1.125
Subnet Mask: 255.255.255.0
Network buffers: 90 lowest 90
DNS server IP Address: 208.67.222.222
Binding socket to port 10000
Socket 10000 → 0ip:0 State eCLOSED->eTCP_LISTEN
Network buffers: 89 lowest 89

Device generates an ARPTimerEvent to update its ARPCache:

ARPAgeCache() ->FreeRTOS_OutputARPRequest() → xNetworkInterfaceOutput()

Just prior to /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */

pxDMATxDesc 0x20000080: Status 0x70D00000 ( own bit not yet set ). ControlBufferSize 0x00000002A. Buffer1Addr = 0X20002272
Contents of buffer1Addr: FF FF FF FF FF FF 01 02 03 04 05 06 08 06 00 01 08 00 06 04 00 01 01 02 03 04 05 06 C0 A8 01 7D 00 00 00 00 00 00 C0 A8 01 7D FF
This is xETH_HEADER + xARP_HEADER ( see FreeRTOS_IP_Private.h ). Note this shows a broadcast MAC addr FF FF FF FF FF FF as destination, 01 02 03 04 05 06 as source MAC addr, “Frame TYpe”

	as 0x0806, Hardware Type as 0x0001, ProtocolType = 0x0800 HardwareaddressLength = 0x06, ProtocolAddressLength = 0x04, Operation = 0x0001, xSenderHardwareAddress = 01 02 03 04 05 06
	SenderProtocolAddress = C0 A8 01 7D (This is addr 192.168.1.125 ) TargetHardware Address = 00 00 00 00 00 00 TargetProtocolAddress = C0 A8 01 7D (This is addr 192.168.1.125 )

SET the OWN bit in Status of pxDMATxDesc:
pxDMATxDesc 0x20000080: Status 0xf0d00000
At this point here are various relevant DMA and MAC register values. The only thing that loos possibly strange are that the values of TBUS and TPS in the DMASR ( DMA status register ). These values are

always 1 and 6 respectively, even after the transmit is “finished” ( TBUS = 1 = Transmit Buffer unavailable, and TPS = 6 = Transmit process suspended ). But I believe these are referring to the NEXT

descriptor, not the current Descriptor.:

DMABMR                       0x02c12080    
    SR                       0             
    DA                       0             
    DSL                      0x00          
    EDFE                     1             
    PBL                      0x20          
    RTPR                     0x0           
    FB                       1             
    RDP                      0x20          
    USP                      1             
    FPM                      0             
    AAB                      1             
    MB                       0             
DMATPDR                      0x00000000    
    TPD                      0x00000000    
DMARPDR                      0x00000000    
    RPD                      0x00000000    
DMARDLAR                     0x20000000    
    SRL                      0x20000000    
DMATDLAR                     0x20000080    
    STL                      0x20000080    
DMASR                        0x00680004    
    TS                       0             
    TPSS                     0             
    TBUS                     1             
    TJTS                     0             
    ROS                      0             
    TUS                      0             
    RS                       0             
    RBUS                     0             
    RPSS                     0             
    PWTS                     0             
    ETS                      0             
    FBES                     0             
    ERS                      0             
    AIS                      0             
    NIS                      0             
    RPS                      0x4           
    TPS                      0x6           
    EBS                      0x0           
    MMCS                     0             
    PMTS                     0             
    TSTS                     0             
DMAOMR                       0x02202006    
    SR                       1             
    OSF                      1             
    RTC                      0x0           
    FUGF                     0             
    FEF                      0             
    ST                       1             
    TTC                      0x0           
    FTF                      0             
    TSF                      1             
    DFRF                     0             
    RSF                      1             
    DTCEFD                   0             
DMAIER                       0x000163fb    
    TIE                      1             
    TPSIE                    1             
    TBUIE                    0             
    TJTIE                    1             
    ROIE                     1             
    TUIE                     1             
    RIE                      1             
    RBUIE                    1             
    RPSIE                    1             
    RWTIE                    1             
    ETIE                     0             
    FBEIE                    1             
    ERIE                     1             
    AISE                     0             
    NISE                     1             
DMAMFBOCR                    0x000008ca    
    MFC                      0x08ca        
    OMFC                     0             
    MFA                      0x000         
    OFOC                     0             
DMARSWTR                     0x00000000    
    RSWTC                    0x00          
DMACHTDR                     0x20000080    
    HTDAP                    0x20000080    
DMACHRDR                     0x20000000    
    HRDAP                    0x20000000    
DMACHTBAR                    0x00000000    
    HTBAP                    0x00000000    
DMACHRBAR                    0x20003fea    
    HRBAP                    0x20003fea    

Ethernet_MAC
MACCR 0x0000ce0c
RE 1
TE 1
DC 0
BL 0x0
APCS 0
RD 1
IPCO 1
DM 1
LM 0
ROD 0
FES 1
CSD 0
IFG 0x0
JD 0
WD 0
CSTF 0
MACFFR 0x00000040
PM 0
HU 0
HM 0
DAIF 0
RAM 0
BFD 0
PCF 1
SAIF 0
SAF 0
HPF 0
RA 0
MACHTHR 0x00000000
HTH 0x00000000
MACHTLR 0x00000000
HTL 0x00000000
MACMIIAR 0x000007d0
MB 0
MW 0
CR 0x4
MR 0x1f
PA 0x00
MACMIIDR 0x00001058
TD 0x1058
MACFCR 0x00000080
FCB 0
TFCE 0
RFCE 0
UPFD 0
PLT 0x0
ZQPD 1
PT 0x0000
MACVLANTR 0x00000000
VLANTI 0x0000
VLANTC 0
MACPMTCSR 0x00000000
PD 0
MPE 0
WFE 0
MPR 0
WFR 0
GU 0
WFFRPR 0
MACDBGR 0x00000000
CR 0
CSR 0
ROR 0
MCF 0
MCP 0
MCFHP 0
MACSR 0x00000000
PMTS 0
MMCS 0
MMCRS 0
MMCTS 0
TSTS 0
MACIMR 0x00000000
PMTIM 0
TSTIM 0
MACA0HR 0x80000605
MACA0H 0x0605
MO 1
MACA0LR 0x04030201
MACA0L 0x04030201
MACA1HR 0x0000ffff
MACA1H 0xffff
MBC 0x00
SA 0
AE 0
MACA1LR 0xffffffff
MACA1LR 0xffffffff
MACA2HR 0x0000ffff
MAC2AH 0xffff
MBC 0x00
SA 0
AE 0
MACA2LR 0xffffffff
MACA2L 0x7fffffff
MACA3HR 0x0000ffff
MACA3H 0xffff
MBC 0x00
SA 0
AE 0
MACA3LR 0xffffffff
MBCA3L 0xffffffff
MACRWUFFER 0x00000000

Then After resume DMA transmission (after iptraceNETWORK_INTERFACE_TRANSMIT() and setting xReturn to pdPASS: )

Ethernet_DMA
DMABMR 0x02c12080
SR 0
DA 0
DSL 0x00
EDFE 1
PBL 0x20
RTPR 0x0
FB 1
RDP 0x20
USP 1
FPM 0
AAB 1
MB 0
DMATPDR 0x00000000
TPD 0x00000000
DMARPDR 0x00000000
RPD 0x00000000
DMARDLAR 0x20000000
SRL 0x20000000
DMATDLAR 0x20000080
STL 0x20000080
DMASR 0x00690405
TS 1
TPSS 0
TBUS 1
TJTS 0
ROS 0
TUS 0
RS 0
RBUS 0
RPSS 0
PWTS 0
ETS 1
FBES 0
ERS 0
AIS 0
NIS 1
RPS 0x4
TPS 0x6
EBS 0x0
MMCS 0
PMTS 0
TSTS 0
DMAOMR 0x02202006
SR 1
OSF 1
RTC 0x0
FUGF 0
FEF 0
ST 1
TTC 0x0
FTF 0
TSF 1
DFRF 0
RSF 1
DTCEFD 0
DMAIER 0x000163fb
TIE 1
TPSIE 1
TBUIE 0
TJTIE 1
ROIE 1
TUIE 1
RIE 1
RBUIE 1
RPSIE 1
RWTIE 1
ETIE 0
FBEIE 1
ERIE 1
AISE 0
NISE 1
DMAMFBOCR 0x00000034
MFC 0x0034
OMFC 0
MFA 0x000
OFOC 0
DMARSWTR 0x00000000
RSWTC 0x00
DMACHTDR 0x200000a0
HTDAP 0x200000a0
DMACHRDR 0x20000000
HRDAP 0x20000000
DMACHTBAR 0x00000000
HTBAP 0x00000000
DMACHRBAR 0x200059ca
HRBAP 0x200059ca
Ethernet_MAC
MACCR 0x0000ce0c
RE 1
TE 1
DC 0
BL 0x0
APCS 0
RD 1
IPCO 1
DM 1
LM 0
ROD 0
FES 1
CSD 0
IFG 0x0
JD 0
WD 0
CSTF 0
MACFFR 0x00000040
PM 0
HU 0
HM 0
DAIF 0
RAM 0
BFD 0
PCF 1
SAIF 0
SAF 0
HPF 0
RA 0
MACHTHR 0x00000000
HTH 0x00000000
MACHTLR 0x00000000
HTL 0x00000000
MACMIIAR 0x000007d0
MB 0
MW 0
CR 0x4
MR 0x1f
PA 0x00
MACMIIDR 0x00001058
TD 0x1058
MACFCR 0x00000080
FCB 0
TFCE 0
RFCE 0
UPFD 0
PLT 0x0
ZQPD 1
PT 0x0000
MACVLANTR 0x00000000
VLANTI 0x0000
VLANTC 0
MACPMTCSR 0x00000000
PD 0
MPE 0
WFE 0
MPR 0
WFR 0
GU 0
WFFRPR 0
MACDBGR 0x00000000
CR 0
CSR 0
ROR 0
MCF 0
MCP 0
MCFHP 0
MACSR 0x00000000
PMTS 0
MMCS 0
MMCRS 0
MMCTS 0
TSTS 0
MACIMR 0x00000000
PMTIM 0
TSTIM 0
MACA0HR 0x80000605
MACA0H 0x0605
MO 1
MACA0LR 0x04030201
MACA0L 0x04030201
MACA1HR 0x0000ffff
MACA1H 0xffff
MBC 0x00
SA 0
AE 0
MACA1LR 0xffffffff
MACA1LR 0xffffffff
MACA2HR 0x0000ffff
MAC2AH 0xffff
MBC 0x00
SA 0
AE 0
MACA2LR 0xffffffff
MACA2L 0x7fffffff
MACA3HR 0x0000ffff
MACA3H 0xffff
MBC 0x00
SA 0
AE 0
MACA3LR 0xffffffff
MBCA3L 0xffffffff
MACRWUFFER 0x00000000

Is there a loopback mode or Ethernet example provided by ST you could use to check its not a physical issue with the board?

As far as I can tell from the spec, there is a loopback mode for the MAC but it only works for MII, I’m using RMII. The ST examples all use LWIP, I’m using FreeRTOS-TCP/IP.

Did you verify with a ST provided demo network application that the board and the network drivers are basically working ? Which FreeRTOS+TCP version(s) do you use ?
As far as I can tell the FreeRTOS TCP stack is working well (on a STM32F407 board in my case). The MAC+PHY drivers are a different story… :wink:
Do you use the STM32Fxx drivers from here ?

Have you checked your implementation of the function HAL_ETH_MspInit()? Have you compared all pin settings with the hardware scheme?
Could it be that some pins have a double function, and that you must change jumpers on the board to get the proper connections?
I recently had to solder an STM32H board to get Ethernet working.
The STM32Fxx driver uses phyHandling.c. Have you checked if the PHY initialisation went well? It should take at most 3 seconds before the negotiation is ready.

Hello Hein,

I am using version 2.3.0 of FreeRTOS-TCP.
The pin assignments have been verified correct ( they were generated via CubeMX, and use AF11 to get the ethernet out ) and there are no jumpers that are associated with ethernet…also using RMII interface. The autonegotiation works well and comes up just fine…link status comes up. I included the reg dump of the PHY above and all of the registers look correct.

The stack itself seems to be running OK…it appears that there is something at the lowest level which is not functioning properly.

If anyone has a pre-compiled exe for this board which has a running ethernet functionality I would be grateful to try it out. I don’t think there is a board issue, but you never know.

I tried putting the phy in Loopback mode. Autonegotiation changed from full duplex/100 Mbs with no loopback to half duplex/10Mbs when loopback was turned on. This makes sense and tells me that at least the transmit does work at the PHY level. The problem seems to be at the DMA /MAC output level…Unfortunately MAC loopback only applicable for MII.

Another thing I can think of is memory barriers: sometimes a write to a peripheral register doesn’t come through. In those cases it often helps to read back a register from the same peripheral. You can also have a look at some special macros for memory barriers.

You might want to do an extra read-back after setting DMATPDR :

     /* Resume DMA transmission*/
     xETH.Instance->DMATPDR = 0;
+    if( xETH.Instance->DMATPDR ) {}

How about memory caching? I think that the STM32f746 caches memory. Have you tried to disable RAM caching and undefine NETWORK_BUFFERS_CACHED in NetworkInterface.c?

Thanks for the suggestions Hein. I went ahead and gave the a try.

  1. disabling CPU data cache - this caused a cpu hard fault. Not sure why

  2. tried the extra read-back after setting DMATPDR . No change.

  3. It looks like the memory barrier command DSB() is already present in the code in networkinterface.c, just prior to setting DMATPDR. Should I be inserting an additional command somewhere ?

  4. I notice that the default code generated by CubeMX for lwip does the setting of DMATPDR slightly differently in their xNetworkInterfaceOutput(), so I tried doing it that way instead of the way that is written in the 2.3.0 FreeRTS-TCP version of that function. They do it like:

                              /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */
                            if ((xETH.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET)
                              {
                            /* Clear TUS ETHERNET DMA flag */
                                xETH.Instance->DMASR = ETH_DMASR_TUS;
    
                                /* Resume DMA transmission*/
                                  xETH.Instance->DMATPDR = 0;
                              }
    

This had no effect either.

  1. NETWORK_BUFFERS_CACHED in NetworkInterface.c is already not defined in my code. Is there some other code switch that needs to be disabled as well ?

  2. FYI I am using the lower 32K of SRAM ( non-cached ) to hold the descriptors as outlined in the driver readme doc for the STM32F74X.

Also tried cutting the CPU clock ( SYSCLK ) in half from 216 Mhz to 108 Mhz, no effect either.

FreeRTOSIPConfig.h settings are below. Does anything here look obviously wrong ?

#define ipconfigBYTE_ORDER  pdFREERTOS_LITTLE_ENDIAN // mbdtest
#ifndef ipconfigUSE_TCP
	#define	ipconfigUSE_TCP						( 1 )
#endif

#if	ipconfigUSE_TCP

	/* Include support for TCP scaling windows */
	#ifndef ipconfigUSE_TCP_WIN
		#define ipconfigUSE_TCP_WIN				( 1 )
	#endif

	#ifndef ipconfigTCP_WIN_SEG_COUNT
		#define	ipconfigTCP_WIN_SEG_COUNT		( 256 )
	#endif

	#ifndef ipconfigIGNORE_UNKNOWN_PACKETS
		/* When non-zero, TCP will not send RST packets in reply to
		TCP packets which are unknown, or out-of-order. */
		#define ipconfigIGNORE_UNKNOWN_PACKETS	( 0 )
	#endif
#endif

#ifndef ipconfigTCP_MAY_LOG_PORT
	#define ipconfigTCP_MAY_LOG_PORT(xPort)			( ( xPort ) != 23U )
#endif


#ifndef	ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME
	#define	ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME	portMAX_DELAY
#endif

#ifndef	ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME
	#define	ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME	portMAX_DELAY
#endif


#ifndef	ipconfigDNS_RECEIVE_BLOCK_TIME_TICKS
	#define	ipconfigDNS_RECEIVE_BLOCK_TIME_TICKS	pdMS_TO_TICKS( 5000U )
#endif

#ifndef	ipconfigDNS_SEND_BLOCK_TIME_TICKS
	#define	ipconfigDNS_SEND_BLOCK_TIME_TICKS		pdMS_TO_TICKS( 500U )
#endif

#ifndef ipconfigUSE_NETWORK_EVENT_HOOK
	#define ipconfigUSE_NETWORK_EVENT_HOOK 1
#endif

#ifndef ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS
	#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( pdMS_TO_TICKS( 20U ) )
#endif

#ifndef ipconfigARP_CACHE_ENTRIES
	#define ipconfigARP_CACHE_ENTRIES		10
#endif

#ifndef ipconfigMAX_ARP_RETRANSMISSIONS
	#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5U )
#endif

#ifndef ipconfigMAX_ARP_AGE
	#define ipconfigMAX_ARP_AGE			150U
#endif

#ifndef ipconfigUSE_ARP_REVERSED_LOOKUP
	#define ipconfigUSE_ARP_REVERSED_LOOKUP		0
#endif

#ifndef ipconfigUSE_ARP_REMOVE_ENTRY
	#define	ipconfigUSE_ARP_REMOVE_ENTRY		0
#endif

#ifndef ipconfigINCLUDE_FULL_INET_ADDR
	#define ipconfigINCLUDE_FULL_INET_ADDR	1
#endif

#ifndef ipconfigUSE_LINKED_RX_MESSAGES
	#define ipconfigUSE_LINKED_RX_MESSAGES			1
#endif

#ifndef ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS
	#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS		95U
#endif

#ifndef ipconfigEVENT_QUEUE_LENGTH
	//#define ipconfigEVENT_QUEUE_LENGTH		( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 )
        #define ipconfigEVENT_QUEUE_LENGTH          100// mbdtest 44
#endif

#ifndef ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND
	#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND	1
#endif

#ifndef ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS
	#define ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS	1
#endif

#ifndef ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS
	#define ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS	0
#endif

#ifndef ipconfigUDP_TIME_TO_LIVE
	#define ipconfigUDP_TIME_TO_LIVE		128
#endif

#ifndef ipconfigTCP_TIME_TO_LIVE
	#define ipconfigTCP_TIME_TO_LIVE		128
#endif

#ifndef ipconfigUDP_MAX_RX_PACKETS
	/* Make postive to define the maximum number of packets which will be buffered
	 * for each UDP socket.
	 * Can be overridden with the socket option FREERTOS_SO_UDP_MAX_RX_PACKETS
	 */
	#define ipconfigUDP_MAX_RX_PACKETS		0U
#endif

#ifndef ipconfigUSE_DHCP
	#define ipconfigUSE_DHCP				0
#endif

#ifndef ipconfigUSE_DHCP_HOOK
	#define ipconfigUSE_DHCP_HOOK		0
#endif

#ifndef ipconfigDHCP_FALL_BACK_AUTO_IP
	/*
	 * Only applicable when DHCP is in use:
	 * If no DHCP server responds, use "Auto-IP" : the
	 * device will allocate a random LinkLayer IP address.
	 */
	#define ipconfigDHCP_FALL_BACK_AUTO_IP		( 0 )
#endif

#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
	#define ipconfigARP_USE_CLASH_DETECTION		1
#endif

#ifndef ipconfigARP_USE_CLASH_DETECTION
	#define ipconfigARP_USE_CLASH_DETECTION		0
#endif

#ifndef ipconfigNETWORK_MTU
	#define ipconfigNETWORK_MTU		1500U
#endif

#define ipconfigIP_TASK_STACK_SIZE_WORDS  1000  // mbdtest param not in orig file but is needed.  Guess at 1000 words?  mbdtest        
#define ipconfigIP_TASK_PRIORITY          4     // // mbdtest param not in orig file but is needed. not sure of value so made same as most other tasks

#ifndef ipconfigTCP_MSS
	#define ipconfigTCP_MSS		( ipconfigNETWORK_MTU - ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER  ) )
#endif

/* Each TCP socket has circular stream buffers for Rx and Tx, which
 * have a fixed maximum size.
 * The defaults for these size are defined here, although
 * they can be overridden at runtime by using the setsockopt() call */
#ifndef ipconfigTCP_RX_BUFFER_LENGTH
	#define ipconfigTCP_RX_BUFFER_LENGTH			( 4U * ipconfigTCP_MSS )	/* defaults to 5840 bytes */
#endif

/* Define the size of Tx stream buffer for TCP sockets */
#ifndef ipconfigTCP_TX_BUFFER_LENGTH
#	define ipconfigTCP_TX_BUFFER_LENGTH			( 4U * ipconfigTCP_MSS )	/* defaults to 5840 bytes */
#endif

#ifndef ipconfigMAXIMUM_DISCOVER_TX_PERIOD
	#ifdef _WINDOWS_
		#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD		( pdMS_TO_TICKS( 999U ) )
	#else
		#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD		( pdMS_TO_TICKS( 30000U ) )
	#endif /* _WINDOWS_ */
#endif /* ipconfigMAXIMUM_DISCOVER_TX_PERIOD */

#if( ipconfigUSE_DNS == 0 )
	/* The DNS module will not be included. */
	#if( ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) )
		/* LLMNR and NBNS depend on DNS because those protocols share a lot of code. */
		#error When either LLMNR or NBNS is used, ipconfigUSE_DNS must be defined
	#endif
#endif

#ifndef ipconfigUSE_DNS
	#define ipconfigUSE_DNS						0
#endif

#ifndef ipconfigDNS_REQUEST_ATTEMPTS
	#define ipconfigDNS_REQUEST_ATTEMPTS		5
#endif

#ifndef ipconfigUSE_DNS_CACHE
	#define ipconfigUSE_DNS_CACHE				0
#endif

#if( ipconfigUSE_DNS_CACHE != 0 )
	#ifndef ipconfigDNS_CACHE_NAME_LENGTH
		/* Per https://tools.ietf.org/html/rfc1035, 253 is the maximum string length
		of a DNS name. The following default accounts for a null terminator. */
		#define ipconfigDNS_CACHE_NAME_LENGTH   254U
	#endif

	#ifndef ipconfigDNS_CACHE_ENTRIES
		#define ipconfigDNS_CACHE_ENTRIES			1
	#endif

#endif /* ipconfigUSE_DNS_CACHE != 0 */

/* When accessing services which have multiple IP addresses, setting this
greater than 1 can improve reliability by returning different IP address
answers on successive calls to FreeRTOS_gethostbyname(). */
#ifndef ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY 
	#define ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY 1
#endif

#ifndef ipconfigCHECK_IP_QUEUE_SPACE
	#define ipconfigCHECK_IP_QUEUE_SPACE			0
#endif

#ifndef ipconfigUSE_LLMNR
	/* Include support for LLMNR: Link-local Multicast Name Resolution (non-Microsoft) */
	#define ipconfigUSE_LLMNR					( 0 )
#endif

#ifndef ipconfigREPLY_TO_INCOMING_PINGS
	#define ipconfigREPLY_TO_INCOMING_PINGS		1
#endif

#ifndef ipconfigSUPPORT_OUTGOING_PINGS
	#define ipconfigSUPPORT_OUTGOING_PINGS	0
#endif

#ifndef ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES
	#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1
#endif

#ifndef ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES
	#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES	1
#endif

#ifndef configINCLUDE_TRACE_RELATED_CLI_COMMANDS
	#define ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS 0
#else
	#define ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS configINCLUDE_TRACE_RELATED_CLI_COMMANDS
#endif

#ifndef ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM
	#define	ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM	 1
#endif

#ifndef ipconfigETHERNET_DRIVER_FILTERS_PACKETS
	#define	ipconfigETHERNET_DRIVER_FILTERS_PACKETS	( 0 )
#endif

#ifndef ipconfigWATCHDOG_TIMER
	/* This macro will be called in every loop the IP-task makes.  It may be
	replaced by user-code that triggers a watchdog */
	#define ipconfigWATCHDOG_TIMER()
#endif

#ifndef ipconfigUSE_CALLBACKS
	#define ipconfigUSE_CALLBACKS			( 0 )
#endif

#if( ipconfigUSE_CALLBACKS != 0 )
	#ifndef ipconfigIS_VALID_PROG_ADDRESS
		/* Replace this macro with a test returning non-zero if the memory pointer to by x
		 * is valid memory which can contain executable code
		 * In fact this is an extra safety measure: if a handler points to invalid memory,
		 * it will not be called
		 */
		#define ipconfigIS_VALID_PROG_ADDRESS(x)		( ( x ) != NULL )
	#endif
#endif

#ifndef ipconfigHAS_INLINE_FUNCTIONS
	#define	ipconfigHAS_INLINE_FUNCTIONS	( 1 )
#endif

#ifndef portINLINE
	#define portINLINE inline
#endif

#ifndef ipconfigZERO_COPY_TX_DRIVER
	/* When non-zero, the buffers passed to the SEND routine may be passed
	to DMA. As soon as sending is ready, the buffers must be released by
	calling vReleaseNetworkBufferAndDescriptor(), */
	#define ipconfigZERO_COPY_TX_DRIVER		( 1 )
#endif

#ifndef ipconfigZERO_COPY_RX_DRIVER
	/* This define doesn't mean much to the driver, except that it makes
	sure that pxPacketBuffer_to_NetworkBuffer() will be included. */
	#define ipconfigZERO_COPY_RX_DRIVER		( 1 )
#endif

#ifndef ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM
	#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 1
#endif

#ifndef ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM
	#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1
#endif

#ifndef ipconfigDHCP_REGISTER_HOSTNAME
	#define ipconfigDHCP_REGISTER_HOSTNAME 0
#endif

#ifndef ipconfigSOCKET_HAS_USER_SEMAPHORE
	#define ipconfigSOCKET_HAS_USER_SEMAPHORE 0
#endif

#ifndef ipconfigSOCKET_HAS_USER_WAKE_CALLBACK
	#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK 0
#endif

#ifndef ipconfigSUPPORT_SELECT_FUNCTION
	#define ipconfigSUPPORT_SELECT_FUNCTION 0
#endif

#ifndef ipconfigTCP_KEEP_ALIVE
	#define ipconfigTCP_KEEP_ALIVE 0
#endif

#ifndef ipconfigDNS_USE_CALLBACKS
	#define ipconfigDNS_USE_CALLBACKS 0
#endif

#ifndef ipconfigSUPPORT_SIGNALS
	#define ipconfigSUPPORT_SIGNALS				0
#endif

#ifndef ipconfigUSE_NBNS
	#define ipconfigUSE_NBNS 0
#endif

/* As an attack surface reduction for ports that listen for inbound 
connections, hang protection can help reduce the impact of SYN floods. */
#ifndef ipconfigTCP_HANG_PROTECTION
	#define ipconfigTCP_HANG_PROTECTION  1
#endif

/* Non-activity timeout is expressed in seconds. */
#ifndef ipconfigTCP_HANG_PROTECTION_TIME
	#define ipconfigTCP_HANG_PROTECTION_TIME 30U
#endif

#ifndef ipconfigTCP_IP_SANITY
	#define ipconfigTCP_IP_SANITY 0
#endif

#ifndef ipconfigARP_STORES_REMOTE_ADDRESSES
	#define ipconfigARP_STORES_REMOTE_ADDRESSES 0
#endif

#ifndef ipconfigBUFFER_PADDING
	/* Expert option: define a value for 'ipBUFFER_PADDING'.
	When 'ipconfigBUFFER_PADDING' equals 0,
	'ipBUFFER_PADDING' will get a default value of 8 + 2 bytes. */
	#define ipconfigBUFFER_PADDING			0U
#endif

#ifndef ipconfigPACKET_FILLER_SIZE
	#define ipconfigPACKET_FILLER_SIZE		2U
#endif

#ifndef ipconfigSELECT_USES_NOTIFY
	#define ipconfigSELECT_USES_NOTIFY		0
#endif

#endif /* FREERTOS_DEFAULT_IP_CONFIG_H */

And from stm32fxx_hal_eth.c:

#define ETH_MAX_PACKET_SIZE ((uint32_t)524U)
#define ETH_HEADER ((uint32_t)14U) /*!< 6 byte Dest addr, 6 byte Src addr, 2 byte length/type /
#define ETH_CRC ((uint32_t)4U) /
!< Ethernet CRC /
#define ETH_EXTRA ((uint32_t)2U) /
!< Extra bytes in some cases /
#define ETH_VLAN_TAG ((uint32_t)4U) /
!< optional 802.1q VLAN Tag /
#define ETH_MIN_ETH_PAYLOAD ((uint32_t)46U) /
!< Minimum Ethernet payload size /
//#define ETH_MAX_ETH_PAYLOAD ((uint32_t)1500U) /
!< Maximum Ethernet payload size /
#define ETH_MAX_ETH_PAYLOAD ((uint32_t)500U) /
!< Maximum Ethernet payload size /
#define ETH_JUMBO_FRAME_PAYLOAD ((uint32_t)9000U) /
!< Jumbo frame payload size */

#define ETH_RXBUFNB ((uint32_t)5U) /* 5 Rx buffers of size ETH_RX_BUF_SIZE */
#define ETH_TXBUFNB ((uint32_t)5U)

Just an idea: try #define ETH_MAX_PACKET_SIZE ((uint32_t)1524U) covering MTU size 1500. I’m not sure about the other partially redundant defines like ETH_MAX_ETH_PAYLOAD.
It depends on your ethernet driver resp. the low level DMA buffer size calculation/configuration.

I tend to create DMA buffers with a fixed length of 1536 bytes, which is 0x600, nicely aligned. But I am sure that 1524U will work equally well.

Beside the 1500 bytes of MTU, 14 bytes are needed for the Ethernet header, plus minimal 10 ‘invisible’ bytes that come before the pointer pucEthernetBuffer.

pxNextBuffer[-10] A pointer back to the containing pucEthernetBuffer
pxNextBuffer[ -6] Alignment word
pxNextBuffer[ -2] 2 “filler” bytes, which can be used freely

Totalling 10 + 14 + 1500 = 1,524 bytes.

On a 64-bit platform, where pointers are 64-bits, it becomes like this:

14 hidden bytes containing a 64-bit pointer + alignment word + 2 filler bytes
14 bytes Ethernet header
1500 bytes MTU

Totalling 1528 bytes.

Some network interfaces want to use the hidden space as well, to store flags or some pointer. The macro ipconfigBUFFER_PADDING can be used to get more space. It can be set to 10 plus a multiple of 4.

When using IPv6 on a 64-bit platform, the layout will be as follows:

pxNextBuffer[-14] A pointer back to the containing pucEthernetBuffer
pxNextBuffer[ -6] Either ipTYPE_IPv4 (0x40) or ipTYPE_IPv6 (0x60)
pxNextBuffer[ -2] 2 “filler” bytes, which can be used freely

It is all a bit complicated, but it was necessary to create mechanisms for zero-copy operations. When you only have a payload, you can find the Ethernet buffer, and vice versa. See FreeRTOS_sendto() and FreeRTOS_recvfrom().

New is the ipTYPE byte, which indicates if the packet contains an IPv4- or an IPv6 frame.

Sorry for the long story here above, but you are right that ETH_MAX_PACKET_SIZE should be at least 1524 bytes.
I think that the other defines in stm32fxx_hal_eth are not used anywhere.

BTW I’m using 1536 byte as (final) DMA buffer size (on a STM32F4) due to the reasons you mentioned Hein :slight_smile:

Today I powered up my STM32F746G DISCO board just to test the driver again. It still works OK!

It is a GCC Makefile project, which you can find here. Maybe it helps to compare some settings.

I linked it with this FreeRTOS_plus_TCP, which is almost the same as the official repo.

I have NETWORK_BUFFERS_CACHED defined as zero, and D-cache is enabled.

The demo has UDP logging, which is configured with these defines:

/* The UDP port to which the UDP logging facility sends messages. */
#define configUDP_LOGGING_PORT_REMOTE		2403
/* The local UDP port to which commands can be sent. */
#define configUDP_LOGGING_PORT_LOCAL		2402

The target address is the local broadcast address, e.g. 192.168.0.255, unless you define your own target address:

#define configUDP_LOGGING_ADDR0    192
#define configUDP_LOGGING_ADDR1    168
#define configUDP_LOGGING_ADDR2    5
#define configUDP_LOGGING_ADDR3    1

I hope that you find the problem now, by comparing settings and so.

Hartmut wrote:

BTW I’m using 1536 byte as (final) DMA buffer size (on a STM32F4) due to the reasons you mentioned Hein

Very good. Maybe we should define this magic number in a central place, e.g. in FreeRTOS_IP.h