FreeRTOS TCP on Altera Cyclone V

I am trying to enable +TCP on Intel Altera Cyclone V board. I re-use the project from GitHub - htibosch/FreeRTOS-Plus-TCP: FreeRTOS-Plus-TCP library repository. +TCP files only. Submoduled into https://github.com/FreeRTOS/FreeRTOS and various other repos. which is maintained by @htibosch

The initialization looks perfect, and then hang on a random area of DHCP process:

GMAC: enable TX store and forward mode
GMAC: enable RX store and forward mode
PHY : Checking address 4 (ID: 0x16100022)
PHY : Found Micrel KSZ9021 PHY at address 4
PHY : Starting auto-negotiation
PHY : Link is up
PHY : Enabling auto-negotiation
PHY : Link Partner Capabilities :
PHY : 1000 Mbps Full Duplex (YES)
PHY : 1000 Mbps Half Duplex (NO)
PHY : 100 Mbps Full Duplex (YES)
PHY : 100 Mbps Half Duplex (YES)
PHY : 10 Mbps Full Duplex (YES)
PHY : 10 Mbps Half Duplex (YES)
PHY : Rate-variable = 1000
PHY : Link is up at 1000 Mbps full duplex
Network buffers: 52 lowest 52
prvInitialiseDHCP: start after 250 ticks
vDHCPProcess: discover

Then I tried to set DHCP to 0, then it hangs on some other places:

GMAC: enable TX store and forward mode
GMAC: enable RX store and forward mode
PHY : Checking address 4 (ID: 0x16100022)
PHY : Found Micrel KSZ9021 PHY at address 4
PHY : Starting auto-negotiation
PHY : Link is up
PHY : Enabling auto-negotiation
PHY : Link Partner Capabilities :
PHY : 1000 Mbps Full Duplex (YES)
PHY : 1000 Mbps Half Duplex (NO)
PHY : 100 Mbps Full Duplex (YES)
PHY : 100 Mbps Half Duplex (YES)
PHY : 10 Mbps Full Duplex (YES)
PHY : 10 Mbps Half Duplex (YES)
PHY : Rate-variable = 1000
PHY : Link is up at 1000 Mbps full duplex
Network buffers: 52 lowest 52

IP Address: 10.238.236.77
Subnet Mask: 255.0.0.0
Gateway Address: 10.254.212.1
DNS Server Address: 208.67.222.222

RX_EVENT RI 10044 3 6 0RX Recv 0 (60)Network buffers: 51 lowest 51
RX_EVENT RI 10044 3 6 0RX Recv 1 (64)RX_EVENT RI 10044 3 6 0RX Recv 2 (64)RX_EVENT RI 10044 3 6 0RX Recv 3 (243)RX_EVENT RI 10044 3)

Since I can’t upload attachment. I paste the FreeRTOSIPConfig.h here

Is there anything that I need pay attention to? Thank you very much

#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN
#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1
#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 )
#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 )
#define ipconfigUSE_LLMNR ( 0 )
#define ipconfigUSE_NBNS ( 0 )
#define ipconfigUSE_DNS_CACHE ( 1 )
#define ipconfigDNS_CACHE_NAME_LENGTH ( 16 )
#define ipconfigDNS_CACHE_ENTRIES ( 4 )
#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 )
configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in
#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 )
#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 )
#define ipconfigRAND32() uxRand()
#define ipconfigUSE_NETWORK_EVENT_HOOK 1
#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS )
#define ipconfigUSE_DHCP 0
#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS )
required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum
#define ipconfigARP_CACHE_ENTRIES 6
#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 )
/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP
#define ipconfigMAX_ARP_AGE 150
#define ipconfigINCLUDE_FULL_INET_ADDR 1
/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that
#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60
#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 )
#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1
#define ipconfigUDP_TIME_TO_LIVE 128
#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */
#define ipconfigUSE_TCP ( 1 )
#define ipconfigUSE_TCP_WIN ( 1 )
#define ipconfigNETWORK_MTU 1200
#define ipconfigUSE_DNS 0
#define ipconfigREPLY_TO_INCOMING_PINGS 1
#define ipconfigSUPPORT_OUTGOING_PINGS 0
#define ipconfigSUPPORT_SELECT_FUNCTION 1
#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1
#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1
#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS )
#define ipconfigPACKET_FILLER_SIZE 2
simultaneously, one could define TCP_WIN_SEG_COUNT as 120. /
#define ipconfigTCP_WIN_SEG_COUNT 240
#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 )
#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 )
#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL )
#define ipconfigTCP_HANG_PROTECTION ( 1 )
#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 )
#define ipconfigTCP_KEEP_ALIVE ( 1 )
#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /
in seconds */
#define configNETWORK_INTERFACE_TO_USE 2L
#define configECHO_SERVER_ADDR0 192
#define configECHO_SERVER_ADDR1 168
#define configECHO_SERVER_ADDR2 0
#define configECHO_SERVER_ADDR3 11
#define configMAC_ADDR0 0x00
#define configMAC_ADDR1 0x11
#define configMAC_ADDR2 0x22
#define configMAC_ADDR3 0x33
#define configMAC_ADDR4 0x44
#define configMAC_ADDR5 0x41
#define configIP_ADDR0 10
#define configIP_ADDR1 238
#define configIP_ADDR2 236
#define configIP_ADDR3 77
#define configGATEWAY_ADDR0 10
#define configGATEWAY_ADDR1 254
#define configGATEWAY_ADDR2 212
#define configGATEWAY_ADDR3 1
#define configDNS_SERVER_ADDR0 208
#define configDNS_SERVER_ADDR1 67
#define configDNS_SERVER_ADDR2 222
#define configDNS_SERVER_ADDR3 222
#define configNET_MASK0 255
#define configNET_MASK1 0
#define configNET_MASK2 0
#define configNET_MASK3 0
#define configPRINT_PORT ( 15000 )

FreeRTOSIPConfig.h (18.4 KB) main.c (14.4 KB)

File uploaded.

The interrupt handler vEMACInterrupthandler is triggered normally. While in prvEMACHandlerTask, I comment out: vTask_XXX which are not found in FreeRTOS.

//tbd: vTask_init( &xEmacTask, 15 );

//tbd: vTask_finish( &xEmacTask );
/* No events to process now, wait for the next. */
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
//tbd: vTask_start( &xEmacTask );

Hello Austin,

I re-use the project from github.com/htibosch which is
maintained by @htibosch

Feel free to use the drivers from that repo, but I must say that this are not an official release from AWS or from FreeRTOS.

The official release of FreeRTOS+TCP can be found on github.com/FreeRTOS/FreeRTOS.

The Cyclone_V_SoC port was developed for JT Electric, who gave the kind permission to make this driver public.

Can you also upload your FreeRTOSConfig.h please? I will study the files and also I will look up the project sources for which I developed the NetworkInterface.

No problem to comment out the calls to vTask_xxx(). These calls calculate how often a tasks becomes active and for how long. It helped us to optimise the driver.

Sorry to reply in 3 separate posts.

Please find attached the main.c from my Cyclone project:
cyclone_main.zip (15.8 KB)

It is prepared for multiple interfaces (when ipconfigMULTI_INTERFACE is 1)

FreeRTOSConfig.h (9.0 KB) main.c (11.7 KB) my-networkinterface-change.diff.cpp (38.6 KB)

Thanks for the reply. I will look into your files.

I attached more my files

main.c: which is my main file

int main( void )
{
/* Configure the hardware ready to run the demo. /
prvSetupHardware();
/
Start the tasks that implements the command console on the UART, as
described above. /
vUARTCommandConsoleStart( mainUART_COMMAND_CONSOLE_STACK_SIZE, mainUART_COMMAND_CONSOLE_TASK_PRIORITY );
/
Register the standard CLI commands. */
vRegisterSampleCLICommands();
#ifdef FREERTOS_TCP
/*Initialise the internet interface /
start_tcp();
#endif
/
Start the scheduler. */
vTaskStartScheduler();
for( ;; );
}

FreeRTOSConfig.h: my FreeRTOS config file

my-networkinterface-change.diff.cpp: It is the patch against on GitHub - htibosch/FreeRTOS-Plus-TCP: FreeRTOS-Plus-TCP library repository. +TCP files only. Submoduled into https://github.com/FreeRTOS/FreeRTOS and various other repos..

The changes include:

  1. CMakeList.txt which builds FreeRTOS-Plus-TCP with the Cyclone drivers. I use BufferAllocation_1.c. FreeRTOS-Plus-TCP is also copied from GitHub - htibosch/FreeRTOS-Plus-TCP: FreeRTOS-Plus-TCP library repository. +TCP files only. Submoduled into https://github.com/FreeRTOS/FreeRTOS and various other repos.
  2. Two new files eventLogging.h/UDPLoggingPrintf.h which simply call uart0_prinf (I also tried to set the macro to empty, which doesn’t help)
  3. main.c which is copied from FreeRTOS release FreeRTOS-Plus\Demo\FreeRTOS_Plus_TCP_Minimal_Windows_Simulator\main.c and change main to start_tcp which is called from my main.c

One change I would recommend.
Create in FreeRTOSIPConfig.h:
#define ipconfigUSEC_TO_TICKS ( 1000000 / configTICK_RATE_HZ )

Then, in cyclone_phy.c, modify the 3 timeout wait loops to divide by the new definition.
Tout=PHY_LINKUP_TO/ipconfigUSEC_TO_TICKS
Tout=PHY_AUTON_TO/ipconfigUSEC_TO_TICKS

This will scale the time correctly to the defined tick rate.

Hi Manny, thanks a lot for reporting this. You are right that the comments do not correspond with actual behaviour.

The code is waiting 2 ticks in stead of 10 µS:

    /* Wait 10 uS. */
    vTaskDelay( 2 );

This PHY driver was originally developed by Altera ( Intel ).

I propose to change the time-out definitions to use milliseconds and get the extension _MS:

#define PHY_READ_TO_MS     (   100U )  /* Max wait time (ms) when reading from PHY	*/
#define PHY_WRITE_TO_MS    (   100U )  /* Max wait time (ms) when reading from PHY	*/
#define PHY_LINKUP_TO_MS   (  5000U )  /* Max wait time (ms) for link to come up	*/
#define PHY_AUTON_TO_MS    ( 15000U )  /* Max wait time (ms) for auto-ng to succeed*/

( the first 2 macro’s don’t seem to be used. )

And change the loops accordingly:

for( Tout = pdMS_TO_TICKS(PHY_AUTON_TO_MS) ; Tout>0 ; Tout-- )
{
    if (gmac_mdio_read( iMacID, iPHYAddress, PHY_BSR_REG) & PHY_AUTO_NEGOTIATION_COMPLETE) {
        break;     /* Wait for auto-negotiation to complete		*/
    }
    /* Wait 1 clock-tick. */
    vTaskDelay( 1U );
}

I guess you know that vTaskDelay(1) will wait at most 1 clock-tick, depending on the moment on which it is called.
However, in a loop, in which vTaskDelay(1) is called hundreds of times, the actual delay will get close to one clock-tick.

Thanks,

I am running into a problem.
I managed to get the ethernet up and running using the CycloneV code discussed in this thread, but when the first ARP request comes in, the processor will eventually crash with a data abort error when entering vARPGenerateRequestPacket() in FreeRTOS_ARP.c and trying to execute the memcpy() functions.
I have played around with changing these calls an have verified that it is due to a memory alignment issue on pxARPPacket.
I assume that no one has had to modify this function call, so I am wondering if you ran across this issue in your work and what can be done to correct it.
I am running FreeRTOS v10.2.1, compiling with arm-none-eabi-gcc-8.3.1-1.4. I have the compile setting unaligned-access enabled, but understand that the memcpy function in the library may not be compiled for unaligned access.

P.S. Your delay suggestion does look cleaner. I will give that a try when I get a chance.

In vARPGenerateRequestPacket(), memcpy() is called 4 times. Do you know which call leads to an exception?

I have seen crashes that were caused by the compiler replacing a memcpy() with a simple word assignment (when size = 4 ).

The following needs a memcpy():

memcpy( pxARPPacket->xARPHeader.ucSenderProtocolAddress,
	    ipLOCAL_IP_ADDRESS_POINTER,
		sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) );

because ucSenderProtocolAddress is only 16-bit aligned. A word assignment would crash.

It may help if you add these compiler flags: -fno-builtin-memcpy -fno-builtin-memset.

If you can read assembler, you can also see in the LSS file if it is the compiler’s fault.

FreeRTOS v10.2.1 already has the memcpy for ucSenderProtocolAddress you mentioned.
The crashes were occurring on the following 2 lines:
memcpy( ( void * ) pxARPPacket, ( void * ) xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) );
memcpy( ( void* )pxARPPacket->xARPHeader.ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) );
Checking the assembler listing, you were correct that the branch to memcpy did not exist in the assembler code. This seems to be primarly due to the output parameter not being 32-bit aligned.
Adding -fno-builtin-memcpy -fno-builtin-memset fixed this problem and vARPGenerateRequestPacket works properly now.
Unfortunately, my ethernet connection is still not working yet, so I have more debugging to do. Hopefully, my next post will be something more successful. :smile:

I have one last update.
Hein generously provided me his Cyclone TCP test code and my results were exactly the same as I was getting with my code. The Cyclone would successfully negotiate a link but would never actually communicate any data on the bus (i.e. No traffic as seen from Wireshark).

I have since switched to the Xilinx Zync 7000 SOC, an equivlent chip, and my results have been far better. I was able to get my ethernet up and running with minimal effort on this one and will probably use this chip in my products instead.