DÍA 196 DE 365

Fase 4: FreeRTOS y Conectividad IoT

📖 Teoría a Estudiar

El Pecado de la Memoria Dinámica (Heap)

Cuando utilizas la creación dinámica (el comportamiento por defecto), le dices al RTOS: "Crea una tarea, por favor búscame 1KB de RAM libre donde sea que haya espacio". El RTOS revisa su piscina de memoria (Heap), encuentra un pedazo, lo recorta y te lo da.

A lo largo de los meses, si el sistema crea y destruye colas, tareas temporales o conexiones TCP (WiFi), el Heap se llena de huecos. Llega un momento en que tienes 5KB libres en total, pero están divididos en fragmentos de 100 bytes separados. Si intentas crear una Cola que necesita 512 bytes continuos, el RTOS fallará y tu programa crasheará (Out Of Memory).

Asignación Estática (BSS / Data Segment)

La Asignación Estática cambia la narrativa. Tú, como Arquitecto, defines globalmente los arreglos exactos que el RTOS va a usar. Escribes algo como uint8_t stack_metrologia[1024];. El compilador de GCC, en el momento de generar el binario (antes de que la máquina se encienda), asigna esa memoria permanentemente. Nunca se crea, nunca se destruye, y su dirección en la RAM jamás cambia.

Esto garantiza Determinismo de Memoria (100%). Si tu programa compila y el enlazador (Linker) no marca error de RAM excedida, entonces es matemáticamente imposible que la máquina se quede sin memoria mientras esté operando en campo.

MODELOS DE ASIGNACIÓN: DINÁMICO (HEAP) VS ESTÁTICO Dinámico (osThreadNew clásico) Riesgo: Fragmentación a largo plazo RTOS Heap Pool (Ej. 30 KB) Task A Stack (En uso) Basura / Hueco (Liberado) Task B Stack (En uso) Basura / Hueco (Liberado) Queue Buf (En uso) NUEVA TAREA REQUIERE 40 ALTURA Hay 40 libres total, pero no contiguos. CRASH. Estático (.bss / Variables Globales) Garantía: Determinismo 100% RAM del STM32 (Al Compilar) uint8_t stack_A[1024]; uint8_t stack_B[2048]; uint8_t queue_buf[512]; (Resto de la RAM libre) ESPACIO INMUTABLE Y FIJO El compilador verificó que cupiera todo. 0 fallas.

⚙️ Ejercicios Prácticos

Ejercicio 1: Para usar memoria estática en FreeRTOS, primero debemos ir a nuestro panel de control `FreeRTOSConfig.h` y asegurar que la macro configSUPPORT_STATIC_ALLOCATION esté en 1. Luego, utilizando CMSIS-OS v2, llenaremos las estructuras de atributos apuntando físicamente a nuestros arreglos previamente creados, prohibiendo al RTOS que use su Heap dinámico interno.

1. Habilitación en FreeRTOSConfig.h


// Desactiva la asignación dinámica por completo para cumplir norma aeronáutica/SIL
#define configSUPPORT_DYNAMIC_ALLOCATION        0

// Activa la asignación estática obligatoria
#define configSUPPORT_STATIC_ALLOCATION         1
        

2. Creación Estática Segura en main.c


/**
 * @file alloc_estatica_rtos.c
 * @brief Implementación de Hilos sin Memoria Dinámica (Certificable SIL-3)
 */

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

// =======================================================
// 1. DECLARACIÓN ESTÁTICA GLOBAL DE MEMORIA (Sección .bss)
// El compilador reserva estos bytes exactamente aquí, para siempre.
// =======================================================

// A) Memoria para la Tarea de Metrología
#define STACK_SIZE_METRO 1024 // Bytes
uint8_t memory_stack_metro[STACK_SIZE_METRO];     // El Pila de la tarea
osThreadCb_t control_block_metro;                 // El "TCB" (Cerebro de la tarea)

// B) Memoria para la Cola de Mensajes (Ej. 10 mensajes de 8 bytes)
#define MSG_COUNT 10
#define MSG_SIZE 8
uint8_t memory_buffer_cola[MSG_COUNT * MSG_SIZE]; // El tubo de los mensajes
osMessageQueueCb_t control_block_cola;            // El Control Block de la Cola

// =======================================================
// 2. CONFIGURACIÓN DE ATRIBUTOS PARA CMSIS-OS V2
// =======================================================

const osThreadAttr_t attr_tarea_metro = {
    .name = "Metro_Task",
    .cb_mem = &control_block_metro,               // Le decimos: "Usa mi TCB estático"
    .cb_size = sizeof(control_block_metro),
    .stack_mem = &memory_stack_metro[0],          // Le decimos: "Usa mi RAM estática"
    .stack_size = sizeof(memory_stack_metro),
    .priority = osPriorityHigh
};

const osMessageQueueAttr_t attr_cola_comandos = {
    .name = "Cmd_Queue",
    .cb_mem = &control_block_cola,
    .cb_size = sizeof(control_block_cola),
    .mq_mem = &memory_buffer_cola[0],
    .mq_size = sizeof(memory_buffer_cola)
};

// =======================================================
// LA TAREA (Idéntica, el código no se entera de cómo fue creada)
// =======================================================
void Thread_Metrologia(void *argument) {
    for (;;) {
        // Código de despacho de Gas...
        osDelay(10);
    }
}

// =======================================================
// INICIALIZACIÓN
// =======================================================
int main(void) {
    SystemClock_Config();
    osKernelInitialize();
    
    // Al usar 'New' con atributos estáticos bien definidos, 
    // CMSIS-OS / FreeRTOS sabe que NO debe usar malloc() internamente.
    // Simplemente "amarra" sus punteros a nuestras variables globales.
    
    osMessageQueueId_t mi_cola = osMessageQueueNew(MSG_COUNT, MSG_SIZE, &attr_cola_comandos);
    osThreadId_t mi_hilo = osThreadNew(Thread_Metrologia, NULL, &attr_tarea_metro);
    
    osKernelStart();
    while (1);
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Cumplimiento de Normativa MISRA-C y Tolerancia a Fallos a Largo Plazo.

Tu Despachador de Gas LP no es un teléfono celular que la gente reinicia cuando se pone "lento". Es infraestructura industrial crítica que se atornilla al suelo de una estación de servicio y opera ininterrumpidamente bajo el sol y la lluvia durante años. Si el software se fragmenta y sufre un *Out of Memory* mientras una válvula de presión está abierta, las consecuencias son devastadoras.

Al migrar la arquitectura completa del RTOS a **Asignación Estática (Static Allocation)**, has superado uno de los requisitos más severos de las certificaciones de software seguro (como IEC 61508 SIL-3 o la normativa automotriz ISO 26262). Le demostraste al compilador exactamente cada byte de memoria que el sistema utilizará. Si te excedes de los 96 KB del STM32, el error saltará *ahora mismo* en tu computadora durante la compilación, y no dentro de 6 meses a las 3 de la mañana en una gasolinera. Has convertido el firmware de un programa probabilístico a una entidad matemáticamente determinista.

📝 Resumen del Día