Electronic – Queues in FreeRTOS

cfreertosrtos

I have multiple tasks that all write to a screen. Obviously without controlling who can write to the screen when I'll have problems. I thought the easiest way to do this was with queueing.

I have a global QueueHandle. In my int main(void) function I create a queue of size 10 (large enough for my needs) with an item size of that equal to my struct which holds all the data.

struct screenData {
    uint8_t string;
    uint8_t line;
} data;

In the tasks which need to write to the screen they send to the queue:

struct screenData * toSend;
data.string = "TEST";
data.line = 0;

toSend = &data;

xQueueSend ( xQueue, ( void * ) &toSend , xTicksToWait );

In the task which updates the screen it reads from the queue and puts it on the screen:

struct screenData * data;
xQueueReceive( xQueue, &( data ), xTicksToWait );

I then access the data like so: data->string; etc…

However, as far as I understand it, this passes the address of the struct. Which means if I update data, the data held in the struct will be different.

What I want to do is have a queue which I can add to where the data sent is of the type screenData, and it'll read each incoming screenData to put a message on the screen.

Essentially, should I just be sending the whole struct to the queue? In which case, is this the best use of the queue? Or is there a better way to buffer data?

Thanks

Best Answer

There two basic approaches that come to mind.

1) Use a queue as outlined by the OP.

According to the FreeRTOS API documentation for xQueueSend, all of the data from your screenData structure is copied into the queue (see description for the pvItemToQueue argument: "A pointer to the item that is to be placed on the queue. The size of the items the queue will hold was defined when the queue was created, so this many bytes will be copied from pvItemToQueue into the queue storage area." This means your assumption is incorrect. After the code execution returns from the xQueueSend call, you can modify data without fear of overwriting what was just queued up.

2) Use a mutual exclusion semaphore or mutex.

(read more about FreeRTOS mutex implementation in the API documentation of xSemaphoreCreateMutex) to synchronize access to the display between different tasks.

The main trade-offs to consider in choosing between a queue or a mutex are as follows:

Using a queue will buffer the data and not block any tasks from executing unless your queue becomes full but requires you to allocate more memory (10 * sizeof(screenData) in this case).

Using a mutex does not require the memory allocation but will block execution of tasks if more than one is trying to access the display at the same time.

Related Topic