Dual TCP Autonegotiation


I am using FreeRTOS-Plus-TCP Multiple Interfaces experimental branch in my project with a Zynq-7000 and have a question about the initial setup/autonegotiation.

I initially create two interfaces and fill an end point for each interface before calling FreeRTOS_IPStart(). I know that on start up the first network down event is generated by the IP stack itself to initialise the network hardware. When the initialisation gets to the autonegotiation of the and detection of the phy speed (get_IEEE_phy_speed), it waits for the IEEE_STAT_AUTONEGOTIATE_COMPLETE flag to be set.

If the first ethernet cable is not connected, then the autonegotiation will not complete (as expected). However, the autonegotiation for the second interface will also not complete as it is blocked by the autonegotiation of the first waiting for the IEEE_STAT_AUTONEGOTIATE_COMPLETE flag. I know it is unlikely for the first (or second) cable to become disconnected or have some other issue that could cause this, but I’d like to fix this issue regardless.

With this in mind, would it be advisable to spawn a new task on the initialisation so that this blocking doesn’t happen? Or are there any other ways in which this could be resolved?


Hello @nick,

That is an interesting issue that you pointed out. Thank you for that.

Yes, reading the code, it is clear that the library will keep waiting for the auto-negotiation to complete for the first PHY forever.

Spawning a task is expensive. And then there will be concurrency issues to deal with. I would not suggest you do that.
A simple solution that I can think of is return a ~0U (essentially 0xFFFFFFFF on a 32-bit machine) after you have waited for some time for autonegotiation to complete. Like so here:

+       uint32_t counter = 0;
        while( !( status & IEEE_STAT_AUTONEGOTIATE_COMPLETE ) )
+           counter++;
+           if( counter > 50 /* Or any value that you like */ )
+           {
+               return ( ~0U );
+           }

           /* .... */
           /* .... code snippet removed for brevity .... */
           /* .... */

            vTaskDelay( MINIMUM_SLEEP_TIME );
            XEmacPs_PhyRead( xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET,
                             &status );

Make sure that the upstream functions know what does ~0U mean. Like here you will need to add an else to check whether the function get_IEEE_phy_speed retuned a ~0U.

It is not a very clean solution, but it should work.

Let us know if that helps.