It may not be a suggestion for a project that you would do yourself, but I’ll give an overview of a project that I completed earlier this year using FreeRTOS and a PIC32MX microcontroller. I guess it could be an example of a real world application of using an RTOS.
I have a garage which is a short walk away from my house, I keep a motorbike in it. I dont have mains power there, so I have a solar panel on the roof which I can use to keep the battery of the motorbike charged during the colder months when I dont ride it regularly.
Now, I could have avoided this whole project by using a different type of charger, but wheres the fun in that …
I decided to build a little “contraption” that turns a charger which is connected to the solar panel on and off on a daily basis if the motorbike battery is starting to get a little low and needs a top up. I also added some “nice to have” features like an LCD display that can show voltages and current, temperature, time, and some status icons, and a LoRaWAN module so that I could transmit some statistics back to the house and monitor the battery voltage remotely. Way over the top, but it all presented some nice challenges to build the logic, control, and sequencing using FreeRTOS features.
So some specifics:
The LCD is attached to the front panel of a case so that I can see it, and there are also some buttons. I have a task which periodically reads the status of the buttons and places them into a variable. A task that is “in control of the user interface” can read that variable to see what the buttons are doing and then decide what action it should take next (like scrolling through a menu, adjusting a setting, etc). As part of the user interface, I enable the LCD backlight when a button is pressed and use a timer to turn it off again after a short time if no buttons are pressed.
Another task is responsible for taking a buffer and updating the contents of the LCD. This can be quite a slow process, especially since I am using a 4 bit interface with it since I had little IO to spare to implement a full 8 bit interface. So a task can run in the background updating the LCD while everything else continues to function normally.
There is a temperature sensor connected to the I2C bus from the microcontroller, along with some voltage/current sensors, a real time clock, and IO expander. So I built some “infrastructure” that allows me to queue “buffer descriptors” to read/write I2C devices. A task that wants to read the temperature sensor for example can queue a buffer descriptor with the I2C task saying what address and how many bytes to read/write to or from a supplied buffer, the I2C task takes care of that and returns the data in a buffer supplied by the requesting task. Multiple tasks can therefore send in a bunch of buffer descriptors to the queue and they will all be processed in turn.
The LoRaWAN stuff operates similarly, a task that wants to send a message over LoRaWAN queues a buffer descriptor containing the message to be transmitted, and waits for the LoRaWAN task to process it and signal back that it is complete, along with any error or status information. Since its nice to see what is happening with the LoRaWAN connection, the task supplies some status bits which the user interface task reads, allowing it to insert some icons onto the LCD to show whether the LoRaWAN connection is active, and whether it is transmitting. Importantly for the I2C and LoRaWAN tasks, this decouples the requirement of interfacing with those peripherals from each individual task and places it with some central tasks that can implement all of the required logic, taking some buffers as input or output for a given request. That helps to simplify those tasks and removes a lot of duplicated code.
And finally theres a task that turns the charger on and off at certain times of the day if the voltages that have been recorded suggest that it should be turned on.
Theres more to it, but thats just a sample of some of the ways Ive used tasks/queues/timers/etc to implement some of the processing and handling of peripherals etc. Its a bit complicated and probably way over done for sure, but it was a fun project to really sink my teeth into FreeRTOS and its features, and it was all made much easier by having a scheduler underneath my code that can put my tasks to sleep and wake them up as needed. And the result is something that Im very proud of.
Heres a picture of it installed and operating.