📜 ⬆️ ⬇️

FreeRTOS: introduction


Hello. In a short series of posts I will try to describe the possibilities and approaches of working with one of the most popular and developing RTOS for microcontrollers - FreeRTOS. I assume a basic acquaintance of the reader with the theory of multitasking, about which you can read in one of the neighboring posts on Habré or somewhere else.
Links to other parts:
FreeRTOS: interprocess communication.
FreeRTOS: mutexes and critical sections.

Why all this? Or an introduction to multitasking systems from the creators of FreeRTOS.

Traditionally, there are 2 versions of multitasking:

Our soft-touch RTOS can be attributed to our computers. the user should see that, for example, by pressing the button with the symbol, he sees the entered character, and if he pressed the button, and after a while he did not see the reaction, the OS will consider the task “not responding” (by analogy with Windows - “The program does not responds "), but the OS remains usable. Thus, a soft-time RTOS simply determines the expected response time, and if it expires, the OS assigns the task to not responding.

To the RTOS of the hard type, just carry the RTOS in embedded devices. In some ways, they are similar to RTOS on destopes (multi-threaded execution on a single processor), but they have the main difference - each task must be performed in the allotted time slot, not fulfilling this condition leads to the collapse of all systems.

But why?

If you have a device with nontrivial logic of data exchange synchronization between a set of sensors, if you really need to guarantee response time, and finally, if you think that the system can grow, but do not know how much, then RTOS is your choice.
')
It is not necessary to use the RTOS, for applying the RTOS i. It is not necessary to use the RTOS in too trivial tasks (get data from 1 sensor, and send further, handle pressing 1 button, etc.) because This will lead to unnecessary redundancy, as the resulting code, and the solution of the problem itself.

Work with tasks (or tasks, processes).

To begin with, I will give a few definitions in order to clarify further reasoning:

" Real-time operating systems (RTOS) are designed to provide an interface to resources of time-critical real-time systems. The main task in such systems is the timeliness of data processing."
" FreeRTOS is a real-time multitasking operating system (RTOS) for embedded systems. Ported to several microprocessor architectures.
From the andrewsh habrauser , regarding the license: it is allowed not to publish the text of the application that uses FreeRTOS, despite the fact that the OS is linked with it. The source of the RTOS itself should always be applied, the changes made to it also. "

FreeRTOS is written in C with a small amount of assembly code (context switching logic) and its core is represented by only 3 C files. More information about the supported platforms can be found on the official site .

Let's get down to business.
Any task is a C function with the following prototype:

void vTask( void *pvParametres ); 

Each task is essentially a mini subroutine that has its own entry point, and is executed within an infinite loop and usually does not have to go out of it, and also has its own stack. One task definition can be used to create several tasks that will be executed independently and also have their own stack.

The body of the task should not contain an explicit return; constructions, and if the task is no longer needed, you can delete it by calling the API function. The following listing demonstrates the typical skeleton skeleton:
 void vTask( void *pvParametres) { /*       ,   .        someVar.   ,      . */ int someVar; //     -     ,      . for( ;; ) { //   } //            ,        ,   . //  vTaskDelete      ,   . //       NULL,   vTaskDelete( NULL ); } 

To create a task, and add it to the scheduler, use a special API function with the following prototype:
 portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask ); 


pvTaskCode - since task is just a C function, its value is the first parameter.

pcName is the name of the task. In fact, it is not used anywhere, and is only useful when debugging with the appropriate plug-ins for IDE.

usStackDepth - since each task is a mini subroutine with its stack, this parameter is responsible for its depth. When downloading RTOS and deploying the system for your platform, you get the FreeRTOSConfig.h file by setting which you can configure the behavior of the OS itself. This file also declares the constant value configMINIMAL_STACK_SIZE , which is to be transmitted as usStackDepth with the appropriate multiplier, if necessary.

pvParameters - during creation, each task can take some parameters, values, or something else that may be needed inside the body of the task itself. From the point of view of encapsulation, this approach is the safest, and as pvParameters it is worth passing, for example, some structure, or NULL, if you do not need to transfer anything.

uxPriority - each task has its own priority, from 0 (min) to ( configMAX_PRIORITIES - 1). Since, in fact, there is no upper limit for this value, it is recommended to use as few values ​​as possible, so that there is no additional RAM consumption for this logic.

pxCreatedTask - handle of created task. When creating a task, you can optionally pass a pointer to the handle of the future task, for later control of the task itself. For example, to remove a specific task.

This function returns pdTRUE if the task is successfully created, or errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY , if the stack size was specified too large, i.e. there is not enough hip for storing the task stack, and the task itself.

In the following listing, I gave a short example of a complete program that creates 2 tasks, each of which flashes an LED:
 void vGreenBlinkTask( void *pvParametrs ) { for( ;; ) { P8OUT ^= BIT7; //    700 FreeRTOS .      FreeRTOSConfig.h     1. vTaskDelay( 700 ); } } void vRedBlinkTask( void *pvParametrs ) { for( ;; ) { P8OUT ^= BIT6; //    1000 FreeRTOS .      FreeRTOSConfig.h     1. vTaskDelay( 1000 ); } } void main(void) { //  .      . vInitSystem(); //  .      ,      ! xTaskCreate( &vGreenBlinkTask, (signed char *)"GreenBlink", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); xTaskCreate( &vRedBlinkTask, (signed char *)"RedBlink", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); //   .   . vTaskStartScheduler(); //      ,      . //       . for( ;; ) { } } 


In the next post I plan to write about the interaction between tasks and work with interrupts.

Source: https://habr.com/ru/post/129105/


All Articles