FreeRTOS TCP IP implementation on STM32F767ZI

Hello,

The last couple of days I’ve been busy with getting the plus TCP stack for FreeRTOS to work on my Nucleo-144 STM32F767ZI discovery board. The project has been set-up using STM32CubeMX, and altered to include the plus TCP stack.

I’ve followed the tutorial as described in: TCP_Networking_Tutorial.html (removing all standard STM32 HAL ETH drivers etc.) I am not getting any errors when I try to flash a client TCP application to the STM32. The PHY seems to be chosen correctly by the library (PHY_ID_LAN8742A).

I’ve also created a Python script to create an echo server, that is not based on a STM32:

import socket
import sys

# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Bind the socket to the port
server_address = ('192.168.0.2', 7)
print('starting up on {} port {}'.format(*server_address))
sock.bind(server_address)

# Listen for incoming connections
sock.listen(1)

while True:
    # Wait for a connection
    print('waiting for a connection')
    connection, client_address = sock.accept()
    try:
        print('connection from', client_address)
        # Receive the data in small chunks and retransmit it
        while True:
            data = connection.recv(16)
            print('received {!r}'.format(data))
            if data:
                print('sending data back to the client')
                connection.sendall(data)
            else:
                print('no data from', client_address)
                break
    finally:
        # Clean up the connection
        connection.close()

When I try to connect my STM32 client to my Python echo server, an ARP package is received and responded to (see my uploaded Wireshark PCAP). Although, I can’t seem to find any TCP packages.

I’ve updated the FreeRTOS kernel to this version: b0a8bd8f28d0138b5eb70e8b53da3e9d17ce8d40

After a bit of debugging, and adding extra FreeRTOS_debug_printf statements into the FreeRTOS code, I found out that the function prvTCPConnectStart(pxSocket, pxAddress) does return a correct result, but the function FreeRTOS_issocketconnected( pxSocket ); always returns 0 (this needs to be a 1). Because of this issocketconnected return val, I get an pdFREERTOS_ERRNO_ETIMEDOUT error from my FreeRTOS_connect() call.

I can’t seem to figure out why this call gets timed out.

Hopefully someone else might have a clue where I could look next.

Thanks in advance!
Kind regards,
Mats de Waard

P.S. attachments are as follows:

  1. Wireshark proof that ARP works
  2. Source code and header files (that I made, so not the TCP IP stack/FreeRTOS lib)

Attachments can be downloaded from (I am new FreeRTOS forum user, so I can’t upload directly, please remove all the ‘;’ semicolumns):
https://;;;;;;;drive.google;;;;;;;.com/f;;;;;;ile/d/1LWGy;;;;;bQNprNmkk905KnWJMNFFQNLRUHBf/view?u;;;;;;sp=sharing

Hello and Welcome to the forum!
We are trying to reproduce the issue at our end, can you please help us with the FreeRTOS+TCP stack version as well.

How are your client and server wired up to one another - peer to peer cable or a hub, or a switch, or…? Where does the packet sniffer come into play? Is it running on the same machine that runs the Python server?

Are you sure your subnet mask and gateway settings are correct?

Hello, thanks for the reply!

I am using ‘FreeRTOS+TCP V2.4.0’

Hello,

I have tried wiring them directly to each other (MCU → Laptop) and via a switch (MCU → Switch → Laptop). Both seem to give the same result.

Wireshark is active on the same machine as the Python server.

After some more testing, I have found out that the ‘ETH_IRQHandler()’ function from the ‘NetworkInterface.c’ file (STM32FXX/NetworkInterface.c/ETH_IRQHandler()), did not seem to be called.

This seems to be part of my problem, because if I call this function from stm32f7xx_it.c/TIM1_UP_TIM10_IRQHandler(), my Python server seems to find a connection with the MCU, sends a packet but Wireshark sees it as an TCP retransmissions. This makes me think that the MCU tries to send the TCP package too many times (I guess because the ETH_IRQHandler() get called too often?). I have uploaded a new Wireshark PCAP on Google Drive: Wireshark_defunct_TCP_package.pcapng - Google Drive

I can’t seem to find much about how often the ETH_IRQHandler() function needs to be called. My guess would be that it only needs to get called if a hardware pin gets interrupted, but I can’t seem to find how I enable/program this for the STM32F7 familiy.

If anyone has some more clues, information or ideas for me to try, that would be great!

Thanks for the help already.
With kind regards,

Mats de Waard

But earlier you wrote that the ARP exchange worked, so that does not seem to make sense.

Again, please post your IP settings (IP addresses and subnet mask configuration) of both nodes.

Yes, sorry. I thought the complete ARP exchange seemed to work, but I think my understanding of the ARP protocol was a bit off :wink:

Let me clarify.

The situation used to be (without calling ETH_IRQHandler()) : the ARP request got send, the laptop responds to the ARP request, but the MCU did not get a MAC address (so after the set timeout, another ARP request was send, which my laptop responds to, but the MCU does not, and again).

And when I do call ETH_IRQHandler() the situation is as follows:
ARP request gets send, laptop responds, MCU seems to retrieve the correct MAC address, and I start to see TCP retransmission errors in Wireshark.

My current IP settings are as follows:

Node 1 (Laptop, Python Echo server):
Static IP: 192.168.0.2
Subnet Mask: 255.255.255.0
Gateway: 192.168.0.1 (Which I don’t really need since the nodes are wired directly, but its here for completeness)
Port waiting for connection: 10001

Node 2 (STM32F767ZI, Echo client FreeRTOS task):
Static IP: 192.168.0.110
Subnet Mask: 255.255.255.0
Gateway: 192.168.0.1 (idem)
Client task IP definition: xEchoServerAddress.sin_addr = FreeRTOS_inet_addr_quick(192,168,0,2);
Client task port definition: xEchoServerAddress.sin_port = FreeRTOS_htons(10001);

P.S. I’ve used the FreeRTOS_htons function, since my MCU is little endian, and Network stack is always Big Endian, this assumption is correct right?

Thanks again!
Kind regards.

ok, conf looks good. I can not view the pcap right now, so can you check if the tcp packets look good in wireshark? In particular, is the tcp checksum ok? If not it may be the offload issue (query the forum for tcp offloading).

Sorry, I do not know exactly what you mean.

Do you mean the TCP package header checksum? Wireshark says that header checksum validation is disabled.

It says this when I configure the IPConfig setting ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to either 1 or 0. But I believe the STM32F7 does have hardware IP checksum checking, so this should be set to a 1 value right (for optimal performance)?

It feels like the MCU TCP IP stack won’t wait for the ACK message of my Windows Python Script. I have found a forum post that talks about the ipconfigTCP_SRTT_MINIMUM_VALUE_MS value being to low. Changing this value from 50ms to 10000ms still does not change anything.

The TCP package that Wireshark marks with TCP port number reused is as follows:

Transmission Control Protocol, Src Port: 2409, Dst Port: 10001, Seq: 0, Len: 0
    Source Port: 2409
    Destination Port: 10001
    [Stream index: 0]
    [Conversation completeness: Incomplete (38)]
    [TCP Segment Len: 0]
    Sequence Number: 0    (relative sequence number)
    Sequence Number (raw): 1385
    [Next Sequence Number: 1    (relative sequence number)]
    Acknowledgment Number: 0
    Acknowledgment number (raw): 0
    1000 .... = Header Length: 32 bytes (8)
    Flags: 0x002 (SYN)
    Window: 3480
    [Calculated window size: 3480]
    Checksum: 0xab08 [unverified]
    [Checksum Status: Unverified]
    Urgent Pointer: 0
    Options: (12 bytes), Maximum segment size, No-Operation (NOP), Window scale, No-Operation (NOP), No-Operation (NOP), SACK permitted
        TCP Option - Maximum segment size: 1160 bytes
        TCP Option - No-Operation (NOP)
        TCP Option - Window scale: 0 (multiply by 1)
        TCP Option - No-Operation (NOP)
        TCP Option - No-Operation (NOP)
        TCP Option - SACK permitted
    [Timestamps]
        [Time since first frame in this TCP stream: 19.585544000 seconds]
        [Time since previous frame in this TCP stream: 19.585544000 seconds]
    [SEQ/ACK analysis]
        [iRTT: 1.642729000 seconds]
        [TCP Analysis Flags]
            [Expert Info (Note/Sequence): A new tcp session is started with the same ports as an earlier session in this trace]
                [A new tcp session is started with the same ports as an earlier session in this trace]
                [Severity level: Note]
                [Group: Sequence]

and the TCP package that is marked as TCP retransmission is as follows:

Transmission Control Protocol, Src Port: 10001, Dst Port: 2409, Seq: 0, Ack: 1, Len: 0
    Source Port: 10001
    Destination Port: 2409
    [Stream index: 0]
    [Conversation completeness: Incomplete (38)]
    [TCP Segment Len: 0]
    Sequence Number: 0    (relative sequence number)
    Sequence Number (raw): 2227544677
    [Next Sequence Number: 1    (relative sequence number)]
    Acknowledgment Number: 1    (relative ack number)
    Acknowledgment number (raw): 1386
    1000 .... = Header Length: 32 bytes (8)
    Flags: 0x012 (SYN, ACK)
    Window: 65535
    [Calculated window size: 65535]
    Checksum: 0x9030 [unverified]
    [Checksum Status: Unverified]
    Urgent Pointer: 0
    Options: (12 bytes), Maximum segment size, No-Operation (NOP), Window scale, No-Operation (NOP), No-Operation (NOP), SACK permitted
        TCP Option - Maximum segment size: 1460 bytes
        TCP Option - No-Operation (NOP)
        TCP Option - Window scale: 8 (multiply by 256)
        TCP Option - No-Operation (NOP)
        TCP Option - No-Operation (NOP)
        TCP Option - SACK permitted
    [Timestamps]
        [Time since first frame in this TCP stream: 20.588016000 seconds]
        [Time since previous frame in this TCP stream: 1.002377000 seconds]
    [SEQ/ACK analysis]
        [iRTT: 1.642729000 seconds]
        [TCP Analysis Flags]
            [Expert Info (Note/Sequence): This frame is a (suspected) retransmission]
                [This frame is a (suspected) retransmission]
                [Severity level: Note]
                [Group: Sequence]
            [The RTO for this segment was: 1.002377000 seconds]
            [RTO based on delta from frame: 141]

That simply means that Wireshark itself does not bother to validate the packet checksum. You can enable that.

Theoretically yes, but there are problems with the offloaded check sum (again, query the forum for details).

The reason why I bark up this tree is that IF the FreeRTOS client does emit the SNY request successfully (as testified by the packet visible in Wireshark) AND the preceding ARP negotiation succeeds (which must happen for the TCP packet to be output in the first place), then there is a high probability that the SYN packet is being dropped by the server. Do I understand it correctly that the wireshark trace only records the recurring SYN packets TO the host but never a corresponding SYN ACK FROM the server? If yes, the SYN packet is probably malformed OR there is a firewall issue on the server that will not allow incoming SYN requests to your port.

Theoretically yes, but there are problems with the offloaded check sum (again, query the forum for details).

Okay, thanks! I’ll look into that, and just keep it disabled for now.

The reason why I bark up this tree is that IF the FreeRTOS client does emit the SNY request successfully (as testified by the packet visible in Wireshark) AND the preceding ARP negotiation succeeds (which must happen for the TCP packet to be output in the first place), then there is a high probability that the SYN packet is being dropped by the server. Do I understand it correctly that the wireshark trace only records the recurring SYN packets TO the host but never a corresponding SYN ACK FROM the server? If yes, the SYN packet is probably malformed OR there is a firewall issue on the server that will not allow incoming SYN requests to your port.

Hmm, the order in which Wireshark picks up the TCP messages is as follows:

1307	5920.140411	192.168.0.110	192.168.0.2	TCP	66	2409 → 10001 [SYN] Seq=0 Win=3480 Len=0 MSS=1160 WS=1 SACK_PERM

1308	5923.140336	192.168.0.110	192.168.0.2	TCP	66	[TCP Retransmission] [TCP Port numbers reused] 2409 → 10001 [SYN] Seq=0 Win=3480 Len=0 MSS=1160 WS=1 SACK_PERM

1309	5929.140281	192.168.0.110	192.168.0.2	TCP	66	[TCP Retransmission] [TCP Port numbers reused] 2409 → 10001 [SYN] Seq=0 Win=3480 Len=0 MSS=1160 WS=1 SACK_PERM

1310	5929.140372	192.168.0.2	192.168.0.110	TCP	66	10001 → 2409 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=1460 WS=256 SACK_PERM

1311	5929.140799	192.168.0.110	192.168.0.2	TCP	60	2409 → 10001 [ACK] Seq=1 Ack=1 Win=3480 Len=0

So the server side does ACK the SYN packet, although there are TCP Retransmission messages in between. Also, when I shut down the server after these TCP messages, I get the following error in Wireshark:

1314	5941.880226	192.168.0.2	192.168.0.110	TCP	54	10001 → 2409 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0

I guess that just inform me on resets of the sockets whenever one of the nodes disconnects?

BTW, I have also tried a UDP setup, which seems to work (in both directions). Laptop as server, laptop as client, MCU1 as server and MCU2 as client. (Which at least tells me I did not screw up my hardware setup, and that the TCP IP stack does work). Since I used the same ports for TCP and UDP, I think that my firewall settings could not be the problem.

Here is the Wireshark PCAP file that I referenced in this post (MSG ID start: 1307):

Wireshark_defunct_TCP_package_withSyn_and_SYN_ACK.zip (17.4 KB)

Thanks again for your help so far, I really appreciate it. If you’d have any more suggestions I could try, that would be great :slight_smile:

Kind regards.

To me this looks more like a problem on the server side. If it takes the Python code 3 retransmissions to respond to the syn request, that smells fishy. Can you try attaching to a different port on the server, eg 80 and see if the three way handshake looks different?

Yeah, that was my idea as well. Especially since I got UDP to work in all directions.

Unfortunately changing the port, changes nothing in the results:

I have tested the server by also creating a Python3 client, that sends a message to the same Python3 server I try to use with the STM32 client. That Python3 client does work on port 80 (and port 10001 for that matter):

I really don’t see what I could’ve done different :sweat_smile:

Thanks in advance.

no, do not change the 80 in your python code. Run, for example, a web server on that machine and try to connect to that. The idea is to take the custom Python code out of the loop-

Ah, excuse me. I misunderstood your statement.

Good idea to remove the Python for a test.
I have installed XAMPP (Windows Local Webserver on port 80). At first it looked like you were right!

Unfortunately it still gives Retransmission errors and also resets the sockets after a few seconds.
Seems the same again :confused:

I have also tried another Python TCP socket package, which also does not work. I really do think it has something to do with my code setup or hardware setup on the STM32F7 part of this project (since all tests without the STM32 TCP setup do work, but UDP from STM32F7 does work, which is kind of odd in my mind).

No, the FreeRTOS code may be consistent. Your Python code definitely has a problem.

Okay, then why does it respond the same to the XAMPP Apache Webserver on port 80?

I did not mean to bash on the FreeRTOS code (it’s great) :stuck_out_tongue:

I was talking about my own FreeRTOS application code/configuration that I probably will have screwed up.

I’ll look at it again tomorrow. If anyone has more suggestions on what I could be doing wrong, that would be greatly appreciated.

And @RAc, thanks for the help so far!

No, the three way connection esrablishment on your web server looks good, but the Python code delays the syn ack unbearably wrong on both port 1001 and 80. the tcp syn “retransmission” and connection reset (initiated by freertos!!!) are NOT the same problem and may simply be consistent with the control flow. Wireshak may erratically see the next connection establishment after a connection shutdown as a retransmission.

Hello @NeusAap , would it be possible if you post a relevant PCAP file, in stead of a picture of a fragment?

Before posting, you can apply a filter like "ip.port==192.168.0.110&&tcp.port==80’ to limit the size of the file.