Execute a function in idle task just before sleeping

I have a function which does a lot of processing. I only want to execute this function just before I switch my device to sleep mode which is done in the Idle task by checking a variable has been modified by an ISR. Would it be possible to call this function while the scheduler is suspended? I cannot tell whether the idle task does not have enough stack space for this. Here is my code:

void vApplicationIdleHook( void )
{
    if (sleepMode == false)
    {
      //printf ("Exiting sleep mode\n");
    }
    else
    {
      xSemaphoreTake (uartMutexLock, portMAX_DELAY);
      printf ("Enter sleep mode\n");
      xSemaphoreGive (uartMutexLock);

      vTaskSuspendAll ();
      nvm_writeData (); // This function does a lot of processing.
      xTaskResumeAll ();

      PM_StandbyModeEnter ();
    }
}

When I do not call nvm_writeData(), my device is able to enter/exit sleep mode successfully.

Can’t say whether it’s safe to call that function while the scheduler is suspended or not without knowing what it’s doing. If it attempts to yield, then it’s not safe - at least - depending on the architecture - the yield might not occur until within the xTaskResumeAll() function.

The idle task should never try to block, so xSemaphoreTake() can only be called with a zero block time - test the return value to know if the semaphore was obtained. You are calling it with an infinite block time - that may be ok if you have another idle priority task that never blocks, but not otherwise, as the scheduler always needs a task it can run.

The nvm_writeData function writes 3 uint16_t arrays to NVM based on the MCU I am using. Something like this:

void nvm_writeData (void)
{
    bool stop_write = false;
    int i;
    int j;
    sensorData_t arr[ARRAY_SIZE];
    uint8_t data[64] = {0};

    for (i = 0; i < ARRAY_SIZE; i++)
    {
        arr[i].als = ALS_SENSE_READS[i];
        arr[i].ir1 = IR1_SENSE_READS[i];
        arr[i].ir2 = IR2_SENSE_READS[i];
        arr[i].fg_sense = FG_SENSE_READS[i];

        if ((ALS_SENSE_READS[i] == 0x8000) ||
            (IR1_SENSE_READS[i] == 0x8000) ||
            (IR2_SENSE_READS[i] == 0x8000) ||
            (FG_SENSE_READS[i] == 0x8000))
        {
            break;
        }
    }

    for (j = 0; j < i + 1; j + 8)
    {
        data[j] = (arr[i].als & 0xFF);
        data[j + 1] = ((arr[i].als >> 8) & 0xFF);
        data[j + 2] = (arr[i].ir1 & 0xFF);
        data[j + 3] = ((arr[i].ir1 >> 8) & 0xFF);
        data[j + 4] = (arr[i].ir2 & 0xFF);
        data[j + 5] = ((arr[i].ir2 >> 8) & 0xFF);
        data[j + 6] = (arr[i].fg_sense & 0xFF);
        data[j + 7] = ((arr[i].fg_sense >> 8) & 0xFF);
    }

    while (NVMCTRL_IsBusy ());
    NVMCTRL_RowErase ((uint32_t) 0x00400000);

    while (NVMCTRL_IsBusy ());
    NVMCTRL_PageWrite ((uint32_t *) data, (uint32_t) 0x00400000);

    xSemaphoreTake (uartMutexLock, portMAX_DELAY);
    printf ("Finished write\n");
    xSemaphoreGive (uartMutexLock);

    /* Clear all arrays after writing to NVM */
    for (i = 0; i < ARRAY_SIZE; i++)
    {
        ALS_SENSE_READS[i] = 0x8000;
        IR2_SENSE_READS[i] = 0x8000;
        IR1_SENSE_READS[i] = 0x8000;
        FG_SENSE_READS[i] = 0x8000;
    }

    vTaskDelay (1000 / portTICK_PERIOD_MS);

    uint32_t val;
    uint32_t val2;
    uint32_t addr = 0x00400000;
    for (i = 0; i < 400; i + 8)
    {
        NVMCTRL_Read (&val, 4, addr);
        addr += 4;
        NVMCTRL_Read (&val2, 4, addr);
        addr += 4;
        xSemaphoreTake (uartMutexLock, portMAX_DELAY);
        printf ("i: %d B1 0x%x B2 0x%x\n", i, val, val2);
        xSemaphoreGive (uartMutexLock);
    }
}

The vTaskDelay call is only used to check that data has been written to the NVM correctly by having a delayed read of the NVM afterwards.

As per my previous post - you cannot block the idle task because that leaves no tasks for the kernel to switch to. So both the task delay and semaphore take are problematic in the code you posted as both attempt to block.