Memory model: How to synchronize acces?

yanosz
Posts: 12
Joined: Sun Jun 10, 2018 12:37 pm

Memory model: How to synchronize acces?

Postby yanosz » Tue Jun 12, 2018 9:33 am

Hello folks,

I'm somewhat puzzled about freerots' memory model - I wasn't able to finde a suitable reference, yet.

To illustrate my confusion, I modified the example blink app, to read data from the heap:

Code: Select all

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#define BLINK_GPIO CONFIG_BLINK_GPIO

static int freq = 1000;

void blink_task(void *pvParameter)
{
	gpio_pad_select_gpio(BLINK_GPIO);
	gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
	while(1) {
		gpio_set_level(BLINK_GPIO, 0);
		vTaskDelay(freq / portTICK_PERIOD_MS);
		gpio_set_level(BLINK_GPIO, 1);
		vTaskDelay(freq / portTICK_PERIOD_MS);
	}
}

void app_main()
{
    xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
    while(1) {
      vTaskDelay(5000 / portTICK_PERIOD_MS);
      freq = 500;
      vTaskDelay(5000 / portTICK_PERIOD_MS);
      freq = 1000;
    }
}
This seems to work - but: In order to change freq from the main task, the blink_task has to read the value from the heap every time it calls vTaskDelay. There must be no cache (i.e. CPU register) still having an old value.

I'm not sure, if it this worked by coincidence (i.e. both task are running on the same core) or if the memory model of FreeRTOS guarantees this.

I.e. when programming Java, the "volatile" keyword instructs the JVM not cache a variable. Is there something like volatile in FreeRTOS? Do you know a nice reference on the FreeRTOS memory model?

Thanks in advance,
yanosz

User avatar
kolban
Posts: 1683
Joined: Mon Nov 16, 2015 4:43 pm
Location: Texas, USA

Re: Memory model: How to synchronize acces?

Postby kolban » Tue Jun 12, 2018 3:11 pm

Howdy and welcome to the forum.

With reference to your program example, the variable called freq is actually not on the heap. Only dynamically allocated storage is placed on the heap (primarily storage allocated by malloc ... but not exclusively). When you declared:

static int freq = 1000;

you allocated enough storage to hold an "int" (32bits if I remember) and gave it an initial value of 1000. This is allocated in what is called the ".data" section of the application. Loosely, think of an application that you compile as having compiled executable code (.text), initialized global data (.data) and un-initialized global data (.bss). When the ESP32 loads your application, it copies (from flash) your .data and your .bss sections from flash into RAM. Then, whatever else remains (again loosely) is used as heap.

When your code runs, the variable called "freq" already has the storage reserved and populated. In your multiple tasks, when you refer to "freq" in all cases, it is referring to the same area of storage in RAM. Heap is not involved and caching is not involved either (we should assume that RAM is directly accessible as it is internal RAM).
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32

ESP_igrr
Posts: 1656
Joined: Tue Dec 01, 2015 8:37 am

Re: Memory model: How to synchronize acces?

Postby ESP_igrr » Tue Jun 12, 2018 3:28 pm

Note that this is not FreeRTOS specific, any multithreaded C program will work the same way.
C does have a "volatile" keyword which should be used in this case. Without it, compiler can safely assume that once the blink task grabs the value of freq, nothing else can change it. Hence a copy of it will be stored in a register, instead of reloading it from RAM every time. Adding 'volatile' is an indicator that variable can change at any time and compiler should not optimize away the loads.

User avatar
fly135
Posts: 606
Joined: Wed Jan 03, 2018 8:33 pm
Location: Orlando, FL

Re: Memory model: How to synchronize acces?

Postby fly135 » Tue Jun 12, 2018 3:29 pm

I see what you are asking in your example, and not sure how optimization will handle it. Might be something I should consider working in a multithreaded environment as well. You can always make your declaration as follows...

Code: Select all

static volatile int freq = 1000;
I think this is a worthy discussion. Perhaps some others have a more definitive take on this issue. The other option would be to put all variable loads across multiple threads in function call.

John A

Who is online

Users browsing this forum: No registered users and 34 guests