FreeRTOS+TCP in AMD/Xilinx Vitis 2024

Hi, I’m the author of the linked PR. As far as I know in the previous drivers XPAR_PS7_ETHERNET_0_DEVICE_ID is always defined to 0 and if it exists XPAR_PS7_ETHERNET_1_DEVICE_ID is always 1. It was used that way in the Zynq portable code (including before my PR). The Zynq portable layer also only supports either 1 or 2 ethernet devices, so your xEMACIndex is always going to be either 0 or 1.

As @tony-josi-aws states, xEMACIndex isn’t unique to Zynq, that is the API that is in place. The only thing that changed is that Xilinx removed a macro that you were using as the xEMACIndex, so you need to keep track of that yourself now.

1 Like

Anoying in any case.

However, thanks for the help @tony-josi-aws and thanks @mike919192 for the PR!

2 Likes

I agree but I don’t work for Xilinx :slight_smile: I am just a user.

I definitely meant “Anoying that Xilinx does this the way they did” and not “Anoying that you didn’t implement it another way.” :slight_smile:

Thank you @mike919192 for your response!

Hello everybody!

WIth your help I can now compile +TCP but the stack doesn’t seem to opperate. The network up event happens (the callback gets called) and the Link LED is also flashing but I cannot ping the device. I am pretty sure it’s a software problem since the device works fine with an older version of the firmware that was built in Vivado/SDK 2019.
Does anyone have an idea on how to debug this?

If you have enabled DHCP are you getting the IP address and other endpoint settings for the endpoint with which the network up event callback is called?

No, DHCP is deactivated.
In the event hook I do the following

void vApplicationIPNetworkEventHook_Multi( eIPCallbackEvent_t eNetworkEvent, struct xNetworkEndPoint * pxEndPoint )
{
    /* Both eNetworkUp and eNetworkDown events can be processed here. */
    if( eNetworkEvent == eNetworkUp )
    {
        xEventGroupSetBits( os_syncEvents, (1 << OS_FLAG_POS_SYNC_EVENTS_TCP_IP_STACK_READY));
    }

    char buf[16] = {};
    xil_printf("Network is up!\n");
    xil_printf("IP address: %s\n",FreeRTOS_inet_ntoa(pxEndPoint->ipv4_settings.ulIPAddress,buf));
    xil_printf("Subnetmask: %s\n",FreeRTOS_inet_ntoa(pxEndPoint->ipv4_settings.ulNetMask,buf));
    xil_printf("Gateway:    %s\n",FreeRTOS_inet_ntoa(pxEndPoint->ipv4_settings.ulGatewayAddress,buf));
}

and I do get the correct IP, subnet, gateway.

I can also confirm that

  • no ARP traffic is generated
  • emacps_send_message is called and STARTX gets set, TX and rX enable are high

Any other debugging suggestions?

EDIT: I think packets can be received because after activating debug prints for the stack I get

pxEasyFit: ARP C0A8A864ip -> C0A8A8E6ip<\n>
ipARP_REQUEST from C0A8A864ip to C0A8A8E6ip end-point C0A8A8E6ip

uppon trying to ping the device, but in wireshark a don’t see any ARP replies.
@mike919192 Can you upload the config you tested the port with?

I also ran into similar issue. For me it was due to initialization of the TX side being misconfigured, so no TX data is ever transmitted, including ARP data. I got it working properly at least for my configuration:

This is the function that was modified in the PR:

https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/source/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c#L503

Based on this Xilinx example code:

https://github.com/Xilinx/embeddedsw/blob/master/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_intr_dma.c#L1457

When I stepped through the xilinx example code SLCR_GEM0_CLK_CTRL_ADDR is never written to because the macro XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 didn’t exist. I followed the example and put the write to the register behind the $ifndef SDT and that worked for me.

You could try to step through each of these functions to see what the code is doing for your configuration. I attached my FreeRTOSIPConfig.
FreeRTOSIPConfig.h (1.1 KB)

Thanks @mike919192
Indeed it seems that the SCLR for GEM0 wasn’t properly set.
When I ignore the #ifndef SDT and write to the SCLR anyways, the stack works.

I wonder how this should normally work with the SDT.
But I guess that’s a topic for the AMD/Xilinx forum (and will be ignored there).

Is XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 or similar defined in your xparameters.h? For me I have none of those defined with the SDT drivers so when I ran the unmodified function it just ended up writing an uninitialized variable to the register which was obviously wrong.

Maybe instead of the current #ifndef SDT it needs to write a value if one is defined but otherwise don’t write. That would be closer to what is being done in the example code.

No, those are not defined (many others are missing too). You’re absolutely right - I think the SCLR does not get configured in the unmodified version at all.

OK. I think I misread your earlier comment. So to clear it up, is the code in the master branch (which includes my PR) working for you or did you need to modify it? If you modified it can you post the modified code?

No, the code in main does not work for me.
I replaced the #ifndef SDT with #if 1 in SetUpSLCRDivisors (for now): git

Additionally the #XPAR_PS7_ETHERNET_0_ENET_SLCR_x_DIVx defines must exist which they didn’t for me.

OK. I can’t explain why you need to write to the SLCR_GEM0_CLK_CTRL_ADDR while I don’t need to and the example also does not write to the register. I don’t think it is the responsibility of the user or FreeRTOS to define #XPAR_PS7_ETHERNET_0_ENET_SLCR_x_DIVx if it doesn’t exist because it is the Xilinx driver responsibility.

At this point if you want to debug it further I would recommend that you try to run the linked example code. First check that it works for you and then also step through that section to see what is the path that it takes. Next week I can check again the example make sure what I remember is still accurate.

Have a good weekend.

Maybe it’s beneficial if I share some background:

I am not building this project from scratch but porting it from Vivado/SDK 2019 to Vivado/Vitis 2024.2.
In 2019 those parameters are defined in xparameters.h and I can confirm, that the code in x_emacpsif_physpeed.c is actually executed and the SLCR registers are written.
Because of that and because it just make sense that the clock deviders have to be set correctly, I think this could should also be executed in a project built with 2024.2.

Of course the registers may be set with another piece of code, but given that ethernet does not work when I don’t modify the code in main and does work when I do so, I’d say there’s something fishy with the examples.

And yes, does parameters should be generated by the AMD/Xilinx flow, but since they moved to the SDT based flow with Vitis Unified IDE and just don’t generate a lot of parameters that where formely placed in xparameters.h, we’re a bit screwed here.

I am also working with a codebase that has been ported over the years from SDK to the current Vitis. But, I have never really trusted the Xilinx IDE when it comes to project migration though. I have always recreated the workspace when updating and then reimport the application source files. Honestly you should have that process well documented or scripted anyway so its really not difficult to do. That could be a source of the differences that we are seeing.

I did double check the example code that I linked. What I said was correct, that the example also does not have the XPAR_PS7_ETHERNET_0_ENET_SLCR_x_DIVx macros defined, and it does not write to the SLCR_GEM0_CLK_CTRL_ADDR.

I have also recreated the Vivado project and workspace and only copied the source files. I am currently in the process of learning how the porting is done to be able to document and script in the first place.

Regarding examples:
I tried a TCP/IP example on a ZCU106 and it worked fine. However, none of the TCP/IP examples out of Vitis (neither FreeRTOS nor baremetal) worked on our Trenz Electronic TE0715, which holds a xc7z015. Just now that I added the macros, Ethernet is working.

OK, if that’s the case that the examples also don’t run for you that does seem to be a bug in the Xilinx code somewhere. But if the workaround for you seems to be to manually define XPAR_PS7_ETHERNET_0_ENET_SLCR_x_DIVx I think that the FreeRTOS Zynq code can be changed to accommodate the workaround.

@tony-josi-aws Since you reviewed my last PR, does this make sense to you? I can make a followup PR that will accommodate the workaround that we are talking about.