2

I'm trying to understand FreeRTOS building a C++ class which contains a LED blinking task. But in the task body (which is also a class member), other class members i.e. LED1_delay are empty/not-initialized. It seems like the task body was linked to another instance.

Class function which sets the blinking frequency and starts the task: (gpio.cpp)

void c_gpio::LED_blink_on(float frequency){

    LED1_delay=(uint32_t)(1000/frequency);

    if(LEDTaskcreated!=true){
        //Create task
        LEDTaskHandle = osThreadNew(startTask_LED1_blinker, LEDTask_args, &LEDTask_attributes);
        LEDTaskcreated=true;
    }

}

Wrapper function avoiding static declaration: (gpio.cpp)

void c_gpio::startTask_LED1_blinker(void* _this){
    static_cast<c_gpio*>(_this)->taskbody_LED1_blinker((void*)0);
}

Task body: (gpio.cpp)

void c_gpio::taskbody_LED1_blinker(void* arguments){
    //All class members are uninitialized here..
      while(1)
      {
          HAL_GPIO_TogglePin(GP_LED_1_GPIO_Port,GP_LED_1_Pin);
          osDelay(this->LED1_delay);    //LED1_delay is not set.
      }
}

Class declaration (gpio.hpp)

class c_gpio{

public:
    void LED_blink_on(uint8_t LED_id, float frequency);
private:

    static void startTask_LED1_blinker(void* _this);
    void taskbody_LED1_blinker(void *arguments);
    uint32_t LED1_delay;

    //Task handles & attributes
    osThreadId_t LEDTaskHandle;
    osThreadAttr_t LEDTask_attributes;
    uint16_t LEDTask_args[2];
};

Instantiation (main.cpp)

#include "gpio.hpp"
c_gpio gpio;

int main(void)
{
    gpio.LED_blink_on(1,10);

    /* Init scheduler */
    osKernelInitialize();
    /* Start scheduler */
    osKernelStart();
}

I thought, the members taskbody_LED1_blinker() and LED1_delay are belonging to the same instance. But this doesn't seem to be so. Why? How to properly construct such a task?

Caniko
  • 867
  • 2
  • 11
  • 28
  • Why are you using C-style casts in C++? – Jesper Juhl May 31 '20 at 16:50
  • 1
    Can you put the declarations? – Mirko May 31 '20 at 17:37
  • 1
    And what do you mean by "not seeing"? Are you getting a compile time error? Which one? – Mirko May 31 '20 at 18:41
  • I think `taskbody_LED1_blinker` have to be a `static` function. – HamidReza May 31 '20 at 19:34
  • Please see updated question. – Caniko May 31 '20 at 20:01
  • 1
    You are passing LEDTask_args as an argument and then you expect it to point at this. You should be doing `osThreadNew(startTask_LED1_blinker, this, ...)` – Mirko Jun 01 '20 at 00:07
  • Please also note that method `LED_blink_on()` is not **reentrant** as it accesses `LEDTaskcreated` in an unprotected way. This is not your present problem, but it may happen to become one if you create severeal `c`_gpio objects at a time. – HelpingHand Jun 03 '20 at 22:26
  • The problem was that I missed the fact that the tasks have to be static on FreeRTOS. That means, that the non-static objects of the class are invisible for the static function members. This is partially limiting the object oriented programming using FreeRTOS. (and I believe also other multithreading concepts) After some rework, I converted all needed members to static members. – Caniko Jun 05 '20 at 06:51

1 Answers1

0

Problem:

You have used the class object "gpio" for setting the blicking frequency. meaning the blinking frequency is updated inside the gpio object . Whereas "startTask_LED1_blinker" is a static method of a class which is not bound to any object

Solution:

Take advantage of the "arguments" to the task body function startTask_LED1_blinker. You can send 'this' pointer to the osThreadNew instead of LEDTask_args and then use that pointer to invoke task body "taskbody_LED1_blinker". Correction in your code for reference

    void c_gpio::taskbody_LED1_blinker(void* arguments){
        //All class members are uninitialized here..
        while(1)
        {
            HAL_GPIO_TogglePin(GP_LED_1_GPIO_Port,GP_LED_1_Pin);
            osDelay(LED1_delay);    //LED1_delay is not set.
        }
    }

    void c_gpio::LED_blink_on(float frequency){

        LED1_delay=(uint32_t)(1000/frequency);
        

        if(LEDTaskcreated!=true){
            //Create task
            LEDTaskHandle = osThreadNew(startTask_LED1_blinker, this, &LEDTask_attributes);
            LEDTaskcreated=true;
        }
    }
akshayb
  • 16
  • 3