Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Imagine that there is a resource, such as writing a file, or managing modem communication over UART. Typically with an RTOS, one might be opted to do this:

#include "FreeRTOS.h"
#include "semphr.h"

static SemaphoreHandle_t mutex_for_file_write;

void task_one(void *p) {
  while(1) {
    if(xSemaphoreTake(mutex_for_file_write, portMAX_DELAY)) {
      write_file();
      xSemaphoreGive(mutex_for_file_write);
    }
  }
}

void task_two(void *p) {
  while(1) {
    if(xSemaphoreTake(mutex_for_file_write, portMAX_DELAY)) {
      write_file();
      xSemaphoreGive(mutex_for_file_write);
    }
  }
}

With Safety certified OS (or RTOS), the mutex primitive is omitted. The safety aspects recommend that there should be no mutexes in a system, hence the safety rated FreeRTOS variant (SafeRTOS) does not have any mutex APIs.

The code pattern would therefore change to a single task that writes files and therefore there is no contention for the file write.

#include "FreeRTOS.h"
//#include "semphr.h"

//static SemaphoreHandle_t mutex_for_file_write;

typedef struct {
  void *data_to_write;
  size_t data_to_write_size;
  char *filename_to_write;
} file_write_request_s;

static QueueHandle_t file_write_request_queue;

void file_writer_task(void *p) {
  while(1) {
    file_write_request_s write_request = { NULL };
    if(xQueueReceive(file_write_request_queue, &write_request, portMAX_DELAY)) {
      write_file();
    }
  }
}

void send_write_request(void) {
  const char data_to_write[] = "hello";
    
  file_write_request_s write_request = { NULL };
  write_request.data_to_write = data_to_write;
  write_request.data_to_write_size = strlen(data_to_write);
  write_request.filename_to_write = "file.txt";
    
  xQueueSend(file_write_request_queue, &write_request, portMAX_DELAY);
}

void tasks_that_request_files_to_be_written(void *p) {
  while(1) {
    send_write_request();
    vTaskDelay(5000);
  }
}

Because there is a dedicated (the one and only) task that actually writes files, there is resource contention and therefore there is no need for mutual exclusion and hence a mutex primitive.

The one problem with the code above is that the file_writer_task() should be assured that the pointers associated with file_write_request_s do not go out scope until the file is written. In the example above, the const char data_to_write[] (despite that it is a const) is going be memory that resides in the stack, and it will actually go out of scope after the call to xQueueSend() has been made.

To address this situation, we actually need to wait until the file write request has been fully completed before we can move in. Therefore, we can tweak the logic to add a notification mechanism.

#include "FreeRTOS.h"
#include "semphr.h"

typedef struct {
  void *data_to_write;
  size_t data_to_write_size;
  char *filename_to_write;
  
  SemaphoreHandle_t request_complete_notification; //** new change
} file_write_request_s;

static QueueHandle_t file_write_request_queue;

void file_writer_task(void *p) {
  while(1) {
    file_write_request_s write_request = { NULL };
    if(xQueueReceive(file_write_request_queue, &write_request, portMAX_DELAY)) {
      write_file();
      xSemaphoreGive(write_request.request_complete_notification); //** new change
    }
  }
}

void send_write_request(file_write_request_s *request) {
  const char data_to_write[] = "hello";
    
  request->data_to_write = data_to_write;
  request->data_to_write_size = strlen(data_to_write);
  request->filename_to_write = "file.txt";
    
  xQueueSend(file_write_request_queue, request, portMAX_DELAY);
}

void tasks_that_request_files_to_be_written(void *p) {
  SemaphoreHandle_t request_complete_notification = xSemaphoreCreateBinary();
  file_write_request_s write_request = {
    .request_complete_notification = request_complete_notification
  }

  while(1) {
    send_write_request(&request_complete_notification);
    xSemaphoreTake(write_request.request_complete_notification); //** new change
    vTaskDelay(5000);
  }
}

  • No labels