Embedded System Tutorial FreeRTOS

From Embedded Systems Learning Academy
Revision as of 19:28, 11 February 2014 by Preet (talk | contribs) (FreeRTOS "Hello World" Task)

Jump to: navigation, search

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

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:

void hello_world_task(void* p)
{
    while(1) {
        puts("Hello World!");
        vTaskDelay(1000);
    }
}

int main()
{
    xTaskCreate(hello_world_task, (signed char*)"task_name", STACK_BYTES(2048), 0, 1, 0);
    vTaskStartScheduler();

    return -1;
}


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

class orient_compute : public scheduler_task
{
    public:
        orient_compute(uint8_t priority) : scheduler_task("compute", 512, priority)
        {
            xQueueHandle my_queue = xQueueCreate(1, sizeof(int));
            addSharedObject("queue_id", my_queue);
        }

        bool run(void *p)
        {
            /* Compute orientation here, and send it to the queue once a second */
            int orientation = 0;
            xQueueSend(getSharedObject("queue_id"), &orientation, 999999);
            vTaskDelay(1000);
            return true;
        }
};

class orient_process : public scheduler_task
{
    public:
        orient_process (uint8_t priority) : scheduler_task("process", 512, priority)
        {
            /* Nothing to init */
        }

        bool run(void *p)
        {
            /* Compute orientation here, and send it to the queue once a second */
            int orientation = 0;
            if (xQueueReceive(getSharedObject("queue_id"), &orientation, 999999))
            {
            }
            return true;
        }
};


Add the task in main()

int main()
{
    scheduler_add_task(new orient_compute(PRIORITY_LOW));
    scheduler_add_task(new orient_process(PRIORITY_LOW));
    scheduler_start();
    return 0;
}


Assignment

This assignment is based on SJ-One board, but you can alter the requirement to fit your own hardware.

  1. Create a task (task1) that computes the orientation of the board.
    Send the orientation enumeration, such as "up", "down", "left", "right" to a queue
  2. 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)
  3. 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.
  4. Create a terminal task with a command "orientation on" and "orientation off"
    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.
// At the terminal tasks taskEntry() function :
bool terminalTask::taskEntry()
{
    // Add the command, but pass the "this" pointer when the command is invoked
    cp.addHandler(orientationCmd,  "orientation", "Two options: 'orientation on' or 'orientation off'", this);
}

// Somewhere else:
CMD_HANDLER_FUNC(orientationCmd)
{
    // Our parameter was the terminal task's "this" pointer:
    scheduler_task *terminalTask = (scheduler_task*) pDataParam;

    // Use this to get the pointer of the "other task"
    scheduler_task *orientTask = terminalTask->getTaskPtrByName("orientTask");

    // We've got the handle now, so use FreeRTOS API to suspend or resume
    if (cmdParams == "on") {
        vTaskResume(orientTask->getTaskHandle());
    }
    else {
        vTaskSuspend(orientTask->getTaskHandle());
    }
}