Summary
In the previous article I talked about getting FreeRTOS running on the PSoC, then creating two threads (one for a blinking LED and one for a UART command processor). In this article I will add the ability to change which LED is blinking (the board has a tricolor RGB LED) by pressing a key on the keyboard. Specifically ‘r’ for Red, ‘b’ for Blue and ‘g’ for Green. In order for this to happen you will need to make the UART thread talk to the LED thread. I will implement this with the FreeRTOS Queue mechanism.
FreeRTOS Queue
Using an RTOS like FreeRTOS is a great tool for reducing the complexity of your programs. This is very useful when your MCU supports bigger more complicated programs. However, using multiple threads of execution also creates problems. One of the poster children for threading problems is shared memory.
FreeRTOS uses a shared memory model. Meaning, all of the threads in your program share the same address space and have access to all of the memory. This means that one possible technique for communicating between threads would be to declare a global variable, which both threads have access to.
For example, you could declare a variable called “uint32_t ledColor” and have the the LED Thread read the variable to determine which LED to blink. Then the UART thread could write the variable to set which LED is blinking. Well maybe this isn’t such a good idea. There are at least (and maybe more) things that can go wrong.
- The compiler doesn’t know that there are multiple threads. As a result, the variable may or may not always be in the RAM, it could be allocated for significant amounts of time into a register. This means that one thread might write the RAM, and the other thread might not realize that it has changed because it is living in a register (this could be solved with the volatile keyword)
- If instead of an “uint32_t” it was a “struct”, you could easily end up with a context switch while you had only partially written, or partially read the memory.
- By using a variable, you will find yourself in the position of constantly polling the variable to find out if it had changed.
A better way to solve this problem is to use a FreeRTOS queue. You can think of the queue as an array in the memory with a head and a tail. You can insert new items into the tail of the queue, and you can remove them from the head of the queue. The FreeRTOS queue makes sure that you do this “safely”, meaning you have complete transferred in or out before another thread can take over. The FreeRTOS queue also makes sure that you don’t try to insert into a queue that is full, or remove from a queue that is empty by providing a mechanism to “block” your thread until it is either full/empty.
To use a queue you first
- Create a new queue with the FreeRTOS queue function xQueueCreate(). You need to tell it how many items are in the queue and how big the items are so that it can reserve space in the FreeRTOS heap to hold the items that you put in the queue.
- Next, Task1 can insert into the queue with the FreeRTOS queue function xQueueSend. If there is room in the queue, FreeRTOS will memcpy your item into the head of the queue and then move down the tail pointer. If there is no room it will either block your thread and wait until there is room in the queue, or it will return an error.
- Task2 can then receive from the queue with the FreeRTOS queue function xQueueReceive(). If there is something in the queue, it will memcpy from the queue into memory inside of your task, then move the tail pointer. If there is nothing in the queue you can set it to either block your thread and wait, or return an error.
Modify the project
I start the implementation process by copying the UART-Thread project to a new project called “Queue” and then adding the GREEN and BLUE LEDs to my schematic.
Then I create a new type called “Color_t” which will represent the list of possible colors. This is the “item” that I will add/remove from the queue. Next I declare a global variable “QueueHandle_t” which is a data structure which FreeRTOS uses to keep track of the queue. FreeRTOS can safely read and write this variable from multiple threads even though it is global.
typedef enum Color_t { RED, GREEN, BLUE } Color_t; QueueHandle_t colorQueue;
Before you can use a queue you must initialize it. To do this call “xQueueCreate”. This function takes two arguments
- The number of elements that can be stored in the queue
- How big the elements are in the queue. You can store any “type” in the queue from a minimum of 1 word (32-bits) to something bigger, say a struct. You are only limited by the memory on your MCU.
int main(void) { CyGlobalIntEnable; /* Enable global interrupts. */ setupFreeRTOS(); colorQueue = xQueueCreate(1, sizeof(Color_t)); // 1 item queue that can hold colors
Next I will update the UART thread so that it can send a message to the queue. If the queue is full I just printout that there is an error. You could imagine that there are a number of ways that you might handle this error, but I opted for simple. You can make this error happen if you press keys faster than 1x per 500ms.
case 'r': tempColor = RED; if(xQueueSend(colorQueue,&tempColor,0) != pdTRUE) UART_UartPutString("queue error\n\r"); break; case 'b': tempColor = BLUE; if(xQueueSend(colorQueue,&tempColor,0) != pdTRUE) UART_UartPutString("queue error\n\r"); break; case 'g': tempColor = GREEN; if(xQueueSend(colorQueue,&tempColor,0) != pdTRUE) UART_UartPutString("queue error\n\r"); break;
The last thing to do is fixed the LED_Task to check for items in the queue. If there is one, then turn off all of the LEDs and start blinking the new color.
void LED_Task(void *arg) { (void)arg; Color_t currentColor = GREEN; while(1) { if(xQueueReceive(colorQueue,¤tColor,0) == pdTRUE) { RED_Write(1); BLUE_Write(1); GREEN_Write(1); } if(currentColor == RED) RED_Write(~RED_Read()); else if (currentColor == BLUE) BLUE_Write(~BLUE_Read()); else GREEN_Write(~GREEN_Read()); vTaskDelay(500); } }
If you have more FreeRTOS PSoC Examples that you are interested in please make a comment and maybe Ill create them.
As always, you can find the FreeRTOS PSoC Examples on the IoT Expert GitHub site or git@github.com:iotexpert/PSoC-FreeRTOS-Examples.git
Topic
Description
FreeRTOS: A PSoC4 FreeRTOS Port
An introduction to making FreeRTOS work on PSoC 4
FreeRTOS PSoC Examples
Using multiple tasks in FreeRTOS
FreeRTOS Queue Example
Using a queue to communicate between tasks
PSoC 6 FreeRTOS - The First Example
Booting FreeRTOS on PSoC 6
FreeRTOS Binary Semaphore
An first example of a binary semaphore
FreeRTOS Binary Semaphore (Part 2)
Removing polling in the UART Task
FreeRTOS Counting Semaphore
An example using a counting semaphore
PSoC FreeRTOS
Reading I2C Sensors with a shared I2C Bus
PSoC FreeRTOS Task Notify
A light weight scheme to replace Semaphores
PSoC FreeRTOS Task Notification Values
A very light weight method to transfer one word of information into a task
2 Comments
Thanks for great article.
It would be nice to see the article how to work with FreeRTOS “task notifications”. It’s a pretty new feature of FreeRTOS and there are no many examples dedicated to this.
You are right. I haven’t tried it yet, but will