Table of Contents
Introducción: El papel de los sistemas operativos en tiempo real en el diseño embedido
Los sistemas integrados exigen cada vez más una ejecución predecible, baja latencia y un manejo simultáneo de múltiples eventos. Un sistema operativo en tiempo real (RTOS) proporciona el marco para satisfacer estos requisitos sin obligar a los desarrolladores a construir lógica de programación desde cero. Entre las opciones disponibles, FreeRTOS destaca como un núcleo ligero y de código abierto que se ha convertido en la opción de facto para microcontroladores (MCU) y pequeños procesadores.
Este artículo se expande en la guía original de FreeRTOS, sumergiéndose más profundamente en su arquitectura, configuración, gestión de tareas, mecanismos de sincronización y capacidades avanzadas. Al final, usted tendrá una comprensión completa de cómo aprovechar FreeRTOS para el desarrollo de software integrado de grado de producción.
¿Qué es FreeRTOS?
FreeRTOS es un núcleo de sistema operativo en tiempo real líder en el mercado diseñado específicamente para sistemas integrados. Fue creado por Richard Barry y ahora se mantiene bajo el paraguas Amazon Web Services (AWS) FreeRTOS, asegurando el apoyo y alineación continuos con los ecosistemas de Internet de las cosas (IoT). El núcleo proporciona multitarea preventiva, comunicación entre tareas, primitivos de sincronización y temporizadores de software, todo mientras que requieren sólo unos pocos kilobytes de RAM.
Los atributos clave que hacen FreeRTOS tan ampliamente adoptados incluyen:
- Fuente abierta bajo licencia MIT: No hay tarifas de licencia, disponibilidad de código de fuente completa y uso permisivo en productos comerciales.
- Portabilidad: Puertos oficiales para docenas de arquitecturas MCU (ARM Cortex-M, RISC‐V, AVR, PIC, etc.) y cadenas de herramientas (GCC, IAR, Keil, LLVM).
- ]Papel mínimo: El núcleo puede funcionar en tan poco como 4 KB de ROM y 1 KB de RAM, lo que lo hace adecuado para dispositivos sensibles a los costos.
- Comportamiento definitorio: La programación de la cabeza es constante e independiente del número de tareas, asegurando un tiempo predecible.
- Apoyo comunitario activo y comercial: documentación amplia, foros y servicios profesionales del equipo y socios de FreeRTOS.
FreeRTOS es a menudo el primer encuentro de ingenieros RTOS, y sus conceptos se dirigen directamente a sistemas más complejos, lo que lo convierte en una excelente plataforma de aprendizaje y una base de producción.
Conceptos básicos y objetos de núcleo
Antes de sumergirse en pasos prácticos, es esencial entender los bloques fundamentales de construcción que ofrece FreeRTOS.
Tareas
Las tareas son hilos independientes de ejecución que comparten el tiempo de CPU según un programador preentivo basado en prioridades. Cada tarea tiene su propio pila y contexto. FreeRTOS admite un número ilimitado de tareas (limitado sólo por la memoria disponible). El programador cambia entre tareas basadas en sus prioridades y estado (listo, corriendo, bloqueado, suspendido).
Cargos
Las colas permiten que los mensajes se transmitan entre tareas y entre interrupciones y tareas. Son el mecanismo principal para la comunicación entre tareas. Las colas FreeRTOS son FIFO o LIFO (el último vía ]) y pueden contener elementos de datos de tamaño fijo. Las operaciones de cola están diseñadas para ser eficientes y seguras de interrupción cuando se utilizan con la variante correcta de API.
Semaforas y Mutexes
FreeRTOS ofrece semaforas binarias, semaforas y mutexes. Semaforas binarias actúan como banderas simples utilizadas para señalizar o sincronizar tareas (por ejemplo, notificación de que se ha producido una interrupción). Contando semaforas administran múltiples recursos, mientras que los mutex proporcionan exclusión mutua con un mecanismo de herencia prioritario integrado para prevenir la inversión prioritaria.
Software Timers
El núcleo proporciona temporizadores de software que ejecutan una función de callback cuando un período se pasa. Las máquinas pueden ser una sola instantánea (fuego una vez) o auto-recarga. Corren en una tarea de servicio de temporizador dedicado, por lo que sus manipuladores deben ser cortos y no bloqueadores.
Grupos de eventos
Los grupos de eventos permiten esperar una combinación de múltiples bits (eventos) que se establecerán. Simplifican escenarios donde una acción depende de varias condiciones asincrónicas, como lecturas de sensores y pulsación de botón de usuario.
Comienzo con FreeRTOS
Adoptar FreeRTOS requiere evaluar su hardware objetivo, obtener la fuente del núcleo y configurarlo para que coincida con las limitaciones de su aplicación.
Elegir un microcontrolador compatible
Los puertos FreeRTOS existen para casi todas las familias populares de MCU. Confirme que su dispositivo elegido tiene suficiente RAM y flash para el núcleo más sus tareas. Por ejemplo, un ARM Cortex-M0+ con 16 KB RAM puede ejecutar cómodamente algunas tareas, mientras que un Cortex-M4 con 256 KB RAM soporta muchos. Compruebe la página oficial de puerto de FreeRTOS o el SDK de su proveedor de silicio para ejemplos pre-integrados.
Descarga e integración del núcleo
El último código fuente FreeRTOS está disponible en el FreeRTOS sitio web oficial] o a través de GitHub. La distribución incluye el núcleo (]), los ficheros portátiles de capa () y los proyectos de demostración. Para un comienzo eficiente, copiar el y el directorio portátil adecuado en su árbol de proyecto.
Configuración: El archivo
Todo el comportamiento del kernel se controla a través de . Obtener estos ajustes es crítico tanto para el rendimiento como para la estabilidad.
- :] Se establece a 1 para la programación preventiva (típica para aplicaciones en tiempo real). Se establece a 0 para la programación cooperativa.
- : La frecuencia actual del reloj de la CPU (utilizada por el núcleo para el tiempo correcto).
- : La frecuencia del tiempor del sistema interrumpe. Valores comunes son 100 Hz (10 ms tick) o 1000 Hz (1 ms tick). Las tasas más altas mejoran la resolución pero aumentan la sobrecarga.
- : Cantidad total de RAM disponible para la asignación dinámica de memoria (utilizada por ).
- : El tamaño de la pila (en palabras) para la tarea inactiva y el predeterminado para nuevas tareas si no se especifica. Asegúrese de que esto es lo suficientemente grande para las llamadas de funciones anidadas y los contextos de interrupción.
- : La longitud máxima de los nombres de tareas legibles por el hombre (ayuda a depurar).
- : Se establece a 1 para contadores de garrapatas de 16 bits (saves RAM pero limita el valor máximo de garrapata a 65535 – no se recomienda para sistemas de velocidad de garrapatas largas o altas).
Además, elija un esquema de gestión de montones a través de y . El núcleo incluye cinco implementaciones de montones (heap 1 a heap 5) con diferentes compensaciones en la fragmentación, velocidad de asignación y determinismo. La mayoría de las aplicaciones utilizan (primero ajuste con coalescing) o (multiple non-contiguous Memory regions).
Creación de tareas y gestión del ciclo de vida
Crear tareas es sencillo, pero los detalles de la velocidad de pila, prioridades y las transiciones estatales afectan profundamente la fiabilidad del sistema.
Usando
Una tarea se crea al definir una función que nunca regresa (un bucle es típico) y llamando :
TaskHandle_t xHandle;
xTaskCreate(
vTaskFunction, // Task function pointer
"MyTask", // Name for debugging
configMINIMAL_STACK_SIZE, // Stack size in words
NULL, // Parameters passed to task
2, // Priority (higher number = higher priority)
&xHandle // Optional task handle
);
La función debe inicializar cualquier periférico necesario y luego entrar en su bucle infinito, realizando su trabajo, durmiendo o esperando eventos.
Prioridades de tareas y el programador
FreeRTOS apoya prioridades de 0 (oeste) a (más alto). La tarea ociosa se ejecuta con prioridad 0. El programador preventivo siempre ejecutará la tarea lista de máxima prioridad. Si dos tareas comparten la misma prioridad, ellos se hacen cargo del tiempo (robin redondo) con una duración igual a un período de garrapata. Evite dar tareas no críticas la misma prioridad que las tareas críticas; de lo contrario, el tiempo de la jitteror
Estados de tareas
Cada tarea existe en uno de estos estados:
- Reanunciando: La tarea está ejecutando actualmente (sólo una tarea por núcleo de CPU).
- Ready: La tarea es capaz de funcionar pero se está ejecutando una tarea de mayor prioridad o de igual prioridad.
- Bloqueado: La tarea está esperando un evento (tiempo, mensaje de cola, semaforo, etc.) No consume tiempo de CPU.
- Suspended: La tarea se elimina de la lista lista lista lista del programador, típicamente a través . Sólo se puede reanudar explícitamente.
El bloqueo es el mecanismo principal para una utilización eficiente de la CPU: en lugar de la votación, una tarea simplemente espera una condición, permitiendo que las tareas de menor prioridad funcionen.
Protección de tallas y sobrecostos
Una de las fuentes más comunes de los errores FreeRTOS es el flujo de pila. El núcleo proporciona dos cheques opcionales: . Cuando está habilitado, puede detectar los desbordamientos en el tiempo de conmutación de contexto. Siempre asigna los tamaños de pila generosos durante el desarrollo y utiliza la función para ver el espacio de pila mínimo libre.
La asignación estatica (utilizando ) ofrece más control al permitir que usted proporcione el amortiguador de pila, lo que evita la fragmentación de hebillas y permite la colocación en regiones de memoria específicas (por ejemplo, la memoria ajustada para tareas en tiempo real).
Sincronización y comunicación inter-Task
Las tareas raramente funcionan en forma aislada; necesitan coordinar e intercambiar datos. FreeRTOS ofrece varios mecanismos, cada uno adaptado a patrones particulares.
Cargos para el paso de datos
Use colas para enviar datos de una tarea (o interrumpir) a otra. La cola almacena un número fijo de elementos de un tamaño determinado. Por ejemplo, una tarea de lectura de sensores podría enviar muestras a una tarea de registro. La API es sencilla:
- – enviar el artículo de una tarea (bloquear si está lleno).
- – recibir el artículo (bloquear si está vacío).
- Versiones seguras de ISR: y .
Siempre revise los valores de retorno; una cola puede estar llena o la llamada puede ser hora de salida. En ISRs, una o de retorno indica si se necesita un cambio de contexto.
Semaforas binarias como simples señales
Las semáforas binarias son ideales para notificar una tarea que ha ocurrido un evento. Por ejemplo, una interrupción de GPIO puede “dar” un semáforo y una tarea de espera puede “tomar” el evento y procesar el evento. Este decouples interrumpe las rutinas de servicio (ISR) de la lógica de aplicación. La ISR utiliza ; la tarea utiliza ] en un bucle.
Mutexes con herencia prioritaria
Cuando múltiples tareas acceden a un recurso compartido (por ejemplo, un UART o una estructura de datos), use un mutex en lugar de una semafora binaria. Los mutexes incluyen un mecanismo de herencia prioritario que eleva temporalmente la prioridad de la tarea de mantener el bloqueo a la máxima prioridad de cualquier tarea de espera. Esto evita que las tareas de prioridad media bloqueen indefinidamente una tarea de alta prioridad (inversión de prioridad).
Contando semafores para la gestión de recursos
Contando semaforas, se registra el número de instancias disponibles de un recurso. Por ejemplo, un grupo de cinco canales DMA se puede gestionar con un semaforo contable inicializado a 5. Una tarea “tomafora” una semafora para adquirir un canal y “dar” de vuelta cuando se hace.
Grupos de eventos para la sincronización de múltiples condiciones
Si una tarea debe esperar hasta que se hayan producido varios eventos independientes, los grupos de eventos son más eficientes que los semaforos múltiples. Los bits se fijan por tareas o ISRs, y la tarea de espera puede especificar una máscara de bits y si todos o cualquier necesidad de establecer. La API incluye , ], y sus contrapartes ISR.
Manejo interrumpido: Procesamiento diferido
Uno de los patrones más importantes en FreeRTOS es mantener los ISR extremadamente cortos. En lugar de realizar un procesamiento complejo dentro de una interrupción, utilice el siguiente enfoque:
- Dentro de la ISR, recopilar datos mínimos y señalar una tarea (a través de la semafora, cola o notificación de tareas).
- Desbloquear la tarea, que se ejecuta con una prioridad normal para realizar el levantamiento pesado.
- Utilice las versiones “DeISR” de FreeRTOS API calls (], , etc.) y compruebe el parámetro . Si la tarea desbloqueada tiene una prioridad más alta que la tarea interrumpida, se solicita un interruptor de contexto.
Este tratamiento interrumpido diferido (también llamado el manipulador “bottom‐half”) garantiza que el sistema sigue siendo sensible al mantener la latencia interrumpida predecible. FreeRTOS también admite anidación de interrupciones, pero debe asegurarse de que los niveles de prioridad interrumpida se configuran correctamente—para ARM Cortex‐M, el núcleo requiere que el nivel de prioridad más alto acceso del usuario sea utilizado para el temporizador de garrapata y cualquier ISR API.
Mejores prácticas para aplicaciones de FreeRTOS de producción
Más allá del uso básico, varias prácticas separan un sistema estable de un sistema frágil.
Gestión de memoria
Elija la implementación de heap que coincida con su patrón de asignación. heap 4] es generalmente un buen defecto porque fusiona bloques libres adyacentes. Si su aplicación crea y elimina tareas o colas frecuentemente, evite heap 2 (no coalescing) como conduce a la fragmentación.
Supervisa el uso de la pila usando y . Asegurar que sea lo suficientemente grande como para acomodar las asignaciones de los peores casos.
Estrategia de asignación de prioridades
Prioridades de asignación basadas en el plazo y la importancia crítica de cada tarea.
- Mayor prioridad:] Los bucles de control crítico (por ejemplo, PID de motor, procesamiento de audio).
- Prioridad media:] Adquisición periódica de datos con requisitos de latencia moderada.
- Low priority:] Tareas de fondo, actualizaciones de interfaz de usuario, registro.
Evite tener múltiples tareas con la misma prioridad si todos necesitan plazos firmes, porque el tiempo-slicing puede introducir injusticia. Use bloqueo para permitir que las tareas de menor prioridad funcionen cuando las tareas de mayor prioridad están esperando.
Optimización de potencia: Idle sin tick
Muchos dispositivos integrados son propulsores de batería. FreeRTOS soporta un modo de ocio sin garrapatas que detiene la interrupción periódica de garrapatas cuando el sistema está ocioso y todas las tareas están bloqueadas durante una duración conocida. El MCU puede entrar en un estado de sueño profundo. Esto se configura mediante la configuración a 1 y la provisión de macros .
Debugging y Profiling
FreeRTOS incluye una función estadística de tiempo de ejecución (enable y ]) que proporciona porcentajes de ejecución de tareas. Esto ayuda a identificar los cerdos y puestos de CPU. Además, las funciones y de salida de resúmenes legibles por el ser humano a un amortiguador de caracteres.
Para un análisis más profundo, integre FreeRTOS+Trace (ahora parte del AWS IoT Device Tester). Esta herramienta registra eventos del núcleo (cambios de texto, operaciones de cola, entradas de ISR) y los muestra en una línea de tiempo, invaluable para diagnosticar problemas de tiempo y inversiones prioritarias.
Características avanzadas
Notificación de tareas
Las notificaciones de tareas proporcionan una alternativa ligera a las semaforas y colas para la simple señalización. Cada tarea tiene un valor de notificación integrado de 32 bits y un recuento de notificación pendiente. Enviar una notificación (a través o ) puede desbloquear la tarea receptora con cero sobrecabezamiento de un objeto de núcleo separado. Esto es más rápido y utiliza menos RAM que semaphores.
Transmisión de amortiguadores y amortiguadores de mensajes
Presentada en FreeRTOS V10.0.0, los buffers de flujo permiten que se transmitan datos de longitud variable entre tareas o entre una ISR y una tarea sin cola de tamaño fijo. Un buffer de mensaje es un buffer de flujo que también preserva los límites de mensajes. Estos son útiles para situaciones en las que el tamaño de los datos no se conoce de antemano, como pilas de redes o persianas de comando.
Co-Routines (Legacy)
FreeRTOS también incluye co-rutinas, que son tareas sin pila que comparten una sola pila. Rara vez se utilizan en aplicaciones modernas porque complican la depuración y carecen de las características completas de las tareas. Se recomienda utilizar tareas estándar a menos que se encuentre con bajo control RAM severa (por ejemplo, MCU de 8 bits).
Conclusión
FreeRTOS proporciona una base sólida y bien documentada para la construcción de aplicaciones integradas eficientes. Su soporte para multitarea preventiva, primitivos de sincronización rica, y características avanzadas como las notificaciones de ocio y tarea sin garrapatas lo hace adecuado para todo desde simples nodos de sensores hasta complejas pasarelas IoT. Al entender los parámetros de configuración del kernel, siguiendo las mejores prácticas para la gestión de memoria y asignación prioritaria, y aprovechando herramientas de depuración confiables.
Para un aprendizaje más profundo, consulte el Manual de referencia de FreeRTOS] y explore las aplicaciones demo incluidas en el árbol fuente. Muchos proveedores de silicio, como STLa microelectrónica ] y NXP, le proporcionan guías de integración gratuitas.