Task
Tasks are implemented as C functions. The only thing special about them is their prototype, which must return void and take a void pointer parameter.
An application can consist of many tasks. If the processor running the application contains a single core, then only one task can be executing at any given time. This implies that a task can exist in one of two states, Running and Not Running. This simplistic model is considered first—but keep in mind that it is an over simplification. Later in the chapter it is shown that the Not Running state actually contains a number of sub-states.
When a task is in the Running state the processor is executing the task’s code. When a task is in the Not Running state, the task is dormant, its status having been saved ready for it to resume execution the next time the scheduler decides it should enter the Running state. When a task resumes execution, it does so from the instruction it was about to execute before it last left the Running state.
A CMSIS-RTOS assumes that threads are scheduled as shown in the figure Thread State and State Transitions. The thread states change as follows:
A thread is created using the function osThreadNew. This puts the thread into the READY or RUNNING state (depending on the thread priority).
CMSIS-RTOS is preemptive. The active thread with the highest priority becomes the RUNNING thread provided it does not wait for any event. The initial priority of a thread is defined with the osThreadAttr_t but may be changed during execution using the function osThreadSetPriority.
The RUNNING thread transfers into the BLOCKED state when it is delayed, waiting for an event or suspended.
Active threads can be terminated any time using the function osThreadTerminate. Threads can terminate also by just returning from the thread function. Threads that are terminated are in the INACTIVE state and typically do not consume any dynamic memory resources.
Thread states
Threads can be in the following states:
- RUNNING: The thread that is currently running is in the RUNNING state. Only one thread at a time can be in this state.
- READY: Threads which are ready to run are in the READY state. Once the RUNNING thread has terminated, or is BLOCKED, the next READY thread with the highest priority becomes the RUNNING thread.
- BLOCKED: Threads that are blocked either delayed, waiting for an event to occur or suspended are in the BLOCKED state.
- TERMINATED: When osThreadTerminate is called, threads are TERMINATED with resources not yet released (applies to joinable threads).
- INACTIVE: Threads that are not created or have been terminated with all resources released are in the INACTIVE state.
oSPriority:
- osPriorityNone = 0,
- osPriorityIdle = 1,
- osPriorityLow = 8,
- osPriorityLow1 = 8+1,
- osPriorityLow2 = 8+2,
- osPriorityLow3 = 8+3,
- ………….
- osPriorityRealtime1 = 48+1,
- osPriorityRealtime2 = 48+2,
- osPriorityRealtime3 = 48+3,
- osPriorityRealtime4 = 48+4,
- osPriorityRealtime5 = 48+5,
- osPriorityRealtime6 = 48+6,
- osPriorityRealtime7 = 48+7,
- osPriorityISR = 56,
- osPriorityError = -1,
- osPriorityReserved = 0x7FFFFFFF
- More details are available in given link.
Steps to Create FREERTOS Task’s Using Cube IDE
1) Go to Pinout & Configurations Tab > FreeRTOS > Tasks & Queues Tab > Add
2) Create Two Tasks
Task 1:
- Priority: osPriorityLow
- Stack Size: 128 Words
- Entry Function: StartTask1
- Code Generation: Default
- Parameter: NULL
- Allocation: Dynamic
Task 2:
- Priority: osPriorityLow
- Stack Size: 128 Words
- Entry Function: StartTask02
- Code Generation: Default
- Parameter: NULL
- Allocation: Dynamic
3) After initial two steps below code will be generated via cube ide
Attribute Definition:
/* USER CODE END Variables */ /* Definitions for Task1 */ osThreadId_t Task1Handle; const osThreadAttr_t Task1_attributes = { .name = "Task1", .priority = (osPriority_t) osPriorityNormal, .stack_size = 128 * 4 }; /* Definitions for Task2 */ osThreadId_t Task2Handle; const osThreadAttr_t Task2_attributes = { .name = "Task2", .priority = (osPriority_t) osPriorityNormal, .stack_size = 128 * 4 };
Task function prototypes, names was taken from STM32CubeMX
void StartTask1(void *argument); void StartTask2(void *argument);
Before the scheduler is start we must create tasks
/* Create the thread(s) */ /* creation of Task1 */ Task1Handle = osThreadNew(StartTask1, NULL, &Task1_attributes); /* creation of Task2 */ Task2Handle = osThreadNew(StartTask2, NULL, &Task2_attributes);
Start the Scheduler
/* USER CODE BEGIN Header_StartTask1 */ /** * @brief Function implementing the Task1 thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartTask1 */ void StartTask1(void *argument) { /* USER CODE BEGIN StartTask1 */ /* Infinite loop */ for(;;) { osDelay(1); } /* USER CODE END StartTask1 */ } /* USER CODE BEGIN Header_StartTask2 */ /** * @brief Function implementing the Task2 thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartTask2 */ void StartTask2(void *argument) { /* USER CODE BEGIN StartTask2 */ /* Infinite loop */ for(;;) { osDelay(1); } /* USER CODE END StartTask2 */ }
Below output is generated
Without delay Below Output will generate shown via graphics
4) User Can change or modified priority of task during initial configuration process or during run time , to do that first enable both the functions inside Include Parameters tab , as per below image.
Brief description of both the functions are given below
a) osThreadSetPriority
osStatus_t osThreadSetPriority (osThreadId_t thread_id, osPriority_t priority )
Parameters
- [in] thread_id thread ID obtained by osThreadNew or osThreadGetId.
- [in] priority new priority value for the thread function.
Returns
status code that indicates the execution status of the function.
The function osThreadSetPriority changes the priority of an active thread specified by the parameter thread_id to the priority specified by the parameter priority.
Code Example
#include "cmsis_os2.h" void Thread_1 (void const *arg) { // Thread function osThreadId_t id; // id for the currently running thread osStatus_t status; // status of the executed function id = osThreadGetId(); // Obtain ID of current running thread status = osThreadSetPriority(id, osPriorityBelowNormal); // Set thread priority if (status == osOK) { // Thread priority changed to BelowNormal } else { // Failed to set the priority } }
b) osThreadGetPriority
osPriority_t osThreadGetPriority (osThreadId_t thread_id)
Parameters
[in] thread_id thread ID obtained by osThreadNew or osThreadGetId.
Returns
current priority value of the specified thread.
The function osThreadGetPriority returns the priority of an active thread specified by the parameter thread_id.
Code Example:
#include "cmsis_os2.h" void Thread_1 (void const *arg) { // Thread function osThreadId_t id; // id for the currently running thread osPriority_t priority; // thread priority id = osThreadGetId(); // Obtain ID of current running thread priority = osThreadGetPriority(id); // Obtain the thread priority }
c) osThreadYield
osStatus_t osThreadYield (void)
Returns
status code that indicates the execution status of the function.
The function osThreadYield passes control to the next thread with the same priority that is in the READY state. If there is no other thread with the same priority in state READY, then the current thread continues execution and no thread switch occurs. osThreadYield does not set the thread to state BLOCKED. Thus no thread with a lower priority will be scheduled even if threads in state READY are available.
Code Example:
#include "cmsis_os2.h" void Thread_1 (void const *arg) { // Thread function osStatus_t status; // status of the executed function while (1) { status = osThreadYield(); if (status != osOK) { // an error occurred } } }
d) osThreadSuspend
osStatus_t osThreadSuspend (osThreadId_t thread_id)
Parameters
[in] thread_id thread ID obtained by osThreadNew or osThreadGetId.
Returns
status code that indicates the execution status of the function.
The function osThreadSuspend suspends the execution of the thread identified by parameter thread_id. The thread is put into the BLOCKED state (osThreadBlocked). Suspending the running thread will cause a context switch to another thread in READY state immediately. The suspended thread is not executed until explicitly resumed with the function osThreadResume.
Note:
This function cannot be called from Interrupt Service Routines.
This function must not be called to suspend the running thread when the kernel is locked, i.e. osKernelLock.
5) when we Increase the priority of task 1 to Normal compare to task 2 as shown below
Task 1:
- Priority: osPriorityNormal
- Stack Size: 128 Words
- Entry Function: StartTask01
- Code Generation: Default
- Parameter: NULL
- Allocation: Dynamic
Terminal output:
6) what happened when there is no osdelay inside task1 function
Terminal output:
Comparing CMSIS & FreeRTOS API’s Functions
https://www.keil.com/pack/doc/cmsis/RTOS2/html/modules.html
Software Tools:
- STM32CubeIDE
- STM32CubeMx
- Teraterm
Hardware Setup:
- STM32F429IDISCOVERY board
- Mini USB Cable
- Jumper wire
Conclusion:
Successfully demonstrated FreeRTOS Tasks creation using STM32CubeMx
If you enjoyed this article, share your feedback.