FreeRTOS+TCP on RT1021 EVK: no Rx Event

Hi,

I’m working on an official RT1021 EVK board to experiment with FreeRTOS and Ethernet communication.

As I’m new to both NXP and FreeRTOS, I started with your TCP Echo example provided in the SDK of the EVK, which is based on LwIP. However, I didn’t feel comfortable with that library (it usually runs out of memory after some editing, I don’t know why), and I wanted to try the FreeRTOS+TCP one.

I soon discovered that your SDK doesn’t provide any working examples based on FreeRTOS+TCP, nor a NetworkInterface suitable for that processor. Luckily, while searching the forum, I found that a user (Dave) had done something similar by porting a NetworkInterface for the RT1064.

However, for some strange reason, it doesn’t work with the latest version of the SDK (2.15) for the EVK because it uses a different implementation of the “fsl_enet” driver. Moreover, I was unable to fully understand what the IDE automatically edits when I import something (usually, I discover more modules/drivers imported than I need), and the import of FreeRTOS and the TCP library lacks some directories/files compared to the GitHub repos. So, I decided to do it the old-fashioned way, importing the things I needed into the source folder of my project.

So, I have externally imported the following:

  • “enet” driver & “phy” component from MCUX_2.12.0_UPDATE (github)
  • “freertos-plus-tcp” source from main/FreeRTOS-Plus on github

After making the necessary changes to the interface (mainly the PHY address) and following the official FreeRTOS-plus-TCP docs, I successfully built the project and loaded it to the board. The project starts up, correctly configures the PHY (I checked with an oscilloscope, bit-to-bit, that the data is the same as the LwIP example), configures the Endpoint (MAC, IP, GW, DNS), and starts the “Main Network Task” (in the project, it’s the “phyksz8081_thread”).

I tried to ping the EVK from my PC (having already set the “ipconfigREPLY_TO_INCOMING_PINGS” flag), but nothing happens, at least in the code (via the oscilloscope, I see that the PHY is sending the data to the MCU). Via Wireshark i see no packets coming from the board, only the ARP and ICMP request from my PC.

Digging into the issue, it seems that the required “kENET_RxFrameInterrupt” never fires, and even looking for a “kENET_RxBufferInterrupt” doesn’t work. Before going further (I need to implement some UDP tests), I decided to ask for some help, mainly because I’ve lost myself in this, and also because I read on the web that at least the ICMP response or the ARP packets should come out of the board with my ipconfig settings.

I’ve attached my project on the NXP forum because i cannot upload here: FreeRTOS+TCP on RT1021 EVK - NXP Community.
Can someone, please, help me find the issue? Is something misconfigured on NXP side or FreeRTOS one?

Thanks

PS: I used the MCUXpresso IDE v11.9.0_2144 for building this project.

EDITED by Actory: fix hyperlink.

@salva2104

Have you verified that you have enabled the ethernet interrupts and set the right interrupt priorities? [example]. Also, were you able to verify that the TX/Tx events work?

If you have a network interface that works with other stacks you could compare that with the one you use for FreeRTOS+TCP to see if you are enabling the right settings.

Hi @salva2104,
Are you using DHCP on the device? If yes, then your driver should work correctly to obtain network settings like IP and gateway. If not, please firstly check if your network environment is properly set up for a static IP address.

Note: from the source code, I see you’re not using DHCP. Could you please check your network environment for static IP setup?

Thank you.

@tony-josi-aws

Thanks for your reply!
The Interrupts are sets in the NetworkInterface.c (NXP1060) i found in the +TCP repo, exactly here: (from r. 386)

/* Enable the interrupt and set its priority to the minimum
* interrupt priority.  */
NVIC_SetPriority( ENET_IRQn, ENET_PRIORITY );
NVIC_ClearPendingIRQ( ENET_IRQn );
NVIC_EnableIRQ( ENET_IRQn );

where

ENET_IRQn = 114
ENET_PRIORITY = 6

this is executed in this contex:

static BaseType_t prvNXP1060_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface )
{
    status_t xStatus;
    BaseType_t xResult = pdFAIL;
    phy_speed_t speed;
    phy_duplex_t duplex;
    BaseType_t xTaskCreated;
    static BaseType_t xFirstCall = pdTRUE;

    configASSERT( FSL_FEATURE_ENET_QUEUE == 1 );

    switch( eEMACState )
    {
        case xEMAC_SetupPHY:
            xStatus = xSetupPHY( &xConfig );
            ...

        /* Fall through. */
        case xEMAC_WaitPHY:
            FreeRTOS_printf( ( "Configuration successful. Waiting for link to go up"
                               " and auto-negotiation to complete." ) );
            ...

        /* Fall through. */
        case xEMAC_Init:
            xStatus = xEMACInit( speed, duplex );

            if( ( xFirstCall == pdTRUE ) || ( receiveTaskHandle == NULL ) )
            {
                if( xStatus == kStatus_Success )
                {
                    /* The link is now up. */
                    bGlobalLinkStatus = true;

                    /* The handler task is created at the highest possible priority to
                     * ensure the interrupt handler can return directly to it. */
                    xTaskCreated = xTaskCreate( prvEMACHandlerTask,
                                                "EMAC-Handler",
                                                configMINIMAL_STACK_SIZE * 3,
                                                NULL,
                                                configMAX_PRIORITIES - 1,
                                                &receiveTaskHandle );

                    if( ( receiveTaskHandle == NULL ) || ( xTaskCreated != pdPASS ) )
                    {
                        FreeRTOS_printf( ( "Failed to create the handler task." ) );
                        break;
                    }

                    /* Enable the interrupt and set its priority to the minimum
                     * interrupt priority.  */
                    NVIC_SetPriority( ENET_IRQn, ENET_PRIORITY );
                    NVIC_ClearPendingIRQ( ENET_IRQn );
                    NVIC_EnableIRQ( ENET_IRQn );

                    eEMACState = xEMAC_Ready;

                    /* After this, the task should not be created. */
                    xFirstCall = pdFALSE;
                }
                else
                {
                    break;
                }
            }
            else
            {
                eEMACState = xEMAC_Ready;
            }

        /* Fall through. */
        case xEMAC_Ready:
            FreeRTOS_printf( ( "Driver ready for use." ) );
            ...
    }

    return xResult;
}

Unfortunally i didn’t have any working code on ethernet / tcpip, and it’s my firts time on this matter from such a lower point of view.
I only tried to play with the example provided by NXP which works by using LwIP that, from my unexperienced point of view, is more difficult to understand.

Anyway, from the software i’m not able to catch any TX/RX event, but i can see them coming from the PHY inspecting the TX and RX lines from the oscilloscope. Obviously I can only see packets coming from outside the board (ICMP from my PC) but nothing is transmitted back.

Hi @ActoryOu ,

yes i tried both configurations, with and without DHCP.

I’m connecting directly on my PC eth port, where usually I connect other statically configured device (linux based) without any issue.

From the board logs i see that it configres correctly the PHY, infact i get back its configuration printed out in the debug console (the UART one) by this portion of code (r. 96 of main_network.c):

		FreeRTOS_inet_ntoa( ulIPAddress, cBuffer );
		FreeRTOS_printf( ( "\r\n\r\nIP Address: %s\r\n", cBuffer ) );

		FreeRTOS_inet_ntoa( ulNetMask, cBuffer );
		FreeRTOS_printf( ( "Subnet Mask: %s\r\n", cBuffer ) );

		FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer );
		FreeRTOS_printf( ( "Gateway Address: %s\r\n", cBuffer ) );

		FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer );
		FreeRTOS_printf( ( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ) );

Is the debug logs turned on? If so please share the logs as well.

Were you able to check the pxInterface->pfInitialize return successfully?
Also please check that the pin mapping defined in the BOARD_InitENETPins are correct as per your board datasheet/manual.

Thanks for the reply Tony…

For debug logs do you mean the “FSL debug console”? if yes, these are my logs currently:

Seed for randomiser: 0

Random numbers:        0      15A       82     2AE6

FreeRTOS_AddEndPoint: MAC: 44-55 IPv4: c0a801c8ip

Hello from main
--- prvIPTask started

Starting PHY initialization.
Configuration successful. Waiting for link to go up and auto-negotiation to complete.
Print del task 1!
Print del task 1!
Timer Task Tick.
Print del task 1!
Print del task 1!
Link up.
Waiting for auto-negotiation to complete.
Auto-negotiation complete.
ENET initialized.
Driver ready for use.


IP Address: 192.168.1.200

Subnet Mask: 255.255.255.0

Gateway Address: 192.168.1.1

DNS Server Address: 208.67.222.222



Timer Task Tick.
Print del task 1!
Print del task 1!
Timer Task Tick.
Print del task 1!
Print del task 1!
Timer Task Tick.
Print del task 1!
Print del task 1!
Timer Task Tick.
Print del task 1!
Print del task 1!
Timer Task Tick.
Print del task 1!
Print del task 1!
ECCOMI ------------------------  ENET Phy_speed = 1, Phy_duplex = 1
Timer Task Tick.
Print del task 1!
Print del task 1!
Timer Task Tick.
Print del task 1!
Print del task 1!
Timer Task Tick.
Print del task 1!
Print del task 1!
Timer Task Tick.
Print del task 1!
Print del task 1!
Timer Task Tick.
Print del task 1!
Print del task 1!
ECCOMI ------------------------  ENET Phy_speed = 1, Phy_duplex = 1

... (and so on) ...

somethimes i receive this log (after 2+ minutes of uptime):

...
Failed to send the frame - driver busy!
Timer Task Tick.
ECCOMI ------------------------  ENET Phy_speed = 1, Phy_duplex = 1
...

about the pxInterface->pfInitialize, it returns in pxMyInterface.
From the debugger i can see the interface being populated:

pxMyInterface	NetworkInterface_t *	0x2000608c <xInterfaces>	
	pcName	const char *	0x20004f8c <pcName.4> "NXP10600	
	pvArgument	void *	0x0	
	pfInitialise	NetworkInterfaceInitialiseFunction_t	0x60002dad <prvNXP1060_NetworkInterfaceInitialise>	
	pfOutput	NetworkInterfaceOutputFunction_t	0x60002f21 <prvNXP1060_NetworkInterfaceOutput>	
	pfGetPhyLinkStatus	GetPhyLinkStatusFunction_t	0x60002fbd <prvNXP1060_GetPhyLinkStatus>	
	bits	struct {...}	{...}	
	pxEndPoint	struct xNetworkEndPoint *	0x200060ac <xEndPoints>	
	pxNext	struct xNetworkInterface *	0x0

and if i expand a little, it populates like this (JSON formatted for readability):

{
    "pxMyInterface": {
        "pcName": "NXP10600",
        "pvArgument": null,
        "pfInitialise": "prvNXP1060_NetworkInterfaceInitialise",
        "pfOutput": "prvNXP1060_NetworkInterfaceOutput",
        "pfGetPhyLinkStatus": "prvNXP1060_GetPhyLinkStatus",
        "bits": {
            "bInterfaceUp": 1,
            "bCallDownEvent": 0
        },
        "pxEndPoint": {
            "ipv4_settings": {
                "ulIPAddress": 3355551936,
                "ulNetMask": 16777215,
                "ulGatewayAddress": 16885952,
                "ulDNSServerAddresses": [0, 0],
                "ulBroadcastAddress": 4278298816,
                "ucDNSIndex": 0
            },
            "ipv4_defaults": {},
            "xMACAddress": {},
            "bits": {
                "bIsDefault": 0,
                "bWantRA": 0,
                "bIPv6": 0,
                "bCallDownHook": 1,
                "bEndPointUp": 1
            },
            "usDNSType": 0,
            "xDHCP_RATimer": {},
            "xRAData": {},
            "pxNetworkInterface": {
                "pcName": "NXP10600",
                "pvArgument": null,
                "pfInitialise": "prvNXP1060_NetworkInterfaceInitialise",
                "pfOutput": "prvNXP1060_NetworkInterfaceOutput",
                "pfGetPhyLinkStatus": "prvNXP1060_GetPhyLinkStatus",
                "bits": {
                    "bInterfaceUp": 1,
                    "bCallDownEvent": 0
                },
                "pxEndPoint": {},
                "pxNext": null
            },
            "pxNext": null
        },
        "pxNext": null
    }
}

About the BOARD_InitENETPins i double checked it, but i was confident it was already ok because i used the default board.c|h files provided by NXP for the evaluation board.

The only thing i don’t understand is the “ENET_INT” pin, because in the LwIP example it is pulled up (set as output and HIGH) before PHY reset, and i can’t see any code that reconfigures it as input with interrupt; in my code i commented out this part (in the InitEthernet function) but i can see that it is configured as interrupt during pin config and it is pulled-up by 1k resistor.
Here is the relevant portion from LwIP example :

// main.c
int main(void)
{
    gpio_pin_config_t gpio_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode};

    BOARD_ConfigMPU();
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    BOARD_InitDebugConsole();
    BOARD_InitModuleClock();

    IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, true);

    GPIO_PinInit(GPIO1, 4, &gpio_config);
    GPIO_PinInit(GPIO1, 22, &gpio_config);
    /* Pull up the ENET_INT before RESET. */
    GPIO_WritePinOutput(GPIO1, 22, 1);
    GPIO_WritePinOutput(GPIO1, 4, 0);
    SDK_DelayAtLeastUs(10000, CLOCK_GetFreq(kCLOCK_CpuClk));
    GPIO_WritePinOutput(GPIO1, 4, 1);

    MDIO_Init();
    g_phy_resource.read  = MDIO_Read;
    g_phy_resource.write = MDIO_Write;

    /* Initialize lwIP from thread */
    if (sys_thread_new("main", stack_init, NULL, INIT_THREAD_STACKSIZE, INIT_THREAD_PRIO) == NULL)
        LWIP_ASSERT("main(): Task creation failed.", 0);

    vTaskStartScheduler();

    /* Will not get here unless a task calls vTaskEndScheduler ()*/
    return 0;
}
// pin_mux.c
void BOARD_InitPins(void) {
  CLOCK_EnableClock(kCLOCK_Iomuxc);           

  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_04_GPIO1_IO04, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_06_LPUART1_TX, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_07_LPUART1_RX, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_08_ENET_REF_CLK1, 1U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_09_ENET_RDATA01, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_10_ENET_RDATA00, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_11_ENET_RX_EN, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_12_ENET_RX_ER, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_13_ENET_TX_EN, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_14_ENET_TDATA00, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_15_ENET_TDATA01, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_06_GPIO1_IO22, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_EMC_40_ENET_MDIO, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_EMC_41_ENET_MDC, 0U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_04_GPIO1_IO04, 0xB0A9U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_06_LPUART1_TX, 0x10B0U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_07_LPUART1_RX, 0x10B0U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_08_ENET_REF_CLK1, 0xB0E9U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_09_ENET_RDATA01, 0xB0E9U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_10_ENET_RDATA00, 0xB0E9U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_11_ENET_RX_EN, 0xB0E9U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_12_ENET_RX_ER, 0xB0E9U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_13_ENET_TX_EN, 0xB0E9U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_14_ENET_TDATA00, 0xB0E9U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_15_ENET_TDATA01, 0xB0E9U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_06_GPIO1_IO22, 0xB0A9U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_EMC_40_ENET_MDIO, 0xB0E9U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_EMC_41_ENET_MDC, 0xB0E9U); 
}

@salva2104

It seems like the BOARD_InitPins definition in the project you shared is empty. Though BOARD_InitENETPins sets the IOMUXC pin mux mode for ethernet pins, it doesn’t seem to configure those pins using IOMUXC_SetPinConfig.

Hi @tony-josi-aws,

yes, the BOARD_InitPins is empty in my code because i consider it like a “GPIO declaring zone”.
If a pin serves or belong to a peripheral, then I will configure it in a peripheral-specific function.

In my code, at main(), I call first BOARD_InitBootPins() (r.189 of MIMXRT1021_Project.c) which will call all other pin init functions:

void BOARD_InitBootPins(void) {
    BOARD_InitPins();
    BOARD_InitDEBUG_UARTPins();
    BOARD_InitENETPins();
}

about the BOARD_InitENETPins() function, I added the IOMUXC_SetPinConfig as in the LwIP example:

void BOARD_InitENETPins(void) {
  CLOCK_EnableClock(kCLOCK_Iomuxc);           

  /* GPIO configuration of ENET_INT on GPIO_AD_B1_06 (pin 84) */
  gpio_pin_config_t ENET_INT_config = {
      .direction = kGPIO_DigitalInput,
      .outputLogic = 0U,
      .interruptMode = kGPIO_IntRisingEdge
  };
  /* Initialize GPIO functionality on GPIO_AD_B1_06 (pin 84) */
  GPIO_PinInit(GPIO1, 22U, &ENET_INT_config);
  /* Enable GPIO pin interrupt on GPIO_AD_B1_06 (pin 84) */
  GPIO_PortEnableInterrupts(GPIO1, 1U << 22U);

  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_04_GPIO1_IO04, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_08_ENET_REF_CLK1, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_09_ENET_RDATA01, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_10_ENET_RDATA00, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_11_ENET_RX_EN, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_12_ENET_RX_ER, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_13_ENET_TX_EN, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_14_ENET_TDATA00, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_15_ENET_TDATA01, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_06_GPIO1_IO22, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_EMC_40_ENET_MDIO, 0U); 
  IOMUXC_SetPinMux(IOMUXC_GPIO_EMC_41_ENET_MDC, 0U); 

  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_04_GPIO1_IO04, 0xB0A9U);
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_08_ENET_REF_CLK1, 0xB0E9U);
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_09_ENET_RDATA01, 0xB0E9U);
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_10_ENET_RDATA00, 0xB0E9U);
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_11_ENET_RX_EN, 0xB0E9U);
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_12_ENET_RX_ER, 0xB0E9U);
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_13_ENET_TX_EN, 0xB0E9U);
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_14_ENET_TDATA00, 0xB0E9U);
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_15_ENET_TDATA01, 0xB0E9U);
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_06_GPIO1_IO22, 0xB0A9U);
  IOMUXC_SetPinConfig(IOMUXC_GPIO_EMC_40_ENET_MDIO, 0xB0E9U);
  IOMUXC_SetPinConfig(IOMUXC_GPIO_EMC_41_ENET_MDC, 0xB0E9U);
}

but the board still acts as before this changes… :frowning:

Have you tried enabling the interrupt once the interrupt pin is configured?

@tony-josi-aws

Yes, I also tried enabling the interrupt after the pin was configured, but it didn’t work as expected…

Upon inspecting the ENET_INT line (connected to IOMUXC_GPIO_AD_B1_06_GPIO1_IO22), it never goes to a low level.
Reading the KSZ8081 datasheet, it seems that this condition occurs when no signal is routed to the interrupt pin: I didn’t configure (manually) any interrupt on the PHY, and based on the behavior, it seems that FreeRTOS isn’t performing such an operation either.
Therefore, I deduce that it’s necessary to regularly poll the interrupt register of the PHY to receive a new RxFrame interrupt…

Upon reanalyzing the MDIO transaction that occurs during the LwIP demo execution, compared to my own, it seems that my code is missing a poll to the aforementioned register (the register address is 0b11011).

Am I missing some FreeRTOS+TCP configuration/initialization for enabling the polling of this register?

@salva2104

I see that there are some modifications done to the network interface file in your project:

@@ -375,7 +372,7 @@ static BaseType_t prvNXP1060_NetworkInterfaceInitialise( NetworkInterface_t * px
                     xTaskCreated = xTaskCreate( prvEMACHandlerTask,
                                                 "EMAC-Handler",
                                                 configMINIMAL_STACK_SIZE * 3,
-                                                pxInterface,
+                                                NULL,
                                                 configMAX_PRIORITIES - 1,
                                                 &receiveTaskHandle );
@@ -501,7 +507,7 @@ static void prvEMACHandlerTask( void * parameter )
         if( ulTaskNotifyTake( pdTRUE, pdMS_TO_TICKS( 500 ) ) == pdFALSE )
         {
             /* No RX packets for a bit so check for a link. */
-            const IPStackEvent_t xNetworkEventDown = { .eEventType = eNetworkDownEvent, .pvData = parameter };
+            const IPStackEvent_t xNetworkEventDown = { .eEventType = eNetworkDownEvent, .pvData = NULL };
         if( bGlobalLinkStatus == true )
         {
-                {
-                    xTaskNotify( receiveTaskHandle, DRIVER_READY, eSetValueWithOverwrite );
-                }
-
                 break;

Are those intentional? Whats the reasoning behind those changes?

The BOARD_InitENETPins function configures pin as (GPIO1, 22) as kGPIO_IntRisingEdge:

 GPIO_PinInit(GPIO1, 22U, &ENET_INT_config);

The same pin is again configured as kGPIO_NoIntmode in main:

 GPIO_PinInit(GPIO1, 22, &gpio_config);

This does not seem right. Is this intentional?

Thanks for the replies…

@tony-josi-aws

You’re right, I made those changes as a test and forgot to revert them, thanks!
However, reverting those changes didn’t solve the issue. :frowning:

@aggarg

Thanks for the note. It was a remnant of the LwIP demo code: the demo configures that pin in the main function, while I do it in the pin initialization function, because that’s the standard method used in NXP’s Eclipse-based IDE (MCUXpresso).
Anyway, that pin isn’t used at all, neither by the demo code nor by the FreeRTOS NXP1060 network interface, so right now I’m essentially ignoring that signal.
I’ve also seen more demo code online doing the same: mimxrt1020_eth_driver.c Source Code - NXP i.MX RT1020 Ethernet MAC driver (oryx-embedded.com)

Upon closer inspection of the code used in the LwIP demo (based on the NXP SDK v2.14 generated from this site: Welcome | MCUXpresso SDK Builder), it uses a PHY driver located in the folder component > phy, fsl_phy.h + fsl_phyksz8081.c|h.

However, if you use the SDK designed for VSCode (which can be found here: GitHub - nxp-mcuxpresso/mcux-sdk: MCUXpresso SDK @tag=MCUX_2.12.0_UPDATE ), you will notice that the structure of component > phy folder is different, as it contains two other directories within it, dividing the code into device and mdio folders.

If I try to use the NetworkInterface.c (NXP1060) of FreeRTOS with the IDE repo, the project does not compile because phy_handle has a different structure than expected. In fact, the project only compiles for me with the VSCode SDK at tag MCUX_2.12.0_UPDATE, which, however, in the file fsl_phyksz8081.c lacks the following define:
#define PHY_INTR_CONTROL_STATUS_REG (0x1BU) /*!< The PHY interrupt control/status register. */
and the related functions in that file:

status_t PHY_KSZ8081_EnableLinkInterrupt(phy_handle_t *handle, phy_interrupt_type_t type)
status_t PHY_KSZ8081_ClearInterrupt(phy_handle_t *handle)

Is it possible that I do not see the read request for register 0x1B passing on the MDIO bus? Do you know where, in FreeRTOS, is this register requested to the PHY?

I pointed that out because few posts before you mentioned that the interrupt was not getting fired and I thought that was your problem.

Though you should confirm it with NXP, it looks like it is new SDK and therefore, more likely to work. How much is the structure difference and is it possible to fix these issues?

@aggarg
you are right, I was talking about interrupts. However, I was referring to the ENET device interrupts, I failed to specify this, my apologies.

Regarding the SDK, I can tell you that by using the latest version of the SDK for VSCode, it presents the missing functions, yet still a phy_handle structure that is not compatible.
Essentially, the NetworkInterface.c file requires that phy_handle has a structure like this:

/*! @brief PHY device handle. */

struct _phy_handle
{
    uint32_t phyAddr;            /*!< PHY address. */
    mdio_handle_t *mdioHandle;   /*!< The MDIO handle used by the phy device, it is specified by device. */
    const phy_operations_t *ops; /*!< The device related operations. */
};

instead, I find myself with this:

/*! @brief PHY device handle. */
struct _phy_handle
{
    uint8_t phyAddr;             /*!< PHY address. */
    void *resource;              /*!< PHY specific resource supporting operation of PHY hardware. */
    const phy_operations_t *ops; /*!< PHY operational method. */
};

The code fails in NetworkInterface.c at this lines

// r. 202
static phy_handle_t phyHandle = { .phyAddr = 0x00, .mdioHandle = &mdioHandle, .ops = &EXAMPLE_PHY_OPS };
// r. 852
sysClock = phyHandle.mdioHandle->resource.csrClock_Hz;

I tried to adapt the code of NetworkInterface.c like this:

// r. 202
static phy_handle_t phyHandle = { .phyAddr = 0x00, .ops = &EXAMPLE_PHY_OPS };
// r. 852
sysClock = mdioHandle.resource.csrClock_Hz;

which let me build but when I try to run I end up in hardfault:

Program received signal SIGSTOP, Stopped (signal).
HardFault_Handler () at ../source/semihost_hardfault.c:53
53	    __asm(  ".syntax unified\n"

Temporary breakpoint 19, main () at ../source/MIMXRT1021_Project.c:199
199	    BOARD_ConfigMPU();

Breakpoint 14, pxNXP1060_FillInterfaceDescriptor (xEMACIndex=0, pxInterface=0x2000608c <xInterfaces>) at ../source/external/freertos-plus-tcp/source/portable/NetworkInterface/NXP1060/NetworkInterface.c:310
310	    return pxInterface;

Breakpoint 2, main () at ../source/MIMXRT1021_Project.c:249
249		vTaskStartScheduler();

Breakpoint 9, PHY_Init (handle=0x2000000c <phyHandle>, config=0x2000001c <xConfig>) at ...\source\external\phy/fsl_phy.h:202
202	    handle->ops = config->ops;

:exploding_head:

It seems like the member mdio_handle_t *mdioHandle is changed to void *resource. If that is correct, you should update your code like the following:

// r. 202
static phy_handle_t phyHandle = { .phyAddr = 0x00, .resource = ( void * )&mdioHandle, .ops = &EXAMPLE_PHY_OPS };
// r. 852
mdio_handle_t *mdioHandle = ( mdio_handle_t * )( phyHandle.resource );
sysClock = mdioHandle->resource.csrClock_Hz;

Again, it based on the assumption that the member mdio_handle_t *mdioHandle is changed to void *resource.

Thanks for the tip @aggarg

with your suggestions the code builds but it crashes at the same point. executing this:

static inline status_t PHY_Init(phy_handle_t *handle, const phy_config_t *config)
{
    handle->ops = config->ops;
    return handle->ops->phyInit(handle, config);
}

I’m not so skilled in C to identify the issue, so I’ll try to post this issue also on the NXP forum…

EDIT:
I would like to know if @Dave (which originally ported the NetworkInterface) have some suggestion for us :slight_smile:

@salva2104

Did you get response from NXP forum?

code builds but it crashes at the same point. executing this:

Were you able to step through the code and find whats leading to the crash? Is it a fault?

Hi @tony-josi-aws,

unfortunately i got no useful replies, yet, about FreeRTOS+TCP implementation on the NXP side.
Right now I had to switch the project for using the LwIP stack and found a way to work with it.

I hope to report some update as soon as I will have time to play again with FreeRTOS+TCP stack.

Thanks for now :slight_smile: