DÍA 191 DE 365

Fase 4: FreeRTOS y Conectividad IoT

📖 Teoría a Estudiar

El Triángulo Mortal de la Inversión de Prioridad

Imagina que tienes tres tareas en tu Despachador de Gas LP:

Ahora, visualiza este escenario catastrófico:

  1. La Tarea L (Baja) adquiere el Mutex del bus I2C para escribir un log en la EEPROM.
  2. Mientras la Tarea L está usando el I2C, la Tarea H (Alta) se dispara por una emergencia y necesita la CPU de inmediato. El RTOS expropia (preempts) a la Tarea L y le da la CPU a la Tarea H.
  3. La Tarea H intenta leer un sensor por I2C y llama a osMutexAcquire(). Pero el candado lo tiene la Tarea L. Como está ocupado, la Tarea H es puesta en estado BLOCKED.
  4. Hasta aquí, todo normal. Pero en ese preciso instante, la Tarea M (Normal) se despierta para actualizar la pantalla LCD. Como la Tarea M tiene mayor prioridad que la Tarea L (y la Tarea H está bloqueada esperando el candado), **¡el RTOS le da la CPU a la Tarea M!**
  5. La Tarea M se pone a parpadear la pantalla alegremente y puede durar ahí todo el tiempo que quiera. La Tarea L jamás vuelve a recibir ciclos de CPU porque la Tarea M la está bloqueando. Y como la Tarea L no tiene CPU, no puede terminar su trabajo de I2C, lo que significa que **la Tarea H (la más importante del sistema) se queda bloqueada indefinidamente**.

¡Una tarea de prioridad baja terminó bloqueando a una tarea de prioridad alta a través de una tarea de prioridad media! A esto se le conoce como Inversión de Prioridad.

La Solución: Herencia de Prioridad (Priority Inheritance)

Para solucionar este defecto lógico, los creadores de FreeRTOS implementaron el algoritmo de Herencia de Prioridad. Cuando activas esta propiedad al crear un Mutex, el Kernel hace lo siguiente:

En el momento exacto en que la Tarea H (Alta) intenta tomar un Mutex que está retenido por la Tarea L (Baja), el RTOS **eleva temporalmente la prioridad de la Tarea L** para que coincida con la prioridad de la Tarea H.

Como la Tarea L ahora tiene la máxima prioridad del sistema, la Tarea M (Normal) ya no puede interrumpirla. La Tarea L termina su transacción de I2C a toda velocidad, libera el Mutex, y en ese instante su prioridad regresa a la normalidad. La Tarea H toma el candado y salva el día. El orden del universo se restaura.

MECANISMO DE HERENCIA DE PRIORIDAD EN UN MUTEX Task H (Alta) Task M (Normal) Task L (Baja) Toma Mutex Despierta Falla al tomar Mutex Task H -> BLOCKED HERENCIA DE PRIORIDAD: Task L sube a nivel de Task H! Termina I2C rápido Task M bloqueada Libera Task H toma CPU y actúa

⚙️ Ejercicios Prácticos

Ejercicio 1: Configuración del Mutex con Herencia en CMSIS-OS v2. Veremos cómo la macro `osMutexPrioInherit` le indica al Kernel de FreeRTOS que administre automáticamente los aumentos de prioridad ante colisiones de recursos físicos.


/**
 * @file priority_inheritance.c
 * @brief Creación segura de un Mutex con Herencia de Prioridad en FreeRTOS
 */

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

// ID Global del Mutex Protegido
osMutexId_t mutex_i2c_seguro;

void Sistema_Init_Mutexes(void) {
    
    // Atributos del Mutex
    const osMutexAttr_t mutex_attributes = {
        .name = "I2C_Protected_Mutex",
        
        // ===================================================================
        // LA LÍNEA MÁGICA: Activa la Herencia de Prioridad
        // ===================================================================
        // Si no colocas esto, estás usando un Mutex básico plano propenso 
        // a bloqueos mortales por Inversión de Prioridad.
        .attr_bits = osMutexPrioInherit 
    };
    
    // Crear el Mutex utilizando el estándar CMSIS-OS v2
    mutex_i2c_seguro = osMutexNew(&mutex_attributes);
    
    if (mutex_i2c_seguro == NULL) {
        // Error crítico: No hay suficiente RAM en el Heap del RTOS para el Mutex
        Error_Handler();
    }
}

// Ejemplo de uso dentro de una tarea de Baja Prioridad
void Thread_Mantenimiento_EEPROM(void *argument) {
    for (;;) {
        // Al adquirir este Mutex, si la Tarea de Seguridad (Alta Prioridad) 
        // lo llega a necesitar mientras nosotros lo tenemos, el RTOS elevará 
        // nuestra prioridad instantáneamente para sacarnos de la CPU rápido.
        osMutexAcquire(mutex_i2c_seguro, osWaitForever);
        
        Escribir_Log_Lento_En_EEPROM(); // Sección crítica
        
        osMutexRelease(mutex_i2c_seguro);
        
        osDelay(10000);
    }
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Blindaje Definitivo contra Bloqueos Sistémicos en Concurrencia.

Has equipado a tu Despachador de Gas LP con la más alta sofisticación conceptual de los sistemas operativos en tiempo real. En la industria, hay sistemas que fallan inexplicablemente cada 30 días sin dejar rastro en los registros (Logs); la causa raíz suele ser una Inversión de Prioridad no resuelta donde una tarea de fondo estrangula a una tarea de seguridad.

Al configurar sistemáticamente todos tus Mutexes con la propiedad **osMutexPrioInherit**, has dotado a FreeRTOS de la capacidad de autodefensa matemática. Tu máquina de despacho maneja la pantalla, el WiFi, la EEPROM y las válvulas PID de manera concurrente, sabiendo que si los hilos compiten por el hardware, el Kernel reorganizará la jerarquía al vuelo para asegurar que los procesos de vida o muerte jamás sufran retrasos. Tu arquitectura ha alcanzado la madurez industrial total.

📝 Resumen del Día