Global variable and freetos

Hello everyone,
I am new to freetos development. By the way, I have in my program several cyclic tasks that run and that all use the same global variables. Now I would like to create in addition another task independent of the others, that is, a task which uses its own global variables: A task which could not have the global variables of the other tasks and the other tasks could not have access to its own .
I would like to know at the level of the memory how it is organized?
Thanks in advance

Hey @Aline,

I have couple of questions here:
What do you mean by cyclic tasks here? Do you mean periodic tasks that run at a specific interval?
Is the shared global variables accessed in critical sections?
It would be great if you could elaborate more on what you are trying to achieve here.

Global variables can be accessed across the application, unless they are static global variables which have there linkage limited to the files (translation units) in which they are defined. They are not scoped/linked to any particular tasks.

Thank your for your replay /

I have couple of questions here:
What do you mean by cyclic tasks here? Do you mean periodic tasks that run at a specific interval?
Oui je veux dire les fonctions crées par
response = xTask_A_CreateRestricted(XX, XX);
Basically what I want to do is:

////////////////////////////////////////////////
//Variable Globale

int  BEDPosition;// Variable for Task A
Int TTLPosition;//Variable for Task B


static const Task_A_Seeting_t repetifTask_A_Seeting = {
	  repetifTask_A,
	  repetifTask_A_Name,
      K_repetifTask_A_StackSize,
      NULL,
      K_repetifTask_A_Priority,
      NULL,
      // Regions
      {
        { (UINT32) &_RAM_soft_Start_Address__,
          (UINT32) &_RAM_soft_End_Address__,
          portMPU_REGION_R_EXECUTE
        },
        { 0,
          0,
          0
        },
        { (UINT32) &_ROM_ConfigurationStartAdr__,
          (UINT32) &_ROM_ConfigurationEndAdr__,
          portMPU_REGION_READ_WRITE
        },
      }
};

________________________________
//Création de l task A
response = xTask_A_CreateRestricted(&repetifTask_A_Seeting, &repetifTask_A_Hdl);
//Création de la task B
response = xTask_B_CreateRestricted(&repetifTask_B_Seeting, &repetifTask_B_Hdl);
______________________

Now I want task A to be unable to access the global variable TTLPosition only access BEDPosition and task B also to be unable to access the global variable BEDPosition only TTLPosition.
It’s for cyber reasons I want to create an independent task that could not communicate with other tasks, but since it shares the variables with the others, I wanted to protect the variables or do such so that the others cannot see his global variables and he could not see those of others

thank you in advance for your help

I’m assuming the target device you are using supports MPU as the target was not specified in the question.

If that’s the case you can specify the memory regions (start address [pvBaseAddress] and length [ulLengthInBytes]) of any non-stack variables (TTLPosition and BEDPosition in your example) you need restricted access in the xRegions field of each task’s with privilege levels (ulParameters) as per each task’s requirement.

You can refer to the MPU demos (example - CORTEX_MPU_STM32L4_Discovery_GCC_IAR_Keil) in the FreeRTOS/FreeRTOS/Demo folder for more information and detailed examples.

More details: FreeRTOS-MPU

1 Like

Thank you tony-josi-aws for your answer, I understand better, but I have another question.
So by saying that I can restrict memory access for each task, now I want to know where the global variables (beginning address and end address) are stored in the memory so I could divide this area into several areas with the xTaskCreateRestricted() function.
Any idea where they might be stored in memory?
The cyber used is the Renesas RX66 microcontroller?

thanks again
Cordially,

You will need to use compiler specific attributes on the variables to force them into specific blocks of memory, and setup the linker to place those at appropriate addresses.

For gcc, it is typically something like adding an

__attribute__((section(“sectname”)))

Which will place the variable that attribute is attached to into linker section “sectname”, which you will need to define in the linker scripts to be a MPU page aligned block of memory.

1 Like

OK,
Thank you richard-damon

The only other thing that I want to add here is that you need to ensure that every memory region that you are granting a task access to satisfies hardware requirements such as size and alignment. For example, Cortex-M33 requires that minimum MPU region size is 32 bytes and every region is 32 bytes aligned. As a result, you cannot grant access to only one integer on a Cortex-M33. See this example how we allocate 32 bytes even though we use only one so that we control access to this region.

1 Like

Hello, I allow myself to come back to you, because after having understood and created the task with its isolated global variables, I would also like to know if technically with freetos it is possible to create a queue for task A and another queue for task B and do so that task A cannot write to or read from queue A and task B either cannot write to or read from queue A.

That is to say if Task A wants to communicate with Task B, it has to go through a function that I am going to create otherwise it could not.
here is my idea,

Thanks in advance

You can put the handle for the queues a file-local scope so only the functions in the file with the select functions you want to be able to do the communication can access the queue.

This can NOT be done by the MPU, as the function, as far as the MPU is concerned, is part of the task, so can’t see the difference between them. This is true unless you implement the function like FreeRTOS implements the actual Queue code with a security gate trampoline between an unprotected call into a privileged function from restricted addresses.

1 Like

Hello everyone here is the code I developed to isolate tasks
Here is my code :
In my link editor configuration file (.icf)
Step 1 :
I defined my memory areas c :

//Sal1 memory
define exported symbol __RAM_Sal2_Start_Address__ = 0x0003FFF0;
define exported symbol __RAM_Sal2_End_Address__ = 0x0003FFFB;
//Sal2
define exported symbol __RAM_Sal1_Start_Address__ = 0x0003FFFC;
define exported symbol __RAM_Sal1_End_Address__ = 0x0003FFFF;

Step 2
I added in my linker configuration file (.icf) the following lines to place all data in the memory address range specified in the :MY_DATASal1 and :MY_DATASal2 sections

//Place in :MY_DATASal1
define region DATA_region = mem:[from __RAM_Sal1_Start_Address__ to __RAM_Sal1_End_Address__ ];
place in DATA_region { readwrite section MY_DATASal1 };
//Place in :MY_DATASal2
define region DATA_region = mem:[from __RAM_Sal2_Start_Address__ to __RAM_Sal2_End_Address__ ];
place in DATA_region { readwrite section MY_DATASal2 };

Step 3
- In my Tasksal1.c file, I added

#pragma default_variable_attributes = @ "MY_DATASAL1
int Data_Sal1;
#pragma default_variable_attributes =

- In my Tasksal2.c file

#pragma default_variable_attributes = @ "MY_DATASal1"
 int data1Sal2;
 int data2Sal2;
#pragma default_variable_attributes =

Step 4 :
In my tasksal2.c I created a task :

static const TaskParameters_t TaskSal2Parameters = {
                                                      (TaskFunction_t) TaskSal2,
                                                      TaskSal2Name,
                                                      K_TaskSal2StackSize,
                                                      NULL,
                                                      K_TaskSal2Priority,
                                                      NULL,
                                                      // xRegions - Allocate up to three separate memory regions for access by
                                                      // the task, with appropriate access permissions.  Different processors have
                                                      // different memory alignment requirements - refer to the FreeRTOS documentation
                                                      // for full information.
                                                      {
                                                        // access to the Ram code for the Task
                                                        {
                                                          (UINT32) &_RAM_Sal1_Start_Address__,
                                                          (UINT32) &_RAM_Sal1_End_Address__,
                                                          portMPU_REGION_NO_ACCESS },
                                                        // access to the FCU registers for the Task

Some observations -

  • Both the memory regions in ICF file are called DATA_region - you should give them different names.
  • You are using portMPU_REGION_NO_ACCESS - by default an unprivileged task does not have access to any memory region other than its own stack, so you do not need to explicitly define no access.

Which hardware are you using? As I mentioned in my previous response, you need to ensure that MPU regions satisfy the hardware requirements. Currently your MPU regions are too small (12 bytes and 4 bytes respectively) and most likely do not meet the hardware requirements.

Hello,
Thank you for your answer,
By hardware used Do you mean microcontroller ?:
I am using a Ranesas RX63 microcontroller.

Yes, I mean microcontroller. Please check the documentation that it allows creation of MPU regions of that size. Other than that, your solution looks good.

1 Like

Ok Gaurav aggarwal, It works, I’ll look at the documentation. Thank you very much for your precious help

I read the documatation, I made the changes it doesn’t work, I have the impression that the variables are not in the right section
I used:
#pragma default_variable_attributes = @ "MY_DATASAL1
int Data_Sal1;
but I have also seen other uses:
#pragma section = “MY_DATASAL1”
int Data_Sal1;
I tell you that I don’t understand the difference and which one to use

Try the following:

 int Data_Sal1 __attribute__( ( section( "MY_DATASAL1" ) ) );

And you can look at the map file to see which variable is going where.