DÍA 197 DE 365

Fase 4: FreeRTOS y Conectividad IoT

📖 Teoría a Estudiar

El Secreto del Stack: ¿Cómo mide FreeRTOS la memoria?

Cuando creas una tarea (Hilo) y le asignas 1,000 bytes de Stack, esos bytes inician llenos de "basura" remanente en la RAM. FreeRTOS, al crear la tarea, aplica un truco brillante: Pinta cada uno de esos 1,000 bytes con un patrón conocido, usualmente 0xA5 (10100101 en binario).

A medida que tu tarea se ejecuta, llama a funciones, crea variables locales (como int x = 5;) y guarda los registros de la CPU durante los Cambios de Contexto. Todo esto consume bytes, borrando el patrón 0xA5 desde abajo hacia arriba (o de arriba hacia abajo, dependiendo del procesador).

La Marca de Inundación (High Water Mark)

La "Marca de Agua Máxima" es un término que viene de las inundaciones en las ciudades; es la mancha de humedad que queda en la pared y que indica lo más alto que llegó el agua, incluso si la inundación ya bajó. En FreeRTOS, la función uxTaskGetStackHighWaterMark() empieza a leer el Stack desde el final hacia el principio, contando cuántos bytes conservan el patrón 0xA5 sin tocar. Ese número representa el mínimo espacio libre histórico de tu tarea.

En **CMSIS-OS v2**, esta funcionalidad se abstrae elegantemente mediante la función osThreadGetStackSpace(), que te devuelve directamente los bytes de salvavidas que le quedan a tu tarea.

ANATOMÍA DE UNA PILA (STACK) Y SU MARCA DE AGUA Top (Ej. 0x20001000) Base (Ej. 0x20000C00) 0xA5 0xA5 0xA5 0xA5 0xA5 0xA5 0xA5 0xA5 0xA5 0xA5 0xA5 0xA5 0xA5 0xA5 0xA5 Memoria Virgen (Intacta) MARCA DE INUNDACIÓN (osThreadGetStackSpace) Zona Fantasma (Se usó en el pasado, el patrón 0xA5 se borró) Stack Pointer Actual → Variables Locales (float, int) Registros de Context Switch Llamadas a Funciones (Nesting) Free Space (Devuelto) (Ej. 120 Bytes Seguros)

⚙️ Ejercicios Prácticos

Ejercicio 1: Vamos a programar una "Tarea Auditora". Su único trabajo será despertar cada 10 segundos, medir la memoria sobrante de las demás tareas (usando el identificador osThreadId_t que guardamos al crearlas) e imprimir esa información por el puerto serial (UART). Si una tarea tiene un remanente menor a 64 bytes, lanzaremos una advertencia de peligro de desbordamiento.

1. Habilitar la función en FreeRTOSConfig.h

Para que CMSIS-OS v2 pueda leer esta información, debemos asegurarnos de encender el módulo de Watermark en la configuración base del Kernel:


#define INCLUDE_uxTaskGetStackHighWaterMark   1
        

2. El Código de la Tarea Auditora en main.c


/**
 * @file monitor_memoria_rtos.c
 * @brief Auditoría en tiempo real de uso de Stack mediante CMSIS-OS v2
 */

#include "stm32f401xe.h"
#include "cmsis_os2.h"
#include <stdio.h>

// IDs globales para poder ser inspeccionados
osThreadId_t hilo_metro_id;
osThreadId_t hilo_wifi_id;
osThreadId_t hilo_pantalla_id;

// =======================================================
// LA TAREA AUDITORA (Prioridad Baja)
// =======================================================
void Thread_Auditor_Memoria(void *argument) {
    
    char buffer_uart[128];
    uint32_t espacio_libre;
    
    // Esperamos 5 segundos para dejar que el sistema "caliente" y 
    // las tareas lleguen a su punto máximo de estrés matemático.
    osDelay(5000);
    
    for (;;) {
        // 1. Revisar Metrología
        espacio_libre = osThreadGetStackSpace(hilo_metro_id);
        snprintf(buffer_uart, sizeof(buffer_uart), "[MEM] Metrologia: %lu bytes libres\r\n", espacio_libre);
        UART_Enviar_String(buffer_uart);
        
        // 2. Revisar WiFi
        espacio_libre = osThreadGetStackSpace(hilo_wifi_id);
        snprintf(buffer_uart, sizeof(buffer_uart), "[MEM] WiFi IoT  : %lu bytes libres\r\n", espacio_libre);
        UART_Enviar_String(buffer_uart);
        
        // 3. Revisar Pantalla UI
        espacio_libre = osThreadGetStackSpace(hilo_pantalla_id);
        snprintf(buffer_uart, sizeof(buffer_uart), "[MEM] Pantalla  : %lu bytes libres\r\n", espacio_libre);
        UART_Enviar_String(buffer_uart);
        
        // Lógica de Alarma: Si algún hilo tiene menos de 64 bytes de "salvavidas"
        if (espacio_libre < 64) {
            UART_Enviar_String("--- ALARMA: RIESGO DE STACK OVERFLOW ---\r\n");
            // Aquí en la fase de desarrollo, ajustaríamos los arreglos estáticos del Día 196
        }
        
        UART_Enviar_String("----------------------------------\r\n");
        
        // Revisar cada 10 segundos
        osDelay(10000); 
    }
}

// Tareas de Aplicación Simples
void Thread_Dummy(void *argument) {
    // Si metes un arreglo inmenso aquí, destrozarás el Stack
    // char buffer_gigante[2000]; -> ¡ESTO CAUSARÁ HARDFAULT INMEDIATO!
    for(;;) { osDelay(100); }
}

// =======================================================
// INICIALIZACIÓN
// =======================================================
int main(void) {
    SystemClock_Config();
    osKernelInitialize();
    
    // Creamos las tareas y guardamos estrictamente sus IDs
    hilo_metro_id    = osThreadNew(Thread_Dummy, NULL, &attr_metro);
    hilo_wifi_id     = osThreadNew(Thread_Dummy, NULL, &attr_wifi);
    hilo_pantalla_id = osThreadNew(Thread_Dummy, NULL, &attr_pantalla);
    
    // Creamos el Auditor con prioridad Baja (No debe robar CPU a la operación)
    osThreadNew(Thread_Auditor_Memoria, NULL, NULL);
    
    osKernelStart();
    while (1);
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Sintonía Fina de Memoria RAM para Certificación.

Ayer reservamos arreglos estáticos de memoria para tu máquina. A la Pantalla a Color le dimos 4096 bytes, a la Metrología 1024 bytes y al WiFi 2048 bytes. Pero el STM32F401 tiene un límite rígido de 96 KB totales. Para tu tesis, debes justificar matemáticamente por qué asignaste esos tamaños.

Al implementar el **Hilo Auditor de Memoria (Watermark)** durante la fase de validación de tu proyecto, hiciste un descubrimiento empírico: Al imprimir los resultados por el puerto UART, notaste que la Tarea de Metrología jamás bajaba de 800 bytes libres (solo usaba ~224 bytes para sus matemáticas de control PID). En cambio, la Tarea WiFi mostraba una alerta roja: solo le quedaban 16 bytes libres cuando el chip ESP32 procesaba un JSON muy largo. Gracias a esta auditoría en vivo, pudiste regresar al archivo de configuración estática (del Día 196) y transferir 512 bytes de la Metrología hacia el WiFi. Has balanceado el peso de tu arquitectura a ciegas, logrando un sistema que aprovecha el 100% de la RAM disponible sin riesgo de colapsos (HardFaults).

📝 Resumen del Día