Difference between revisions of "Embedded System Tutorial FreeRTOS"
From Embedded Systems Learning Academy
(→C++ based FreeRTOS task) |
|||
(17 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
+ | Socialledge is moving to two portals. | ||
+ | * The Wiki will remain here for general references about the SJ-One board, and to document student reports. | ||
+ | * The bookstack will now be used for SJSU assignments | ||
+ | |||
+ | [http://books.socialledge.com/books/embedded-drivers-real-time-operating-systems/page/freertos-tasks This article has been moved here] | ||
+ | |||
+ | <!-- | ||
+ | |||
The objective of this assignment is to show you how to create a FreeRTOS task a few different ways. The [[FreeRTOS Tutorial]] is definitely a must read before going through this lesson. | The objective of this assignment is to show you how to create a FreeRTOS task a few different ways. The [[FreeRTOS Tutorial]] is definitely a must read before going through this lesson. | ||
== FreeRTOS "Hello World" Task == | == FreeRTOS "Hello World" Task == | ||
− | A task just needs memory for its stack and | + | A task just needs memory for its stack and an infinite loop. To prevent "hogging" the CPU, you should use a delay such that the CPU can be allocated to other tasks. Here is the simplest FreeRTOS task: |
− | <syntaxhighlight lang=" | + | <syntaxhighlight lang="cpp"> |
void hello_world_task(void* p) | void hello_world_task(void* p) | ||
{ | { | ||
Line 23: | Line 31: | ||
<BR/> | <BR/> | ||
+ | |||
== C++ based FreeRTOS task == | == C++ based FreeRTOS task == | ||
As a project gets more complex, it becomes difficult to manage initialization and share queue or semaphore handles. This was the motivation to create a C++ based FreeRTOS task. | As a project gets more complex, it becomes difficult to manage initialization and share queue or semaphore handles. This was the motivation to create a C++ based FreeRTOS task. | ||
+ | |||
+ | === Share "Objects" === | ||
+ | A task can "share" its pointers, handles, or "objects" with another task by name. This way, we don't have to worry about declaring handles into a common header file, hence we do not plague the global namespace :) See the next examples on how a task can share a handle with another task by an intuitive string name. | ||
=== C++ Task === | === C++ Task === | ||
− | + | <syntaxhighlight lang="cpp"> | |
+ | |||
+ | /// IDs used for getSharedObject() and addSharedObject() | ||
+ | typedef enum { | ||
+ | shared_SensorQueueId, | ||
+ | } sharedHandleId_t; | ||
+ | |||
+ | /// Orientation type enumeration | ||
+ | typedef enum { | ||
+ | invalid, | ||
+ | left, | ||
+ | right, | ||
+ | } orientation_t; | ||
+ | |||
+ | class orient_compute : public scheduler_task | ||
+ | { | ||
+ | public: | ||
+ | orient_compute(uint8_t priority) : scheduler_task("compute", 2048, priority) | ||
+ | { | ||
+ | /* We save the queue handle by using addSharedObject() */ | ||
+ | QueueHandle_t my_queue = xQueueCreate(1, sizeof(orientation_t)); | ||
+ | addSharedObject(shared_SensorQueueId, my_queue); | ||
+ | } | ||
+ | |||
+ | bool run(void *p) | ||
+ | { | ||
+ | /* Compute orientation here, and send it to the queue once a second */ | ||
+ | orientation_t orientation = invalid; | ||
+ | xQueueSend(getSharedObject(shared_SensorQueueId), &orientation, portMAX_DELAY); | ||
+ | |||
+ | vTaskDelay(1000); | ||
+ | return true; | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | class orient_process : public scheduler_task | ||
+ | { | ||
+ | public: | ||
+ | orient_process (uint8_t priority) : scheduler_task("process", 2048, priority) | ||
+ | { | ||
+ | /* Nothing to init */ | ||
+ | } | ||
+ | |||
+ | bool run(void *p) | ||
+ | { | ||
+ | /* We first get the queue handle the other task added using addSharedObject() */ | ||
+ | orientation_t orientation = invalid; | ||
+ | QueueHandle_t qid = getSharedObject(shared_SensorQueueId); | ||
+ | |||
+ | /* Sleep the task forever until an item is available in the queue */ | ||
+ | if (xQueueReceive(qid, &orientation, portMAX_DELAY)) | ||
+ | { | ||
+ | } | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | }; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Note that a better design is to minimize the use of <b><code>getSharedObject()</code></b>. So it is recommended that the creator of the handle add the shared object in its <b><code>init()</code></b>, and other tasks can store the handle in their <b><code>taskEntry()</code></b> function. | ||
+ | <BR/> | ||
=== Add the task in main() === | === Add the task in main() === | ||
− | + | <syntaxhighlight lang="c"> | |
− | + | int main() | |
− | + | { | |
− | + | scheduler_add_task(new orient_compute(PRIORITY_LOW)); | |
+ | scheduler_add_task(new orient_process(PRIORITY_LOW)); | ||
+ | scheduler_start(); | ||
+ | return 0; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | <BR/> | ||
== Assignment == | == Assignment == | ||
This assignment is based on SJ-One board, but you can alter the requirement to fit your own hardware. | This assignment is based on SJ-One board, but you can alter the requirement to fit your own hardware. | ||
# Create a task (task1) that computes the orientation of the board. | # Create a task (task1) that computes the orientation of the board. | ||
− | #: Send the orientation enumeration, such as "up", "down", "left", "right" to a queue | + | #: You can use the acceleration sensor to figure out the orientation of the board |
+ | #: Send the orientation enumeration, such as "up", "down", "left", "right" to a queue every 1 second | ||
# Create another task (task2) that waits on the queued item | # Create another task (task2) that waits on the queued item | ||
#: If the orientation is left or right, light up the LEDs (otherwise turn them off) | #: If the orientation is left or right, light up the LEDs (otherwise turn them off) | ||
− | # Create a terminal | + | # Note down the observations by doing the following: |
+ | #: Print a message before and after sending the orientation to the queue | ||
+ | #: Print a message after the second task receives an item from the queue | ||
+ | #: Use the same priority for both tasks, and note down the order of the print-outs | ||
+ | #: Use higher priority for the receiving task, and note down the order of the print-outs. | ||
+ | # Create a terminal command: "orientation on" and "orientation off" | ||
#: If orientation is commanded on, resume the task1, otherwise suspend it | #: If orientation is commanded on, resume the task1, otherwise suspend it | ||
#: See code below on hints of how this command can get control of another task. | #: See code below on hints of how this command can get control of another task. | ||
+ | # Answer the following questions: | ||
+ | #: What if you use ZERO block time while sending an item to the queue, will that make any difference? | ||
+ | #: What is the purpose of the block time during xQueueReceive() ? | ||
<syntaxhighlight lang="c"> | <syntaxhighlight lang="c"> | ||
Line 49: | Line 136: | ||
bool terminalTask::taskEntry() | bool terminalTask::taskEntry() | ||
{ | { | ||
− | + | cp.addHandler(orientationCmd, "orientation", "Two options: 'orientation on' or 'orientation off'"); | |
− | cp.addHandler(orientationCmd, "orientation", "Two options: 'orientation on' or 'orientation off'" | ||
} | } | ||
Line 56: | Line 142: | ||
CMD_HANDLER_FUNC(orientationCmd) | CMD_HANDLER_FUNC(orientationCmd) | ||
{ | { | ||
− | // Our parameter was the | + | // Our parameter was the orientation tasks' pointer, but you may want to check for NULL pointer first. |
− | + | scheduler_task *compute = scheduler_task::getTaskPtrByName("compute"); | |
− | |||
− | |||
− | scheduler_task * | ||
− | // | + | // You can use FreeRTOS API or the wrapper resume() or suspend() methods |
if (cmdParams == "on") { | if (cmdParams == "on") { | ||
− | vTaskResume( | + | vTaskResume(compute->getTaskHandle()); // Can also use: compute->resume(); |
} | } | ||
else { | else { | ||
− | vTaskSuspend( | + | vTaskSuspend(compute->getTaskHandle()); // Can also use: compute->suspend(); |
} | } | ||
+ | |||
+ | return true; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | --> |
Latest revision as of 20:11, 25 January 2019
Socialledge is moving to two portals.
- The Wiki will remain here for general references about the SJ-One board, and to document student reports.
- The bookstack will now be used for SJSU assignments
This article has been moved here