FreeRTOS+TCP on Zynq fails silently when ucMACAddress not defined

Using a zynq board, I spent a good bit of time scratching my head recently trying to figure out why networking with FreeRTOS+TCP would seem to init but silently fail. Every sign seemed to show that the networking stack was up and ready to process events, but the board refused to receive or send any sort of network traffic. Pings were ignored, TCP connections were ignored, and wireshark showed no sort of acknowledgement from the board’s IP.
The solution that I discovered came after retrying a demo program, and noting that it defined ucMACAddress in main.c. Despite the fact that I had passed the same exact MAC address into FreeRTOS_IPInit, that value was only used later in the initialization process. Instead, ucMACAddresss is defined as extern in the associated NetworkInterface.c for Zynq.

It was pretty unclear that setting ucMACAddress in main.c was crucial for the networking stack to come up at all (save for a single comment in NetworkInterface over the variable itself), and that it was separate from the mac address parameter passed into FreeRTOS_IPInit(). Not only that, but there were absolutely zero indications or messages indicating that the value was unset. It seems like an assert or printf indicating the unset value would have made the problem a lot clearer and easier to diagnose.

If I understand you correctly - the Ethernet source file was referencing an extern variable, but that variable was not defined. I would expect that to result in a linker error though - so am misunderstanding?

@chafla, thanks a lot for reporting this.

@rtel wrote:

the Ethernet source file was referencing an extern variable, but that variable was not defined

I understand that it was defined somewhere, but it was not properly initialised.

I’m very sorry for the trouble that you went through. Today I will propose a patch that should avoid this.

Background: in the demos of FreeRTOS+TCP, the MAC-address is defined in a global variable in main.c:

/* MACAddress as it appears in main.c */
const uint8_t ucMACAddress[ 6 ] =
{
    configMAC_ADDR0,
    configMAC_ADDR1,
    configMAC_ADDR2,
    configMAC_ADDR3,
    configMAC_ADDR4,
    configMAC_ADDR5
};

And this is how FreeRTOS_IPInit() is called:

FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGateway, ucDNS, ucMACAddress );

The Zynq driver, like most other drivers, is relying on this const array.

What we can do is replace ucMACAddress with ipLOCAL_MAC_ADDRESS, which is a copy of the MAC-address set by FreeRTOS_IPInit():

    /* The 'ucMACAddress' in this statement refers to a function parameter.,
     * and not the global variable. */
    memcpy( ipLOCAL_MAC_ADDRESS, ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );

I will prepare a pull-request for this.

2 Likes