pub:frts_es

FreeRTOS es un sistema operativo de tiempo real multitareas el cual permite administrar los recursos hardware y los tiempos de ejecución de las diferentes tareas implementadas en un microcontrolador. FreeRTOS está desarrollado en lenguaje ANSI-C, conformado por un conjunto de funciones que se ejecutan en momentos determinados del programa y distribuido gratuitamente bajo licencia “Open Source”, incluyendo aplicaciones comerciales.

Actualmente FreeRTOS tiene puertos para procesadores, microcontroladores y softcore de diferentes arquitecturas y marcas. Un listado oficial de los diferentes puertos soportados de manera oficial puede encontrarse en el siguiente enlace: http://www.freertos.org/RTOS_ports.html

Es el interés de esta guía es entregar los fundamentos de sistemas operativos de tiempo real, basados en ejemplos e información propia para FreeRTOS.

El kernel es el componente principal en un sistema operativo. Cada programa que se ejecuta en una aplicación corresponde a una tarea que está bajo el control del sistema operativo. Si el sistema operativo permite ejecutar multiples tareas, se dice que es un sistema operativo multitareas.

Las soluciones desarrolladas típicamente en un microcontrolador tienen requerimientos de tiempo real, esto implica que, los tiempos en los que se ejecutan las tareas deben ser determinísticos y por ello es necesario administrar de forma correcta los recursos de control de tiempo como temporizadores para poder atender todos los eventos que puedan presentarse durante la ejecución del sistema electrónico. Los requerimientos de tiempo real pueden ser “Soft Real Time” y “Hard Real Time”.

  • “Soft Real time”: Un sistema para el cual el control de tiempos es de interés pero el funcionamiento del sistema no se ve comprometido ente posibles demoras en estos tiempos o “dead line”. Ejemplo: Demoras en atender un pulsador puede ser visto por el usuario como un sistema lento pero no deja inservible el sistema.
  • “Hard Real time”: Un sistema para el cual el control de tiempos es de interés y el funcionamiento del sistema se ve comprometido ente posibles demoras en estos tiempos o “dead line”. Ejemplo: Demoras en atender un sensor del sistema de parqueo en un automóvil puede llevr a un accidente, lo que se considera una falla del sistema.

En un procesador de un solo nucleo solo se puede ejecutar una tarea al tiempo, pero, se realizan cambios de contexto entre tareas que permiten dar la apariencia que todas las tareas se estan ejecutando de forma concurrente (ejecución simultanea).

Una tarea es un programa independiente que desarrolla operaciones específicas utilizando uno o varios recursos del microcontrolador como UART, SPI, I2C, memoria RAM, CPU, etc. En una aplicación con sistemas operativos bajo en contexto de multitareas, son varios programas los que comparten los recursos hardware del microcontrolador, incluyendo la CPU. Cada tarea se ejecuta solo cuando todos los argumentos y recursos están disponibles, de lo contrario dicha tarea no podra ser ejecutada por la CPU.

Estructura en lenguaje C de una tarea en FreeRTOS

En FreeRTOS, las tareas tienen una estructura predefinida

void ATaskFunction( void *pvParameters )
{
/* Declara variables locales que utiliza la tarea*/
int iVariableExample = 0;
 
/* La tarea es definida dentro de un ciclo infinito. */
for( ;; )
{
/* El código que ejecuta la tarea está dentro del ciclo infinito. */
}
/* Si la terea sale del ciclo infinito, se entiende que finaliza las operaciones de la misma, por ello esta debe borrarse 
con la funcion de FreeRTOS vTaskDelete(). 
Esto libera todos los recursos que utilizaba dicha tarea. */
vTaskDelete( NULL );
}

Estados de una tarea en FreeRTOS

Una aplicación consiste de muchas tarea. En un microcontrolador con una CPU solo puede ejecutar una tarea a la vez y es deber del sistema operativo gestionar el recurso compartido (CPU) para lograr que todas las tareas sean ejecutadas dentro de unas restricciones de tiempo predefinidas. Si el microcontrolador cuenta con dos o más nucles de procesamiento, serán dos o más las tareas que puedan ejecutarse al tiempo, siempre y cuando todos los argumentos y recursos necesitados por cada tarea estén disponibles.

En el caso de un microcontrolador con una CPU, solo una tarea puede estar en estado “Running”, todas las demás tareas pueden permanecer en estados validos “Suspended”, “Ready” o “Blocked”.

  • Running. Cuando una tarea tiene asignado el recurso CPU y se está ejecutando.
  • Ready. Cuando una tarea esta lista para ser ejecutada (todos los argumentos y recursos están disponibles) y está esperando que el “scheduler” del sistema operativo le asigne la CPU.
  • Blocked. El “scheduler” puede llevar una tarea a este estado si detecta que está esperando por un evento temporal (una espera de tiempo con la función vTaskDelay()), esperando por un evento externo (Interrupcion), o a que un recurso compartido sea liberado (colas, semáforo, notificaciones). Cuando la espera termina, el “scheduler” puede regresar la tarea a estado “ready”.
  • Suspended. Muy similar a “blocked” pero se diferencia en que una tarea solo puede ingresar o salir de este estado cuando es utilizada de forma específica la función vTaskSuspend() o vTaskResume() respectivamente. No es el “scheduler” del sistema operativo el que toma la decisión de cambiar el estado de una tarea a “suspended”.

Estados de una tarea y sus transiciones validas Estados de una tarea y sus transiciones validas

El “scheduler” entrega la CPU (pasar a estado “running”) a una de todas las tareas que se encuentren en estado “ready”. La decisión de a cual tarea entregar la CPU va a depender de las politicas de planificación seleccionada para el “scheduler”. Si varias tareas estan en estado ready, siempre la que tenga mayor prioridad será la que pase primero a estado “running”.

Prioridades de una tarea en FreeRTOS

Cada tarea tiene una prioridad que es asignada en el momento de ser creada. En FreeRTOS una prioridad representada con un número de bajo peso, representa una prioridad baja. Para FreeRTOS existe una tarea denominada “idle task ” y tiene prioridad cero (tskIDLE_PRIORITY). El valor máximo que puede asignarse a una prioridad va a depender del puerto para el cual se está desarrollando la aplicación con FreeRTOS y de su configuración que se encuentra en el archivo “FreeRTOSConfig.h”. El valor en “configMAX_PRIORITIES” define la prioridad máxima para el puerto específico.

Varias tareas pueden tener la misma prioridad y dependiendo de las politicas de operación del scheduler, le será asignado el uso de la CPU a una tarea en específico. En caso de ser habilitado configUSE_TIME_SLICING y son varias tareas con la misma prioridad en estado “ready”, la CPU le será asigna una a una por un espacio de tiempo, a lo cual se llama esquema de planificación “round robin”. Si no es habilitado configUSE_TIME_SLICING y son varias tareas con la misma prioridad en estado “ready”, la CPU le será asignada a la primera tarea en llegar a estado ready y solo cuando esta tarea decida ceder la CPU, se revisará nuevamente las prioridades de las tareas que siguen en estado ready, a lo cual se llama esquema de planificación FIFO.

La prioridad de una tarea puede cambiar en tiempo de ejecución

Tarea Idle en FreeRTOS

Es una tarea creada de manera automática cuando el “scheduler” del RTOS es iniciado. El scheduler debe tener siempre al menos una tarea en estado ready, y para este propósito es la tarea “idle”. Con la prioridad más baja posible (tskIDLE_PRIORITY) se asegura que las demás tareas de la aplicación tengan la CPU cuando esten listas para su ejecución. Esta tarea también cumple la función de liberar la memoria asignada por el RTOS a aquellas tareas que ya han sido eliminadas.

Algunas tareas pueden compartir la misma prioridad de la tarea idle y si este es el caso, se deben revisar las políticas de operación del scheduler para la ejecución de tareas de igual prioridad.

Creación de tareas en FreeRTOS

Una tarea de crea usando la función API de FreeRTOS xTaskCreate(). Es una de las funciones más complejas de FreeRTOS por la cantidad de parámetros que deben ser entregados para su ejecución.

portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode,
const signed portCHAR * const pcName,
unsigned portSHORT usStackDepth,
void *pvParameters,
unsigned portBASE_TYPE uxPriority,
xTaskHandle *pxCreatedTask
);
  • pvTaskCode. Nombre de la función que se define como tarea.
  • pcName. Nombre para identificacion de tarea en tiempo de depuración de la terea. No es usado para la ejecucion de FreeRTOS. Este nombre no debe superar el numero de caracteres definidos en configMAX_TASK_NAME_LEN.
  • usStackDepth. Indica al kernel que tan grande debe asignar en memoria RAM para el stack de la tarea. Este número indica el número de palabras que se pueden almacenar no el número de bytes. Es difícil conocer de antemano cuanta memoria requiere la tarea para su correcta ejecución, por ello típicamente el programador asigna un tamaño que puede considerar razonable, en muchos casos se configura con el valor definido en configMINIMAL_STACK_SIZE, pero esto depende de la tarea.
  • pvParameters. La tarea acepta un parametro de tipo puntero de memoria void ( void* ). El valor asignado en pvParameters será pasado a la tarea en el momento de iniciar su ejecución.
  • uxPriority. Prioridad asignada a la tarea. La prioridad puede ir desde la prioridad más baja (cero) hasta la más alta (configMAX_PRIORITIES – 1). Se recomienda utilizar el menor número de prioridades posibles en una aplicación, sobre todo si existen restricciones en memoria RAM.
  • pxCreatedTask. .

FreeRTOS suministra todas las funciones para la implementación del sistema operativo, incluyendo ejemplos para diferentes puertos. Los archivos mínimos que deben estar presentes en un proyecto con FreeRTOS son:

  • FreeRTOS/Source/tasks.c
  • FreeRTOS/Source/queue.c
  • FreeRTOS/Source/list.c
  • FreeRTOS/Source/portable/[compiler]/[architecture]/port.c.
  • FreeRTOS/Source/portable/MemMang/heap_x.c 'donde x es 1, 2, 3, 4 o 5.'

Si se necesita la funcionalidad timer, incluir “FreeRTOS/Source/timers.c”

Si se necesita la funcionalidad co-routines, incluir “FreeRTOS/Source/croutine.c”

El compilador utilizado debe incluir las siguientes rutas en disco para la busqueda de las fuentes del FreeRTOS:

  • FreeRTOS/Source/include
  • FreeRTOS/Source/portable/[compiler]/[architecture]

FreeRTOS centra todas las configuraciones en un archivo con nombre “FreeRTOSConfig.h”. Es en este archivo donde se puede escalar el sistema operativo, habilitando o deshabilitando funciones para con ello lograr una solución más robusta donde se ocupa mayor cantidad de memoria FLASH y RAM o una solución más ligera, en la que solo aquellos servicios requeridos son incorporados durante la compilación de la aplicación.

El contenido típico del archivo “FreeRTOSConfig.h”:

Para conocer con detalle cada una de las características del FreeRTOS que pueden ser configuradas desde FreeRTOSConfig.h, leer el Manual de Referencia FreeRTOS V9.0.0

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
 
/* 
 * The following #error directive is to remind users that a batch file must be
 * executed prior to this project being built.  The batch file *cannot* be 
 * executed from within the IDE!  Once it has been executed, re-open or refresh 
 * the Eclipse project and remove the #error line below.
 */
 
#include "system.h"
 
/*-----------------------------------------------------------
 * Application specific definitions.
 *
 * These definitions should be adjusted for your particular hardware and
 * application requirements.
 *
 * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
 * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. 
 *----------------------------------------------------------*/
 
#define configUSE_PREEMPTION        1
#define configUSE_IDLE_HOOK         0
#define configUSE_TICK_HOOK         0
#define configTICK_RATE_HZ       ( ( TickType_t ) 1000 )
#define configCPU_CLOCK_HZ       ( ( unsigned long ) SYS_CLK_FREQ )  
#define configMAX_PRIORITIES        ( 5 )
#define configMINIMAL_STACK_SIZE    ( 1024 )
#define configISR_STACK_SIZE        configMINIMAL_STACK_SIZE
#define configTOTAL_HEAP_SIZE       ( ( size_t ) 8388608 )
#define configMAX_TASK_NAME_LEN        ( 8 )
#define configUSE_TRACE_FACILITY    0
#define configUSE_16_BIT_TICKS         0
#define configIDLE_SHOULD_YIELD        0
#define configUSE_MUTEXES        1
#define configUSE_RECURSIVE_MUTEXES    1
#define configUSE_COUNTING_SEMAPHORES     1
#define configCHECK_FOR_STACK_OVERFLOW    0
#define configQUEUE_REGISTRY_SIZE      0
 
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES          0
#define configMAX_CO_ROUTINE_PRIORITIES   ( 2 )
 
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
 
#define INCLUDE_vTaskPrioritySet    1
#define INCLUDE_uxTaskPriorityGet      1
#define INCLUDE_vTaskDelete         1
#define INCLUDE_vTaskCleanUpResources     0
#define INCLUDE_vTaskSuspend        1
#define INCLUDE_vTaskDelayUntil        1
#define INCLUDE_vTaskDelay       1
#define INCLUDE_uxTaskGetStackHighWaterMark  1
 
/* The priority at which the tick interrupt runs.  This should probably be
kept at 1. */
#define configKERNEL_INTERRUPT_PRIORITY      0x01
 
/* The maximum interrupt priority from which FreeRTOS.org API functions can
be called.  Only API functions that end in ...FromISR() can be used within
interrupts. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0x03
 
#endif /* FREERTOS_CONFIG_H */
  • pub/frts_es.txt
  • Última modificación: 2020/09/28 11:44
  • (editor externo)