lwIP initialization problem (init task vs init function)

I have a problem with initializing the lwip.
I want to intialise components for my board in a function before the task scheduler starts. I have a problem with it: the lwIP initialization works if initialized with a task, but the same code doesn’t work when run as function. What I mean with this is that the application crashes when I wish to use the stack. The netconn_recv() or netconn_send() functions simply make the board freeeze.

This works (main.c):

  /* Write your code here */
  /* Initialize and configure clocks */
    CLOCK_SYS_Init(g_clockManConfigsArr, (uint8_t)CLOCK_MANAGER_CONFIG_CNT, g_clockManCallbacksArr, (uint8_t)CLOCK_MANAGER_CALLBACK_CNT);
    CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);

    /* Initialize pins */
    PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);

    /* generate a struct with paramaters for the init function, and place it on the heap */
    taskParams *initParams;
    initParams = (taskParams*) pvPortMalloc(sizeof(taskParams));
    SemaphoreHandle_t ptr_binary_sem;
    ptr_binary_sem = xSemaphoreCreateBinary();
    initParams->binary_sem_ptr = ptr_binary_sem;

    /* create Tasks */
    xTaskCreate(vInitTask, "InitTask", 256U, (void*)(initParams), 10, NULL);
    xTaskCreate(vUDPpingpong, "UDPpingpong", 256U, (void*)(initParams), 9, NULL);
	xTaskCreate(vBlinkLEDTask, "blinkLEDTask", 256U, NULL, 1, NULL);

	vTaskStartScheduler();
  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/

And this doesn’t work (also main.c):

   /* Write your code here */
   /* Initialize and configure clocks */
    CLOCK_SYS_Init(g_clockManConfigsArr, (uint8_t)CLOCK_MANAGER_CONFIG_CNT, g_clockManCallbacksArr, (uint8_t)CLOCK_MANAGER_CALLBACK_CNT);
    CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);

    /* Initialize pins */
    PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);

    /* generate a struct with paramaters for the init function, and place it on the heap */
    taskParams *initParams;
    initParams = (taskParams*) pvPortMalloc(sizeof(taskParams));
    SemaphoreHandle_t ptr_binary_sem;
    ptr_binary_sem = xSemaphoreCreateBinary();
    initParams->binary_sem_ptr = ptr_binary_sem;

    /* initialize tcpip */
    initFunc();

    /* create Tasks */
    xTaskCreate(vUDPpingpong, "UDPpingpong", 256U, (void*)(initParams), 9, NULL);
	xTaskCreate(vBlinkLEDTask, "blinkLEDTask", 256U, NULL, 1, NULL);

	vTaskStartScheduler();
  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/

I am pasting underneath the code I use for initalisation - as you can see it is the same code for a task or for a function:

   void initFunc(void){
    /*init the internet stack */
       tcpip_init(NULL, NULL);
       enetif_init();
  }

VS

void vInitTask(void* pvParameters){
 	/*init the internet stack */
    tcpip_init(NULL, NULL);
    enetif_init();
 
   vTaskDelete(NULL);
   }

I tried to debug the code, but it simply crashes when I wish to recieve or send packets over UDP. It is difficult to say what is the reason - all the functions are called with correct arguments and all function calls looks exactly the same in both cases. I do not understand the assembly debugger enough to be able to figure out any differences.

I am using MPC5748G board from NXP.

Does anybody know what could be the reason of such behaviour?

One more piece of code - my enetif_init() function:

  static void enetif_init(void)
  {
      for(int i = 0; i < ENETIF_NUMBER; i++)
          {
          ip4_addr_t ipaddr, netmask, gw;
         struct netif *mynetif;

          ip4_addr_set_zero(&gw);
          ip4_addr_set_zero(&ipaddr);
          ip4_addr_set_zero(&netmask);
         /* network_interfaces[i] takes the IPV4 addresses from the respective configuration */
         if ((!netif_cfg[i]->has_dhcp) && (!netif_cfg[i]->has_auto_ip))
         {
           IP4_ADDR((&gw), netif_cfg[i]->gw[0], netif_cfg[i]->gw[1], netif_cfg[i]->gw[2], netif_cfg[i]->gw[3]);
           IP4_ADDR((&ipaddr), netif_cfg[i]->ip_addr[0], netif_cfg[i]->ip_addr[1], netif_cfg[i]->ip_addr[2], netif_cfg[i]->ip_addr[3]);
           IP4_ADDR((&netmask), netif_cfg[i]->netmask[0], netif_cfg[i]->netmask[1], netif_cfg[i]->netmask[2], netif_cfg[i]->netmask[3]);
         }
         mynetif = netif_add(&network_interfaces[i], &ipaddr, &netmask, &gw, NULL, enet_ethernetif_init, tcpip_input);
         netif_set_up(&network_interfaces[i]);
         netif_set_default(&network_interfaces[i]);

}

I am not very familier with LWIP but I’d assume that bringing up Ethernet interface would require the scheduler to be running. You can use vApplicationDaemonTaskStartupHook function to perform the initialization that requires scheduler to be running: https://github.com/aws/amazon-freertos/blob/master/vendors/cypress/boards/CY8CKIT_064S0S2_4343W/aws_demos/application_code/main.c#L276

Thanks.

Thanks for the answer, it worked.
I have one more question though - where are the initalised variables placed? Is it all on the heap? Do I have to worry about some special stack management to keep the variables initialised?

this is what I did to make it work (for future reference):

  1. I enabled the configUSE_DAEMON_TASK_STARTUP_HOOK in FreeRTOSConfig.h.
  2. I put my initialization code in a vApplicationDaemonTaskStartupHook() function.
  3. I built the project. There is no need to call the function - task scheduler does it by itself.

where are the initalised variables placed? Is it all on the heap? Do I have to worry about some special stack management to keep the variables initialised?

Would you please mention which variables are you talking about? FreeRTOS does nothing special to variables and the normal C rules should apply.

Thanks.