Cuando descargas FreeRTOS, te encuentras con cientos de archivos. Pero en realidad, el núcleo mágico de este RTOS cabe en solo tres archivos principales de C:
tasks.c: Contiene el Scheduler (Planificador) y el código que crea, pausa y elimina Tareas.queue.c: Maneja la comunicación segura entre tareas (Buzones de mensajes).list.c: Maneja las listas internas de qué tarea está lista y cuál está bloqueada.Los tres archivos de arriba son código C universal; funcionan igual en una tostadora que en un misil. Pero para que el RTOS haga el Cambio de Contexto (pausar una tarea y guardar sus registros), necesita saber exactamente cómo funciona la CPU física. Para ello, FreeRTOS incluye una carpeta llamada portable. Aquí seleccionamos el archivo port.c específico para nuestra arquitectura: el **ARM Cortex-M4F** (nuestro STM32F4).
FreeRTOS es altamente personalizable. No quieres compilar funciones que no vas a usar porque desperdician memoria Flash. El archivo FreeRTOSConfig.h es tu consola de mandos. Aquí defines la velocidad de tu CPU, cuánta RAM cederle al RTOS (Heap) y si quieres usar Preempción o no.
Ejercicio 1: El secuestro de las interrupciones. En nuestros días de Bare-Metal, nosotros configurábamos el SysTick_Handler para contar milisegundos. Ahora, **debemos cederle el control de esas interrupciones al RTOS**. Editaremos el archivo FreeRTOSConfig.h para parametrizar el núcleo de nuestro Despachador de Gas LP, y mapearemos las rutinas de hardware a las funciones del Kernel de FreeRTOS mediante directivas #define.
FreeRTOSConfig.h (Tu panel de mando del RTOS)
/**
* @file FreeRTOSConfig.h
* @brief Configuración maestra del Sistema Operativo para el Despachador
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
// =========================================================================
// 1. CONFIGURACIÓN DEL NÚCLEO
// =========================================================================
// Activar la Preempción. (Si pones 0, el RTOS será cooperativo,
// y las tareas deberán ceder la CPU manualmente. ¡Nosotros queremos 1!).
#define configUSE_PREEMPTION 1
// Frecuencia real del procesador. El RTOS la necesita para calcular los tiempos.
#define configCPU_CLOCK_HZ ( 84000000UL ) // 84 MHz
// Frecuencia del Tick del Sistema. 1000 Hz significa que el Scheduler
// revisa qué tarea debe ejecutarse cada 1 milisegundo.
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
// Prioridades máximas disponibles. (0 es la más baja, 4 es la más alta).
#define configMAX_PRIORITIES ( 5 )
// Tamaño mínimo de Stack (en Words de 32-bits, no en bytes).
// 128 words = 512 bytes de RAM por tarea mínima.
#define configMINIMAL_STACK_SIZE ( ( uint16_t ) 128 )
// =========================================================================
// 2. GESTIÓN DE MEMORIA (El Heap del RTOS)
// =========================================================================
// El STM32F401 tiene 96 KB de SRAM total.
// Le cederemos 30 KB exclusivos al RTOS para que él reparta esta memoria
// dinámicamente entre las tareas que vayamos creando. Los otros 66 KB
// quedan libres para nuestros Framebuffers de la pantalla y variables estáticas.
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 30 * 1024 ) )
// =========================================================================
// 3. SECUESTRO DE INTERRUPCIONES (El Enlace al Hardware)
// =========================================================================
// FreeRTOS utiliza 3 interrupciones crudas de la arquitectura ARM Cortex-M:
// 1. SVC (Supervisor Call): Para iniciar la primera tarea.
// 2. PendSV (Pendable Service): Para ejecutar el Cambio de Contexto de registros.
// 3. SysTick: Para marcar el pulso del tiempo (El Tick).
// Aquí hacemos un "mapeo" redefiniendo los nombres que espera FreeRTOS
// hacia los nombres físicos que usa el compilador (CMSIS) de STM32.
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
#endif /* FREERTOS_CONFIG_H */
main.c (El abandono del Súper Bucle)Una vez que el FreeRTOSConfig.h está listo y los archivos fuente están en nuestro proyecto, nuestro main.c cambia radicalmente su propósito. Ya no hace el trabajo; solo inicializa el hardware y contrata a los "trabajadores" (Tareas).
#include "stm32f401xe.h"
#include "FreeRTOS.h"
#include "task.h"
// Función dummy para representar una tarea
void Tarea_Parpadeo_LED(void *pvParameters) {
while(1) {
// En lugar de usar for() gastando energía, el RTOS bloquea la tarea.
HAL_GPIO_Invertir(pin_led);
vTaskDelay(pdMS_TO_TICKS(500)); // Dormir exactamente 500 Ticks (500 ms)
}
}
int main(void) {
// 1. Inicializa el Hardware (Relojes, Pines, UART)
SystemClock_Config();
// NOTA CRÍTICA BARE-METAL:
// Ya NO configuramos nosotros el SysTick (SysTick_Config).
// FreeRTOS lo configurará automáticamente cuando arranquemos el Scheduler.
// 2. Crear las Tareas
xTaskCreate(Tarea_Parpadeo_LED, "Blinky", 128, NULL, 1, NULL);
// 3. Encender el Sistema Operativo (Punto de no retorno)
// Esta función configura el SysTick, levanta la primera tarea y nunca regresa.
vTaskStartScheduler();
// Si llegas aquí, el RTOS colapsó por falta de RAM en el Heap.
while(1);
return 0;
}
Objetivo del día: Integración del RTOS y Particionamiento de Memoria.
Tu Despachador tiene recursos limitados: 96 KB de RAM. En la Fase 3, apartamos unos cuantos KB para dibujar la pantalla a color sin parpadeos (Framebuffers). Hoy, al compilar FreeRTOS en tu proyecto, hemos configurado la directiva `configTOTAL_HEAP_SIZE` a 30 KB. Esto es crucial.
Al hacer esto, has creado una **Frontera de Memoria**. FreeRTOS toma esos 30 KB y crea su propio administrador interno de memoria (`heap_4.c`). Cuando crees la Tarea de Metrología y la Tarea de WiFi, el RTOS tomará pedacitos de esos 30 KB para darles una "Pila" (Stack) privada a cada tarea. Si la Tarea WiFi tiene un error e intenta pedir más RAM de la permitida, fallará de forma controlada sin invadir la RAM donde guardamos el precio y los litros despachados. Has logrado aislamiento lógico dentro del mismo chip.
tasks.c, queue.c y list.c.FreeRTOSConfig.h es el panel central. Permite activar o desactivar características del sistema operativo (como la preempción) para ahorrar memoria Flash y adaptar el comportamiento del Scheduler a las necesidades de la máquina.port.c) contiene código escrito en lenguaje Ensamblador específico para tu procesador (ej. ARM Cortex-M4). Contiene la magia para guardar los registros de la CPU en la RAM y lograr el cambio de contexto.#define xPortSysTickHandler SysTick_Handler. A partir de este momento, el RTOS es dueño del reloj del sistema.