Can vTaskDelay() be called outside a task from a different cpp file?

abdulsamad-ets wrote on Wednesday, May 23, 2018:

Hi,

I’m running FreeRTOS ver 9.0.0 on Cortex-M4 (MK20DX256) and I’ve recently run into an issue with the MCU freezing completely while running FreeRTOS. Although I haven’t managed to replicate the case again, I’m taking precautionary measures so it doesn’t repeat again - hopefully we’ll figure out why it froze in the first place.

I’m curious if the cause of crash/freeze could have anything to do with calling vTaskDelay() or any other FreeRTOS function from a function outside the task esp if that function happens to be in a different cpp file e.g.

//////////////////////////////////////////////////
Functions.h
//////////////////////////////////////////////////

#ifndef _PIN_DEFS_h
#define _PIN_DEFS_h

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include "Pins.h" // includes references to pin numbers, delays

void power_down();

#endif

//////////////////////////////////////////////////
Functions.cpp
//////////////////////////////////////////////////

#include "Functions.h"
#include "RTOS.h" // FreeRTOS headers e.g. FreeRTOS, task, semphr, timers

void power_down()
{
    pinMode(PWR, LOW);
    while (digitalRead(PWR_STAT))
    {
            vTaskDelay(pdMS_TO_TICKS(DELAY_SHORT));
    }
}

//////////////////////////////////////////////////
main.cpp
//////////////////////////////////////////////////

#include "RTOS.h"
#include "Functions.h"

void setup()
{
    xTaskCreate(PowerDownTask, NULL, configMINIMAL_STACK_SIZE, tskIDLE_PRIORITY + 2, NULL);
    // create other tasks

    vTaskStartSchedule();

    while (true) {}
}

static void PowerDownTask(void *pvParameters)
{
    // do stuff
    while (true)
    {
                // do stuff
                power_down();
    }
}

Can there be any problems leading to system freezing due to calling power_down()?

heinbali01 wrote on Wednesday, May 23, 2018:

Hi AbdulSamad , you should investigate what the “freezing” is. Could there be an exception, that ends in an eternal loop for(;;)?
Does your function digitalRead() always succeed? Or does it wait for a condition that sometimes does not occur?

esp if that function happens to be in a different cpp file e.g.

It should not make any difference in which source file a function is located.

Are you using C++ ? That should work OK with FreeRTOS, as long as the compiler knows the linkage type of every function ( C versus C++ ).

C-only headers will often include these statements:

    #ifdef __cplusplus
    extern "C" {
    #endif

    /* Put your C declarations here */

    #ifdef __cplusplus
    }
    #endif

Mind you that constructors of global and static C++ objects, are being called before main() is active. If you use the option nostartfiles, you will have to call the constructors your self. Also make sure that in these constructors, you can not use many resources: for instance the heap has not been set-up yet before main() is running.

The code that you’re showing is simple and looks good to me.

abdulsamad-ets wrote on Wednesday, May 23, 2018:

Hi Hein,

Thanks for your feedback.

Yes, I’m using C++. The code in the example above constitutes a small chunk of the functionalities in the original application and I thought it would be most suitable for elaboration purposes.

you should investigate what the “freezing” is. Could there be an exception, that ends in an eternal loop for(;;)?

Good pointers! I’ve come across such cases before and to avoid them, I’ve added a good amount of precautionary measures as follows:

  • all tasks have while(true) or for( ; ; ) loops
  • all tasks defined as static
  • no while(true) or for( ; ; ) loop exists without vTaskDelay()
  • software doesn’t try to access invalid memory e.g. task handles, and semaphores
  • no unsupported blocking function is called e.g. Arduino’s delay()
  • semaphores are accessed only when available
  • after deleting tasks, assign their task handles to NULL and call vTaskDelay()

I’ll look into the C-only headers and double check the library if the expressions need to be added.

Do you mind elaborating on this part please?

Mind you that constructors of global and static C++ objects, are being called before main() is active. If you use the option nostartfiles, you will have to call the constructors your self. Also make sure that in these constructors, you can not use many resources: for instance the heap has not been set-up yet before main() is running.

heinbali01 wrote on Wednesday, May 23, 2018:

Do you mind elaborating on this part please?

Well, here is an example to make it clear:

class CMyClass {
    uint8_t *pcBuffer;
public:
    CMyClass();
    ~CMyClass();
};

CMyClass::CMyClass()
{
    // main() might not be running yet
    pcBuffer = pvPortMalloc( BUFFER_SIZE );
}

CMyClass::~CMyClass()
{
    // This might never get called
    vPortFree( pcBuffer );
}

// Constructor will be called *before* main is active.
// Destructor  will be called *after* main has exit,
// which never happens
CMyClass globalObject;

int main()
{
    // Initialise hardware.
    // Initialise heap.

    // Here OK : heap has been initialised
    // The destructor is never called because
    // vTaskStartScheduler() never returns
    CMyClass autoObject;

    // Start scheduler.
    vTaskStartScheduler();
}

abdulsamad-ets wrote on Thursday, May 24, 2018:

Ah, right. This has been covered.

Thanks a lot, Hein!