

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Aspectos fundamentales del kernel de FreeRTOS
<a name="dev-guide-freertos-kernel"></a>

El kernel de FreeRTOS es un sistema operativo en tiempo real que admite numerosas arquitecturas. Los fundamentos de esta arquitectura son ideales para crear aplicaciones de microcontroladores integradas. Proporciona:
+ Un programador multitareas.
+ Varias opciones de asignación de memoria (incluida la opción de crear sistemas asignados de forma totalmente estática). 
+ Primitivos de coordinación entre tareas, como notificaciones de tareas, colas de mensajes, varios tipos de semáforo y búferes de transmisión y mensajes.
+ Compatibilidad para el multiprocesamiento simétrico (SMP) en microcontroladores de varios núcleos.

El kernel de FreeRTOS nunca realiza operaciones no deterministas, como, por ejemplo, recorrer una lista enlazada, dentro de interrupciones o secciones críticas. El kernel de FreeRTOS incluye una implementación de temporizador de software eficiente que no utiliza tiempo de CPU a menos que el temporizador necesite mantenimiento. Las tareas bloqueadas no necesitan laborioso mantenimiento periódico. Las notificaciones directas a la tarea facilitan una rápida señalización de la tarea, sin casi ningún gasto de RAM. Se pueden utilizar en la mayoría de las situaciones de señalización entre tareas y de interrupción a tarea.

El kernel de FreeRTOS cuenta con un diseño pequeño, sencillo y fácil de usar. Una imagen binaria típica del kernel de RTOS se encuentra en el rango de 4000 a 9000 bytes.

Para obtener la documentación más actualizada sobre el kernel de FreeRTOS, consulte [ FreeRTOS.org](https://freertos.org/). FreeRTOS.org ofrece una serie de tutoriales detallados y guías sobre el uso del kernel FreeRTOS, incluida una [Guía de inicio rápido del kernel FreeRTOS](https://freertos.org/Documentation/01-FreeRTOS-quick-start/01-Beginners-guide/02-Quick-start-guide) y el documento más detallado [Implementación de RTOS](https://freertos.org/Documentation/02-Kernel/05-RTOS-implementation-tutorial/01-RTOS-implementation) en la *Documentación de FreeRTOS*.

# El programador del kernel de FreeRTOS
<a name="freertos-kernel-scheduler"></a>

Una aplicación integrada que utiliza un RTOS pueden estructurarse como un conjunto de tareas independientes. Cada tarea se ejecuta dentro de su propio contexto, sin dependencia de otras tareas. En un momento dado, solo se ejecuta una tarea en la aplicación. El programador de RTOS en tiempo real determina cuándo debe ejecutarse cada tarea. Cada tarea se proporciona con su propia pila. Cuando una tarea se intercambia para poder ejecutar otra tarea, el contexto de ejecución de la tarea se guarda en la pila de la tarea de modo que puede restaurarse cuando esa misma tarea vuelva reanudar su ejecución más adelante. 

Para proporcionar comportamiento determinista en tiempo real, el programador de tareas de FreeRTOS permite asignar prioridades estrictas a las tareas. RTOS garantiza que la tarea de máxima prioridad que pueda ejecutar reciba tiempo de procesamiento. Esto requiere compartir el tiempo de procesamiento entre tareas de la misma prioridad si están listas para ejecutarse en el mismo momento. FreeRTOS también crea una tarea de inactividad que ejecuta solo cuando no hay otras tareas listas para ejecutarse.

# Asignación de memoria del kernel
<a name="kernel-memory-allocation"></a>

El kernel de RTOS necesita RAM cada vez que se crea una tarea, cola u otros objetos RTOS. La RAM se puede asignar:
+ Estáticamente durante la compilación.
+ Dinámicamente desde el montón de RTOS mediante funciones de creación de objetos de la API de RTOS.

Cuando se crean objetos de RTOS de forma dinámica, no siempre es adecuado usar las funciones `malloc()` y `free()` de la biblioteca C estándar por una serie de razones:
+ Puede que no estén disponibles en sistemas integrados.
+ Pueden ocupar valioso espacio de código.
+ No son normalmente seguras para subprocesos.
+ No son deterministas.

Por estas razones, FreeRTOS mantiene la API de asignación de memoria en su capa portátil. La capa portátil se encuentra fuera de los archivos de origen que implementan la funcionalidad RTOS central, de forma que podrá proporcionar una implementación específica de la aplicación adecuada para el sistema en tiempo real que está desarrollando. Cuando el kernel de RTOS necesita RAM, llama a `pvPortMalloc()` en lugar de a `malloc()`(). Cuando se libera RAM, el kernel de RTOS llama a `vPortFree()` en lugar de a `free()`.

# Administración de la memoria de aplicaciones
<a name="application-memory-management"></a>

Cuando las aplicaciones necesitan memoria, es posible asignarla desde el montón de FreeRTOS. FreeRTOS ofrece varios esquemas de administración de montón de distinta complejidad y características. También puede proporcionar su propia implementación de montón.

El kernel de FreeRTOS incluye cinco implementaciones de montón:

**`heap_1`**  
Es la implementación más sencilla. No permite liberar memoria.

**`heap_2`**  
Permite liberar memoria, pero no fusiona bloques libres adyacentes.

**`heap_3`**  
Encapsula `malloc()` y `free()` estándar para la seguridad para subprocesos.

**`heap_4`**  
Fusiona bloques libres adyacentes para evitar la fragmentación. Incluye una opción de ubicación de dirección absoluta.

**`heap_5`**  
Es similar a heap\$14. Puede distribuir el montón por numerosas áreas de memoria no adyacentes.

# Coordinación entre tareas
<a name="inter-task-coordination"></a>

Esta sección contiene información sobre los primitivos de FreeRTOS.

**Topics**
+ [Colas](#inter-task-queues)
+ [Semáforos y exclusiones mutuas](#inter-task-semaphones)
+ [Notificaciones directas a la tarea](#direct-task-notifications)
+ [Búferes de transmisión](#rtos-stream-buffer)
+ [Búferes de mensajes](#rtos-message-buffer)

## Colas
<a name="inter-task-queues"></a>

Las colas son la principal forma de comunicación entre tareas. Pueden utilizarse para enviar mensajes entre tareas y entre interrupciones y tareas. En la mayoría de los casos, se utilizan como búferes FIFO (primero en entrar, primero en salir) seguros para subprocesos y los datos nuevos se envían al final de la cola. (Los datos también se puede enviar al principio de la cola). Los mensajes se envían a través de colas mediante copia, lo que significa que los datos (que pueden ser un puntero a búferes de mayor tamaño) en sí se copian en la cola, en lugar de limitarse a almacenar una referencia a los datos.

Las API de cola permiten especificar un tiempo de bloqueo. Cuando una tarea intenta leer una cola vacía, la tarea se coloca en estado bloqueado hasta que haya datos disponibles en la cola o hasta que transcurra el tiempo de bloqueo. Las tareas en estado bloqueado no consumen tiempo de CPU, lo que permite ejecutar otras tareas. Asimismo, cuando una tarea intenta escribir en una cola vacía, la tarea se coloca en estado bloqueado hasta que haya espacio disponible en la cola o hasta que transcurra el tiempo de bloqueo. Si hay más de una tarea bloqueada en la misma cola, se desbloquea primero la tarea con la prioridad más alta. 

Otros primitivos de FreeRTOS, como, por ejemplo, las notificaciones directas a la tarea y los búferes de mensajes y transmisión, ofrecen alternativas ligeras a las colas en muchas situaciones de diseño habituales. 

## Semáforos y exclusiones mutuas
<a name="inter-task-semaphones"></a>

El kernel de FreeRTOS proporciona semáforos binarios, semáforos de recuento y exclusiones mutuas con fines de exclusión mutua y sincronización.

Los semáforos binarios solo pueden tener dos valores. Son una buena opción para implementaciones de sincronización (ya sea entre tareas o entre tareas e interrupciones). Los semáforos de recuento tienen más de dos valores. Permiten compartir recursos entre muchas tareas o realizar las operaciones de sincronización más complejas.

Las exclusiones mutuas son semáforos binarios que incluyen un mecanismo de herencia de prioridades. Esto significa que si una tarea de alta prioridad se bloquea al intentar obtener una exclusión mutua que actualmente está en manos de una tarea de menor prioridad, la prioridad de la tarea que tiene el token se eleva temporalmente a la de la tarea bloqueada. Este mecanismo está diseñado para garantizar que la tarea de mayor prioridad se mantenga en estado bloqueado el menor tiempo posible, a fin de minimizar la inversión de prioridades que ha tenido lugar.

## Notificaciones directas a la tarea
<a name="direct-task-notifications"></a>

Las notificaciones de tareas permiten a las tareas interactuar con otras tareas así como sincronizarse con rutinas de servicio de interrupción (ISR), sin necesidad de un objeto de comunicación independiente como un semáforo. Cada tarea de RTOS tiene un valor de notificación de 32 bits que se utiliza para almacenar el contenido de la notificación, de haberlo. Una notificación de tarea de RTOS es un evento enviado directamente a una tarea que puede desbloquear la tarea receptora y, de forma opcional, actualizar el valor de notificación de la tarea receptora.

Las notificaciones de tareas de RTOS se pueden utilizar como alternativa ligera y rápida a los semáforos de recuento y binarios y, en algunos casos, a las colas. Las notificaciones de tareas ofrecen ventajas de velocidad y huella de RAM con respecto a las otras características de FreeRTOS que se pueden utilizar para realizar una funcionalidad equivalente. Sin embargo, las notificaciones de tareas únicamente se pueden utilizar cuando solo hay una tarea que puede ser receptora del evento.

## Búferes de transmisión
<a name="rtos-stream-buffer"></a>

Los búferes de transmisión permiten pasar una secuencia de bytes de una rutina de servicio de interrupción a una tarea o de una tarea a otra. Una secuencia de bytes puede tener una longitud arbitraria y no tiene que tener un principio o un final. Es posible escribir cualquier número de bytes en un momento dado y es posible leer cualquier número de bytes en un momento dado. La funcionalidad de búfer de transmisión se habilita al incluir el archivo de origen `stream_buffer.c` en su proyecto.

Los búferes de transmisión dan por hecho que solo hay una tarea o interrupción que escribe en el búfer (el escritor) y solo una tarea o interrupción que lee del búfer (el lector). Es seguro que el escritor y el lector sean distintas tareas o rutinas de servicio de interrupción, pero no es seguro tener varios escritores o lectores.

La implementación del búfer de transmisión utiliza notificaciones directas a las tareas. Por lo tanto, llamar a una API de búfer de transmisión que coloca la tarea que llama en estado bloqueado puede cambiar el valor y el estado de la notificación de la tarea que llama.

### Envío de datos
<a name="rtos-stream-buffer-send"></a>

`xStreamBufferSend()` se utiliza para enviar datos a un búfer de transmisión en una tarea. `xStreamBufferSendFromISR()` se utiliza para enviar datos a un búfer de transmisión en una rutina de servicio de interrupción (ISR).

`xStreamBufferSend()` permite especificar un tiempo de bloqueo. Si `xStreamBufferSend()` se llama con un tiempo de bloqueo distinto de cero para escribir en un búfer de transmisión y el búfer está lleno, la tarea se coloca en estado bloqueado hasta que haya espacio disponible o transcurra el tiempo de bloqueo.

`sbSEND_COMPLETED()` y `sbSEND_COMPLETED_FROM_ISR()` son macros que la API de FreeRTOS llama internamente cuando se escriben datos en un búfer de transmisión. Se necesita el controlador del búfer de transmisión que se ha actualizado. Ambas macros comprueban si hay una tarea bloqueada en el búfer de transmisión a la espera de datos y, de ser así, eliminan la tarea del estado bloqueado.

Para cambiar este comportamiento predeterminado, proporcione su propia implementación de `sbSEND_COMPLETED()` en [`FreeRTOSConfig.h`](freertos-config.md). Esto resulta útil cuando se utiliza un búfer de transmisión para transferir datos entre núcleos en un procesador de varios núcleos. En ese caso, se puede implementar `sbSEND_COMPLETED()` para generar una interrupción en el otro núcleo de la CPU y la rutina del servicio de interrupción puede entonces utilizar la API `xStreamBufferSendCompletedFromISR()` para comprobar y, si es necesario, desbloquear, una tarea que está a la espera de datos.

### Recepción de datos
<a name="rtos-stream-buffer-receive"></a>

`xStreamBufferReceive()` se utiliza para leer datos de un búfer de transmisión en una tarea. `xStreamBufferReceiveFromISR()` se utiliza para leer datos de un búfer de transmisión en una rutina de servicio de interrupción (ISR).

`xStreamBufferReceive()` permite especificar un tiempo de bloqueo. Si `xStreamBufferReceive()` se llama con un tiempo de bloqueo distinto de cero para leer de un búfer de transmisión y el búfer está vacío, la tarea se coloca en estado bloqueado hasta que esté disponible una determinada cantidad de datos en el búfer de transmisión o hasta que transcurra el tiempo de bloqueo.

La cantidad de datos que debe haber en el búfer de transmisión antes de que se desbloquee la tarea se denomina umbral de activación del búfer de transmisión. Una tarea bloqueada con un nivel de activación de 10 se desbloquea cuando se escriben al menos 10 bytes en el búfer o cuando transcurre el tiempo de bloqueo. Si el tiempo de bloqueo de una tarea de lectura caduca antes de que se alcance el nivel de activación, la tarea recibe cualquier dato escrito en el búfer. El nivel de activación de la tarea se debe establecer en un valor entre 1 y el tamaño del búfer de transmisión. El nivel de activación del búfer de transmisión se establece cuando se llama a `xStreamBufferCreate()`. Para cambiarlo, llame a `xStreamBufferSetTriggerLevel()`.

`sbRECEIVE_COMPLETED()` y `sbRECEIVE_COMPLETED_FROM_ISR()` son macros que la API de FreeRTOS llama internamente cuando se leen datos de un búfer de transmisión. Los macros comprueban si hay una tarea bloqueada en el búfer de transmisión que está esperando a que haya espacio para volverse disponibles dentro del búfer y, de ser así, eliminan la tarea del estado bloqueado. Para cambiar el comportamiento predeterminado de `sbRECEIVE_COMPLETED()` al proporcionar una implementación alternativa en [`FreeRTOSConfig.h`](freertos-config.md).

## Búferes de mensajes
<a name="rtos-message-buffer"></a>

Los búferes de mensajes permiten pasar mensajes discretos de longitud variable de una rutina de servicio de interrupción a una tarea o de una tarea a otra. Por ejemplo, los mensajes de 10, 20 y 123 bytes de longitud se pueden escribir o leer en el mismo búfer de mensajes. Los mensajes de 10 bytes solo se puede leer como mensajes de 10 bytes, no como bytes individuales. Los búferes de mensajes se basan en la implementación del búfer de transmisión. Puede habilitar la funcionalidad del búfer de mensajes al incluir el archivo de origen `stream_buffer.c` en su proyecto.

Los búferes de mensajes dan por hecho que solo hay una tarea o interrupción que escribe en el búfer (el escritor) y solo una tarea o interrupción que lee del búfer (el lector). Es seguro que el escritor y el lector sean distintas tareas o rutinas de servicio de interrupción, pero no es seguro tener varios escritores o lectores.

La implementación del búfer de mensajes utiliza notificaciones directas a las tareas. Por lo tanto, llamar a una API de búfer de transmisión que coloca la tarea que llama en estado bloqueado puede cambiar el valor y el estado de la notificación de la tarea que llama. 

Para permitir que los búferes de mensajes controlen mensajes de tamaños variables, la longitud de cada mensaje se escribe en el búfer de mensajes antes que el mensaje en sí. La longitud se almacena en una variable de tipo `size_t`, que suelen ser 4 bytes en una arquitectura de 32 bytes. Por lo tanto, al escribir un mensaje de 10 bytes en el búfer de mensajes, se consumen realmente 14 bytes de espacio del búfer. Asimismo, al escribir un mensaje de 100 bytes en el búfer de mensajes, se usan realmente 104 bytes de espacio del búfer.

### Envío de datos
<a name="rtos-message-buffer-send"></a>

`xMessageBufferSend()` se utiliza para enviar datos a un búfer de mensajes desde una tarea. `xMessageBufferSendFromISR()` se utiliza para enviar datos a un búfer de mensajes desde una rutina de servicio de interrupción (ISR).

`xMessageBufferSend()` permite especificar un tiempo de bloqueo. Si `xMessageBufferSend()` se llama con un tiempo de bloqueo distinto de cero para escribir en un búfer de mensajes y el búfer está lleno, la tarea se coloca en estado bloqueado hasta que haya espacio disponible en el búfer de mensajes o transcurra el tiempo de bloqueo.

`sbSEND_COMPLETED()` y `sbSEND_COMPLETED_FROM_ISR()` son macros que la API de FreeRTOS llama internamente cuando se escriben datos en un búfer de transmisión. Se necesita un único parámetro, que es el controlador del búfer de transmisión que se ha actualizado. Ambas macros comprueban si hay una tarea bloqueada en el búfer de transmisión a la espera de datos y, de ser así, eliminan la tarea del estado bloqueado.

Para cambiar este comportamiento predeterminado, proporcione su propia implementación de `sbSEND_COMPLETED()` en [`FreeRTOSConfig.h`](freertos-config.md). Esto resulta útil cuando se utiliza un búfer de transmisión para transferir datos entre núcleos en un procesador de varios núcleos. En ese caso, se puede implementar `sbSEND_COMPLETED()` para generar una interrupción en el otro núcleo de la CPU y la rutina del servicio de interrupción puede entonces utilizar la API `xStreamBufferSendCompletedFromISR()` para comprobar y, si es necesario, desbloquear, una tarea que estaba a la espera de datos.

### Recepción de datos
<a name="rtos-message-buffer-receive"></a>

`xMessageBufferReceive()` se utiliza para leer datos de búfer de mensajes en una tarea. `xMessageBufferReceiveFromISR()` se utiliza para leer datos de un búfer de mensajes en una rutina de servicio de interrupción (ISR). `xMessageBufferReceive()` permite especificar un tiempo de bloqueo. Si `xMessageBufferReceive()` se llama con un tiempo de bloqueo distinto de cero para leer de un búfer de mensajes y el búfer está vacío, la tarea se coloca en estado bloqueado hasta que haya datos disponibles o transcurra el tiempo de bloqueo.

`sbRECEIVE_COMPLETED()` y `sbRECEIVE_COMPLETED_FROM_ISR()` son macros que la API de FreeRTOS llama internamente cuando se leen datos de un búfer de transmisión. Los macros comprueban si hay una tarea bloqueada en el búfer de transmisión que está esperando a que haya espacio para volverse disponibles dentro del búfer y, de ser así, eliminan la tarea del estado bloqueado. Para cambiar el comportamiento predeterminado de `sbRECEIVE_COMPLETED()` al proporcionar una implementación alternativa en [`FreeRTOSConfig.h`](freertos-config.md).

# Compatibilidad para el multiprocesamiento simétrico (SMP)
<a name="smp-support"></a>

La [compatibilidad para SMP en el kernel de FreeRTOS](https://freertos.org/symmetric-multiprocessing-introduction.html) permite que una instancia del kernel de FreeRTOS programe tareas en varios núcleos de procesador idénticos. Las arquitecturas del núcleo deben ser idénticas y compartir la misma memoria.

La API de FreeRTOS sigue siendo prácticamente la misma entre las versiones de un solo núcleo y SMP, a excepción de [estas API adicionales](https://freertos.org/symmetric-multiprocessing-introduction.html#smp-specific-apis). Por lo tanto, una aplicación escrita para la versión de un solo núcleo de FreeRTOS debería compilarse con la versión de SMP con un esfuerzo mínimo o nulo. Sin embargo, es posible que haya algunos problemas funcionales, ya que algunas suposiciones que eran ciertas para las aplicaciones de un solo núcleo pueden dejar de serlo para las aplicaciones de varios núcleos.

Una suposición común es que una tarea de menor prioridad no se puede ejecutar mientras se está ejecutando una tarea de mayor prioridad. Si bien esto era cierto en un sistema de un solo núcleo, ya no lo es en los sistemas de varios núcleos, ya que se pueden ejecutar varias tareas simultáneamente. Si la aplicación se basa en las prioridades relativas de las tareas para excluirse mutuamente, podría observar resultados inesperados en un entorno multinúcleo.

Otra suposición común es que los ISR no pueden ejecutarse simultáneamente entre sí ni con otras tareas. Esto ya no es cierto en un entorno multinúcleo. El redactor de la aplicación debe garantizar una exclusión mutua adecuada al acceder a los datos compartidos entre las tareas y los ISR.

# Temporizadores de software
<a name="software-timers"></a>

Un temporizador de software permite ejecutar una función en un momento determinado en el futuro. La función ejecutada por el temporizador se denomina *función de devolución de llamada* del temporizador. El tiempo entre el inicio de un temporizador y la ejecución de la función de devolución de llamada se denomina *periodo* del temporizador. El kernel de FreeRTOS proporciona una implementación de temporizador de software eficiente porque:
+ No ejecuta funciones de devolución de llamada del temporizador desde un contexto de interrupción.
+ No consume tiempo de procesamiento a menos que el temporizador haya caducado.
+ No añade gastos de procesamiento a la interrupción de ciclo.
+ No recorre estructuras de listas de enlace si las interrupciones están deshabilitadas.

# Soporte de bajo consumo
<a name="low-power-support"></a>

Al igual que la mayoría de los sistemas operativos integrados, el kernel de FreeRTOS utiliza un temporizador de hardware para generar interrupciones de ciclo periódicas, que se utilizan para medir el tiempo. El ahorro energético de las implementaciones de temporizador de hardware normales está limitado por la necesidad de salir y volver a entrar, de forma periódica, en el estado de bajo consumo para procesar interrupciones de ciclo. Si la frecuencia de la interrupción de ciclo es demasiado alta, la energía y el tiempo consumidos en entrar y salir del estado de bajo consumo para cada ciclo superan los posibles ahorros energéticos obtenidos en todos los casos salvo en los modos de ahorro de energía más ligeros. 

Para solucionar esta limitación, FreeRTOS incluye un modo de temporizador sin ciclo para las aplicaciones de bajo consumo. El modo inactivo sin ciclo de FreeRTOS detiene la interrupción de ciclo periódica durante los periodos de inactividad (cuando no hay tareas de la aplicación que se puedan ejecutar) y, a continuación, realiza un ajuste de corrección del valor de recuento de ciclo de RTOS cuando se reinicia la interrupción de ciclo. La detención de la interrupción de ciclo permite que el microcontrolador permanezca en un estado de ahorro de energía profundo hasta que se produzca una interrupción o llegue el momento de que el kernel de RTOS pase una tarea al estado listo.

# Configure el kernel (FreeRtosConfig.h)
<a name="freertos-config"></a>

Puede configurar el kernel de FreeRTOS para una placa y una aplicación específicas con el archivo de encabezado `FreeRTOSConfig.h`. Cada aplicación creada en el kernel debe tener un archivo de encabezado `FreeRTOSConfig.h` en la ruta de inclusión del preprocesador. `FreeRTOSConfig.h` es específico de la aplicación y se debería colocar en un directorio de aplicaciones y no en uno de directorios de códigos fuente del kernel de FreeRTOS.

Los archivos `FreeRTOSConfig.h` de las aplicaciones de demostración y prueba de FreeRTOS se encuentran en `freertos/vendors/vendor/boards/board/aws_demos/config_files/FreeRTOSConfig.h` y `freertos/vendors/vendor/boards/board/aws_tests/config_files/FreeRTOSConfig.h`.

Para obtener una lista de los parámetros de configuración disponibles para especificarlos en `FreeRTOSConfig.h`, consulte [FreeRTOS.org](https://www.freertos.org/a00110.html)