DÍA 186 DE 365

Fase 4: FreeRTOS y Conectividad IoT

📖 Teoría a Estudiar

El Dictador Preemptivo: Regla #1 del RTOS

La regla fundamental de FreeRTOS (y cualquier RTOS moderno) es matemáticamente simple pero brutal: El procesador SIEMPRE ejecutará la tarea con la prioridad más alta que esté en estado READY (Lista).

Esto significa que si tienes una tarea de prioridad Alta, una Normal y una Baja, el RTOS *nunca* repartirá el tiempo equitativamente. La tarea de prioridad Alta se adueñará del 100% de la CPU indefinidamente.

El Peligro de la Inanición (Starvation)

Si escribes tu tarea de prioridad Alta así:

void Tarea_Valvula() { 
    while(1) { 
        Leer_Presion(); // Cuidado, ¡no hay osDelay()!
    } 
}

Has creado un agujero negro. Como esta tarea siempre está ejecutando código y nunca cede voluntariamente la CPU pasando al estado BLOCKED, las tareas Normal y Baja jamás recibirán ni un solo microsegundo de CPU. A este fenómeno fatal se le conoce como Inanición (Starvation). La pantalla de tu máquina se quedará congelada para siempre y el WiFi jamás enviará un paquete.

El Equilibrio del Ecosistema

Para evitar la Inanición, las tareas de Prioridad Alta deben ser diseñadas como Francotiradores: Se despiertan por un evento (o por un osDelay), ejecutan su trabajo en 50 microsegundos de manera ultrarrápida, y se vuelven a dormir (BLOCKED) inmediatamente. Al dormir, la CPU automáticamente cae en cascada hacia las tareas de menor prioridad.

PREEMPCIÓN EN CASCADA: ALTA PRIORIDAD DOMINA LA CPU TIEMPO (ms) → t=0 t=10 t=15 t=25 t=35 VALVULA (High) RUN Despierta! Vuelve a dormir (BLOCKED) PANTALLA (Normal) Dibuja Fondo READY Dibuja Precio WIFI IoT (Low) Prepara TX al Servidor READY (Espera) READY READY Finaliza TX AWS Preempt a LOW Preempt a NORMAL

⚙️ Ejercicios Prácticos

Ejercicio 1: Vamos a crear nuestro ensamble en C asignando prioridades CMSIS-OS v2. Utilizaremos osPriorityRealtime para la Tarea de Válvula, asegurando que si ocurre un evento de cierre, el RTOS acribille inmediatamente cualquier otra tarea (incluso si la pantalla está dibujando) para apagar la salida física.


/**
 * @file priority_test.c
 * @brief Implementación de Jerarquía Estricta en Despachador de Gas LP
 */

#include "stm32f401xe.h"
#include "cmsis_os2.h"

// =======================================================
// TAREA 3: VÁLVULA Y SEGURIDAD (Prioridad MÁXIMA / Realtime)
// Diseño de Francotirador: Ejecución rápida y a dormir.
// =======================================================
void Thread_Seguridad_Valvula(void *argument) {
    for (;;) {
        // [1. DESPIERTA]
        // Lee hardware instantáneamente
        float presion_actual = Leer_Sensor_Presion_ADC();
        float litros = Metro_GetLitros();
        
        // [2. ACCIÓN DE CIRUJANO]
        if (presion_actual > LIMITE_PRESION_PELIGRO || litros >= LIMITE_VENTA) {
            // ¡CIERRE INMEDIATO! Como tiene prioridad Realtime, 
            // esta línea se ejecuta a los pocos microsegundos de despertarse.
            Valvula_SetApertura(0.0f);
        }
        
        // [3. CEDE EL CONTROL (Evita Starvation)]
        // Duerme por 10ms. La CPU automáticamente "cae" al Hilo de Pantalla.
        osDelay(10); 
    }
}

// =======================================================
// TAREA 2: INTERFAZ LCD (Prioridad NORMAL)
// =======================================================
void Thread_Pantalla_LCD(void *argument) {
    for (;;) {
        // Actualizar la pantalla por SPI toma como 20ms.
        // Mientras esto ocurre, el RTOS nos interrumpirá internamente 
        // 2 veces para darle paso rápido a la Tarea de la Válvula.
        UI_Dibujar_Pantalla_Completa();
        
        // Cede el control por 50ms (Refresco a 20 FPS).
        // Al dormir, la CPU "cae" al Hilo WiFi.
        osDelay(50); 
    }
}

// =======================================================
// TAREA 1: IOT WIFI (Prioridad BAJA)
// =======================================================
void Thread_WiFi_Cloud(void *argument) {
    for (;;) {
        // Tarea monstruosamente lenta (Tarda varios segundos).
        // Si usamos polling o enviamos cadenas inmensas de JSON, no nos importa.
        // Debido a que tiene prioridad LOW, el RTOS la pausará sin piedad
        // cada vez que la Pantalla o la Válvula necesiten trabajar.
        Conectar_A_Red_Y_Enviar_Ticket();
        
        // Intenta enviar datos 1 vez por segundo
        osDelay(1000);
    }
}

// =======================================================
// CONFIGURACIÓN E INICIO DEL RTOS
// =======================================================
int main(void) {
    SystemClock_Config();
    osKernelInitialize();
    
    // ATRIBUTOS (¡Notar el cambio radical de prioridades!)
    const osThreadAttr_t attr_valvula = {
        .name = "ValveTask",
        .stack_size = 512,
        .priority = osPriorityRealtime, // MÁXIMA AUTORIDAD (Solo reservado para la vida y la muerte)
    };
    
    const osThreadAttr_t attr_pantalla = {
        .name = "LCDTask",
        .stack_size = 1024,
        .priority = osPriorityNormal,   // Tarea estándar de rutina
    };
    
    const osThreadAttr_t attr_wifi = {
        .name = "WiFiTask",
        .stack_size = 2048,
        .priority = osPriorityLow,      // Esclavo del sistema. Solo come las sobras de la CPU.
    };
    
    // CREACIÓN
    osThreadNew(Thread_Seguridad_Valvula, NULL, &attr_valvula);
    osThreadNew(Thread_Pantalla_LCD, NULL, &attr_pantalla);
    osThreadNew(Thread_WiFi_Cloud, NULL, &attr_wifi);
    
    osKernelStart();
    while (1);
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Garantía de Plazos de Ejecución (Deadlines) en Misiones Críticas.

En el mundo real del despacho de Gas LP, estás cobrando dinero por mililitro de gas inyectado. Si un cliente pide $500 pesos de carga y tu máquina despacha $502 pesos porque tardó 3 milisegundos extra en reaccionar, tú tienes que pagar la diferencia de tu bolsillo. Al multiplicar esto por miles de cargas al día, la empresa quiebra.

Al aplicar **Jerarquía Estricta de Prioridades**, has blindado financieramente (y en seguridad) a tu máquina. Le otorgaste a la Tarea de la Válvula la jerarquía `osPriorityRealtime`. No importa si el chip WiFi ESP32 está colgado enviando megabytes a AWS, o si la pantalla a color está redibujando gráficos complejos; en el microsegundo que la Metrología detecta que llegamos al límite de $500 pesos, el Kernel de FreeRTOS aplastará al WiFi y a la Pantalla, le dará el procesador al módulo de la válvula y cerrará el flujo de gas. Esto no es solo código C; es ingeniería legal y metrológica en acción.

📝 Resumen del Día