Problem Running Tasks From Within C++ Object

A S
2013-01-21
2013-09-16
  • A S
    A S
    2013-01-21

    NXP17xx port:

    Have simplified problem as follows: Create and run  two simple tasks with for loops and vTaskDelays from a file called main.cpp.  When I try to create and execute those same  tasks from within an object, the program goes off into the weeds.  Note I'm able to to create the tasks and within certain conditions they will run.  If appears that if I make any API call from within a task or the scheduler runs, that that is when the program fails. 

    For example task A has priority 2, task B has priority 3.  If I have a while  loop within Task B that updates a counter, all works fine.  If I add a vTaskDelay() within that loop, the program fails when this function is entered. 

    If I create Task A and B both with the same priority, the programs fails.  I can put a breakpoint in the tasks and one task will start, my guess is that when the scheduler goes to start the other task, the program fails. 

    Before I go doing into this much further to find out where I screwed up things, wondering if there's something fundamentally wrong with creating tasks from within an object. 

    Thanks.

     
  • Richard Damon
    Richard Damon
    2013-01-21

    I am not sure what you mean by "creating a task from within an object". One important thing to remember is that task functions should be declared "extern C" and their signature must be void taskfunc(void*); and thus can NOT be a normal member function.

    When I built a c++ wrapper for FreeRTOS, I had a static member function that made a base class that had a private static member function, that would cast the void* pointer to the type of the class, and call a virtual member function on that pointer. The constructor for that class would create a task using its this pointer for the void* parameter, and the rest of the parameters for task creation were needed to be passed to the constructor which forwarded them to the create task function and stored the task handle in a member variable. 

     
  • A S
    A S
    2013-01-29

    Richard,

    Thanks for the response.  I got sidetracked onto another issue and just got back to this.   I just tried building with the C++ wrapper you referenced (see below), I get build errors regarding the static_cast keyword.

    static_cast(parm)->task();

    The compiler expects a '<' and '<'' characters enclosing "parm".  I'm also not familiar with using '(' and ')' with the static_cast keyword.  What am I doing wrong?

    Also, could you provide a short stub using the class with a function per your description above?

    Thanks,  Andy …

    class TaskBase {
    public:
      xTaskHandle handle;

      ~TaskBase() {
    #if INCLUDE_vTaskDelete
        vTaskDelete(handle);
    #endif
        return;
      }
    };

    class Task : public TaskBase {
    public:
      Task(char const*name, void (*taskfun)(void *), unsigned portBASE_TYPE priority,
           unsigned portSHORT stackDepth=configMINIMAL_STACK_SIZE) {
        xTaskCreate(taskfun, (signed char*)name, stackDepth, this, priority, &handle);
      }

    };

    class TaskClass : public TaskBase {
    public:
      TaskClass(char const*name, unsigned portBASE_TYPE priority,
               unsigned portSHORT stackDepth=configMINIMAL_STACK_SIZE) {
        xTaskCreate(&taskfun, (signed char*)name, stackDepth, this, priority, &handle);
      }
      virtual void task() = 0;
      static void taskfun(void* parm) {
        static_cast(parm)->task();
    #if INCLUDE_vTaskDelete
        xTaskDelete(handle);
    #else
        while(1)
          vTaskDelay(10000);
    #endif
      }
    };

     
  • Joshua Napoli
    Joshua Napoli
    2013-01-29

    The static_cast looks like a typo. Try "static_cast<TaskClass*>(param)->task()"

     
  • Richard Damon
    Richard Damon
    2013-01-30

    Yes, that is what that line should look like. I bet that something thought the contents of the angle brackets was an HTML tag and removed it.

    For Task, you just create a "Task" object, pass it the parameters needed, including a task function, and the task will be created and run, where I find it useful is to create the Task object as a global, so the task is created without needing to add the lines to the main function. This allows different version to be created by just adding needed modules into the project, without needing to change the main file.

    For TaskClass you derive your class you want to run as a task from TaskClass, and define in it member function task as

    virtual void task();

    Each object of that class will cause a task to be created, and run on that object. Again, the object can be created as a global and get created automatically.

     
  • A S
    A S
    2013-01-30

    Thanks to all for the support.