C++ wrappers, additional questions

I’ve managed to get the C++ tasking working, and create C++ tasks with semaphores and queues, which are all that I need. However, I have a few questions and some observations.

  1. Apparently, It’s one task per C++ class. I have a situation where two tasks are needed. Side stepped that one by having one task as part of the class and one task with the original code, not a member of the class.

  2. In the hardware design I have, the graphics are a RAM hog, and the processor has insufficient memory. I’ve added memory (it’s an STM32L562VET6Q processor with an OCTOSPI interface. The memory is an AP6404 64 Mbit QSPI memory). The added memory is significantly slower than processor on board memory.

I’ve changed the FreeRTOS stack to use external memory (part of the 64Mbit memory) as the heap. For tasks happening every 100 ms or so, (vTaskDelay) the speed difference does not slow down the system.

However, the graphics system writes to a virtual display image (32 bit color). The low level display driver task (in this case for an ILI9341) takes a queue input of an update packet (rectangular area update) and copies and formats the virtual display for the ILI9341, calling the SPI drivers as needed.

This works.
However. If the task is located in extended memory, it’s quite slow. If the task is located in processor memory, it runs quite a bit faster (acceptably so).

The question becomes: TaskClassS makes decisions on the global condition of whether static allocation is used or not. Short of modifying that class (and making a copy of it), is there a way to specify the location of the task in the system call to TaskClassS?

  1. last, and a puzzlement.
    The screen variable is the owner of a graphics tree of linked graphics objects, which can have siblings, and in some cases children. Drawing the screen automatically draws all objects belonging to that screen. This works, mostly.

With the widgets (graphics objects that update themselves with a task), I get several problems with TaskCPP. One is that not all of the code in the class works properly, which may well be related to the use of a virtual object for drawing. It looks as if the virtual object is broken somehow so that a simple “if object.property == specific property)” equality is not working.

The other problem I’m having with this is that the draw routine hangs when drawing a widget. Literally, wherever it gets to, the rest of the tasks work and the main task is somehow suspended. No idea on that one.

I do have a workaround, and that’s simply to go back to the original code, which places the task outside the class. Oddly enough, that works perfectly.

Any thoughts?

Thanks, code is much nicer with the wrappers…

Since TCB’s are fairly small and not accessed much, to control the type of memory that a task is placed in, use the static allocation option (give the stack size as the template parameter) and put the class “object” in the memory that is right speed for the task with the appropriate attribute for your system.

As to class operations not working, all I can think of is that somehow you are overwriting something that you shouldn’t.

I’m not sure how to do that within the syntax of your wrappers, so an example would be appreciated.

As far as the overwriting something, it makes sense, but I’m not sure how and where. The difference is only the use of TaskClassS.
Using the standard non-C++ tasks, I know how to structure things.
All of the tasks show no heap overrun

From what I understand (and both static and dynamic allocation are enabled), without supplying parameters other than task heap size, you use normal allocation. I’ve overlaid the “new” and “free” operators with pvPortMalloc and so on, so it’s thread safe and should not have a problem. Most of the graphics objects are controlled by pointers initialized by “new”

Thanks for the help

If you provide the stack size template parameter, and have static creation enabled (strongly suggested) then the template will automatically put inside the object you are making the TCB and stack for the task.

How to put in into a given chunk of memory is a function of the tools you are using. The normal GCC method is adding an attribute((section(“sectionname”))) which will place the object into a named loader segment which you place with the linker control file (where you are telling it about your various memories).

static creation and dynamic creation are both enabled (grayed out choice).
I’m not getting the syntax. I do have the linker script rewritten to be able to relocate the heap4c area to extended memory. I’ve overwritten the new and free operators to do a pvPortMalloc, etc.

If I have an instance of a task (PACKET packet) created without a pointer, then the task is created in processor memory. If I create the task (LED* red_led) with a pointer, it is placed in extended memory.

The PACKET creation (multiple queues can be needed) is:

class PACKET: public TaskClassS<PACKET_TASK_SIZE>
//class PACKET: public TaskClassS<PACKET_TASK_SIZE>, TaskS<PACKET_TASK_SIZE>
{

	public:
		#ifdef _NRF
			Queue< union SYSTEM_PACKET_type,_MAX_RECEIVED_PACKETS>		NRF_queue;
		#endif
		Queue< union SYSTEM_PACKET_type,_MAX_RECEIVED_PACKETS>		receive_queue;
		Semaphore													reply_slot_semaphore;

		#ifdef _WIFI_PACKET
			Queue< union SYSTEM_PACKET_type,_MAX_RECEIVED_PACKETS>		WIFI_queue;
		#endif

		#ifdef _I2C_PACKET
			Queue< union SYSTEM_PACKET_type,_MAX_RECEIVED_PACKETS>		I2C_queue;
		#endif

		#ifdef _SERIAL_PACKET
			Queue< union SYSTEM_PACKET_type,_MAX_RECEIVED_PACKETS>		SERIAL_queue;
		#endif


		// constructor code with task name and priority
		PACKET():TaskClassS("PACKET TASK", TaskPrio_Mid),
				receive_queue("packet receive_queue"),
				#ifdef _NRF
					NRF_queue("NRF receive_queue"),
				#endif
				reply_slot_semaphore("reply_slot_semaphore")
		{
			reply_slot_semaphore.give();
		};
		~PACKET();
and for the LED

class LED: public TaskClassS<LED_STACK_SIZE>
{
public:

// generic constructor
LED(char* name):TaskClassS(name, TaskPrio_HMI) {};
// destructor
~LED();

where the creation of the SYSTEM_LED class is

lass SYSTEM_LED: public LED
{
public:
		// generic constructor
		SYSTEM_LED(char* pname):LED(pname) {};
		// destructor
		~SYSTEM_LED();


and the SYSTEM_LED is created by

			RED_STATUS = new SYSTEM_LED((char*) "RED LED");

and for the record, the assignment of extended memory is:

/* USER CODE BEGIN PV */

volatile unsigned long ulHighFrequencyTimerTicks;
uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".freertos_data")));

/* USER CODE END PV */


which is the syntax for STMicro CubeMXIDE

So I've got a good bit of it figured out.  However, I still would like to see an example of the syntax in putting the stack size in, if it's different from what I've done.

Thanks

Invoking TaskClassS with the template parameter PACKET_TASK_SIZE sets the stack size and makes the task created statically.

If, when you create the object for the task, with a statement something like:

PACKET packet_task __attribute__((section (“.freertos_data”))); 

it will put that object into the .freertos_data segment, just like your Heap.

If you want to create the task dynamically (like with new) then you need to make a version of new to force it to allocate from your high speed memory, but I don’t really suggest that method, tasks with special requirements like that really want to be allocated statically.

Hi, do you have (simple) open source working examples for your FreeRTOSCpp project?

I can’t see whether it’s valid to create objects directly from TaskS class, or instead I need to instantiate from TaskClassS.

EDIT: I cannot instantiate from TaskClassS. I need to inherit from it and implement the method task(). Anyway it would be nice to see working examples.

Thank you!

Most of my use of the wrappers in proprietary code, so I can’t share it.

TaskClassS is an abstract class, as it doesn’t define the task() function, that needs to be supplied by the class that defines that task that derives from it.

If you want to make a task from a free function, you use TaskS (or Task if to be dynamically created) and pass it the pointer to the function that you want to be your task function to the object constructor, this makes a task that is basically just like created with xTaskCreate().

This does allow you to make the task with a global object and have the task be created without an explicit creation call, it will be built at global constructor time (and thus you don’t need to add code to main() to create it).

I don’t use this option much as I tend to define all my tasks as parts of classes.

1 Like

Got it!

I hadn’t seen the virtual pure method task() in TaskClassS. Now it makes sense. Thank you!

I’m sorry if I’m bothering you with this kind of questions.

Which way are you using to avoid this error in your FreeRTOSCPP project?

“error: there are no arguments to ‘getTaskHandle’ that depend on a template parameter, so a declaration of ‘getTaskHandle’ must be available [-fpermissive]”

Do you use the this pointer as in

this->getTaskHandle();

or you instead allow the permissive code?

I’m used to use member variables through the this pointer, but it gets weird for regular function members.

About the fpermissive flag, G++ warns:

note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)

This is the code I’m testing:

template<uint32_t _stackDepth>
class Led : public TaskClassS<_stackDepth>
{
public:
   Led( uint8_t _pin, const char* _name, TaskPriority _priority, unsigned portSHORT _stack = 0 ) 
      : TaskClassS<_stackDepth>( _name, _priority )
      , pin{_pin}
   {

   }

   virtual void task() override
   {
      auto handle = getTaskHandle();  // Doesn't compile (-fpermissive is required but depecated)

      handle = this->getTaskHandle(); // Does compile
   }
   
private:
   uint8_t pin;
};

Thank you in advance!

I haven’t had a need to get the task handle in what I’ve done. I simply declare void task(); in the class body, and then void MYCLASS::task() gets the task. For methods within the task, simply suspend(); and resume(); access the class directly.

Why (and I’m curious) did you want to overide the task in this case? I’ve got some odd structures in my code, but didn’t need that.

If you’re doing what I did: The SYSTEM_LED variable allows system access to the LED class, and the LED class has a task that blinks the LED as needed (and is not intended to be accessed by system level code). The SYSTEM_LED class can be either packet driven or directly accessed, but that’s the way my code is intended to work.

Hi Madyn,

According to Richard-Damon there are two ways of creating tasks in his framework:

IMHO it makes no sense to mess with classes if what I need is a free task function (as per the second case mentioned). In such case it’s far better to use the C raw API.
It’s more appealing to use classes if I need to use an C++ API wrapper.

Going back to the code I’ve shown, it is a stripped one. You can see that the override method task() doesn’t do anything useful, and for now that’s ok. I just picked the method getTaskHandle() up for spotting out the error, but any other method from the very base class will emmit the same error.

I’d found two solutions, and in between I’ve found a third way (here, look for Suryaa answer, the one before last). All three are nasty and I wanted to ask Richard-Damon its opinion.

But I could ask you too the same question, because you’re actually using the framework. Could you, in your code, call the method getTaskHandle()even if you don’t need it?

Thank you!

As to the usage of getTaskHandle(), this function is only needed if you are going to do something outside the wrappers, and need the handle for a task, so tends to have a task object explicitly referenced either via something like thetask.getTaskHandle(), or this->getTaskHandle().

Inside templates, you often need to explicitly use this-> to get to members. Making your Led class also a template on stack size is what is causing the issue. I would normally have made you Led class a non-tempate class, and derived from TaskClassS specifying the stack size you want. The problem here is it can be sure which TaskClassS template might be used, or even if it has seen the needed one.

I haven’t needed to do what Xavier has done.
The idea is that the SYSTEM_LED class creation takes a parameter (name), which is then passed down to the LED task, which is a TaskClassS template, which is the one that has to own the task. The idea of the LED class is that it’s task looks at a mask (supplied) which is shifted through periodically. The state of the mask bit (1/0) turns on or off the LED. This allows various blink patterns or all on, or all off.

In this case, the create routine is supplied by the CubeMXIDE with the appropriate port and pin number, i.e

bool LED::create (enum LED_INTERFACE_TYPE interface, void* hvoid, uint16_t ppin, bool high_on, uint8_t Which_led, enum LED_type type, char* name )
{
//	uint32_t				result;


	// semaphore protects LED at this level, needed for all LEDS
	this->high_on = high_on;
	this->interface = interface;
	blink_mask = 0;					// led off
	this->I2C_address = 0;
	this->node_address = 0;
	this->heart_beat = false;
	this->mode = 0;
	this->type_led = type;
//	strcpy(this->)
	this->which_led = Which_led;

	switch (interface)
	{
		case FPGA_LED:
		{
			break;
		}

		case GPIO_LED:
		{
			// for GPIO pin, hvoid points to GPIO structure, ppin is number of pin on interface
			// control with PIN routines
			port = (GPIO_TypeDef*) hvoid;
			pin = ppin;
			I2C_address = 0;
			break;
		}
		default:
		{
			return false;
		}
	}
	return true;
}


Which does require standardized pin definitions in CubeIDE, and a variable to determine if a low turns on the LED or OFF.

The standard accessor methods, for this class, RUN and HALT, simply call the suspend() and resume() routines within the class.

So I haven’t needed to do what you’re trying to do.

Before I start, please note that I have not looked at the code and am unfamiliar with the framework in question, however I do have some experience with FreeRTOS and with writing C++ task classes that wrap tasks on another RTOS (INTEGRITY-178B).

I suspect that having the TCB and task stack in external memory may be a problem (I’ve not tried it in this case). If you’re not using statically allocated TCBs and stacks, it may be better to leave the system heap in internal (fast) memory, and instead create a secondary heap in external memory, and override the “new” and “delete” operators to use the secondary heap. This requires that you implement a different allocator, however if your classes (and application) are fairly regular in how they allocate and release memory, you may be able to write a simplified allocator (for example, no adjacent fragment coalescence if the objects created and destroyed are of fixed sizes). On one embedded project, there is a different heap for variable sized stuff (string storage, etc.) vs. fixed size (constructed class objects), and a third for objects that are created and persist (are not destroyed). Each class overrides “new” and “delete” as required. This technique is used to ensure deterministic behavior and avoid any chance of allocation failures due to heap fragmentation.

Thanks:
The memory problem I have is that the processor (only one available!) has insufficient RAM. Adding external memory is QSPI, which by definition is slower. However, that external memory allows dedicating 320K to the FreeRTOS heap (of which about 120K or so is used).

Slower tasks are fine in the extended memory, the display update task must run in RAM otherwise you can go out and get a cup of coffee while the display updates.

All of my programming is in C++ (as much as possible) and the use of the C++ wrappers works well. I can live with one task per class, since any other task needed was already coded as an external object to the class.

Right now, some classes are created with new (overlaid operator to use pvPortMalloc), and some are created by direct reference (no pointer). Slower classes end up in extended memory since the heap4C has been repositioned to extended memory. Direct reference classes bypass the new operator (not used) and end up in processor RAM.

My use of FreeRTOS features is fairly primitive, tasks are created but not destroyed. Memory is allocated but not necessarily freed, pointers are used for large arrays and buffers where possible. Slow tasks are in extended memory, fast tasks are not. Large amounts of memory (new…) are used for graphics objects. I use queues and semaphores, and nothing more elaborate than that. Interrupts are used in the system, ST HAL routines are generally wrapped in a semaphore.

I don’t think that heap5C does anything but multi region, but does not allow allocation to a specific region. That may be a useful addition.

I think I’m going to use dynamic allocation simply because I don’t see where I need static IF I can get the tasks to live where they need to.

I only have “new” and “free” overridden in one particular place, but that seems to work.

So it’s looking like dynamic memory allocation may work well, splitting things up with the use of new, or a plain instantiation, depending. Block coalescing is not really needed, though, since no memory is really freed.

I do have a separate heap manager that points to extended memory, but that is not running at the this time. Memory coalescing is automatic for adjacent segments.

Thanks

I will point out that just using new/malloc as your allocation mechanism gives you no way to control what gets allocated where, as new/malloc only allocate from one given heap.

To control which memory you are using you need something beyond that. I think the simplest is to statically create at least one of the allocation areas and use segment control to place them in the needed memory area. Personally, I statically allocate almost ALL my tasks (and other structures like queues, semaphores, etc, normally as part of the class that controls that structure).

That works! The idea of a user templetized class was to cleaner create objects without declaring defines elsewhere, but that way dirty the sintax and doesn’t contribute much.

In such case I would prefer the defines instead of using the this pointer with function members, or using the C++ scope operator :: to skip the error.

Thank you!

Have you thought about using a user memory pool? If you’re creating objects of the same size, it would give you control of object creation/deletion, and you allocate it just once wherever you need.