DÍA 228 DE 365

Fase 4: FreeRTOS y Conectividad IoT

📖 Teoría a Estudiar

El Colapso de Silicio y el Watchdog Físico (OOB)

Un Watchdog de software interno (WDT) solo sirve si el RTOS sigue respirando. Pero cuando ocurre un evento de interferencia electromagnética severa (como el chispazo del relé del motor de la bomba de Gas LP), el procesador ESP32 puede entrar en una condición de enganche físico (Latch-up). En este estado, ninguna línea de código puede salvarlo porque la CPU entera está detenida. La única cura es cortar el flujo eléctrico físico o tirar a tierra (GND) el pin de reseteo.

Control Fuera de Banda (Out-of-Band Management)

Para solucionar esto, usaremos nuestro procesador maestro (STM32). El STM32 implementará un **Interrogador Cíclico (Ping Binario)**. Cada 10 segundos enviará por UART un comando especial `CMD_ARE_YOU_ALIVE` al ESP32. El ESP32 tiene la obligación de responder `CMD_ACK` en menos de 500 ms.

Si el STM32 detecta 3 fallos consecutivos (Timeouts), declarará legalmente muerto al módulo WiFi. En ese instante, el STM32 activará un pin de salida digital (GPIO) conectado directamente al pin EN (Enable/Reset) del ESP32, tirándolo a 0 Voltios durante 100 milisegundos. Esta acción física purga los capacitores y reinicia a la fuerza el cerebro del módulo, forzando una reconexión fresca a internet.

ARQUITECTURA DE RESURRECCIÓN DE HARDWARE (OOB RESET) STM32F401 (Cortex-M4) Supervisor Metrológico Task_ESP_Watchdog Ping: TX UART Fallas = 3 (TIMEOUT!) ESP32 (Coprocesador) Módulo IoT (WiFi/MQTT) KERNEL PANIC Ruido EMI generó HardFault (CPU Detenida) CMD_ARE_YOU_ALIVE X NO HAY RESPUESTA X GPIO_PIN_5 (RESET LINE) -> 0 Volts (GND) EN El pin "Enable" apagará y encenderá el hardware del ESP

⚙️ Ejercicios Prácticos

Circuito Electrónico: Debes conectar un pin de salida digital de tu STM32 (Por ejemplo, PA5) al pin marcado como EN o RST de tu módulo ESP32. Es altamente recomendable colocar una resistencia Pull-Up de 10k ohmios entre el pin EN y la línea de 3.3V, y un capacitor de 1uF entre EN y Tierra (GND). El capacitor absorberá micro-ruidos, y la línea del STM32 solo bajará el voltaje cuando nosotros explícitamente apliquemos un GPIO_PIN_RESET.

Ejercicio 1: Escribiremos la tarea de supervisión en el lenguaje C Bare-Metal/RTOS de nuestro maestro STM32. Utilizaremos el protocolo binario del Día 222 para sondear la vitalidad del coprocesador.


/**
 * @file esp32_watchdog.c
 * @brief Rutina de Recuperación Física de Coprocesador IoT desde STM32
 */

#include "stm32f401xe.h"
#include "cmsis_os2.h"
#include "protocolo_iot.h" // Nuestra trama del Día 222

// Pines de control físico (Out-of-Band Management)
#define ESP32_EN_PORT   GPIOA
#define ESP32_EN_PIN    GPIO_PIN_5

extern UART_HandleTypeDef huart1;
extern osEventFlagsId_t uart_rx_flags_id;
#define FLAG_ESP_ALIVE  (1U << 1) // Levantada por la ISR del UART cuando recibe CMD_ACK

// =======================================================
// RUTINA DE DESFIBRILACIÓN DE HARDWARE (HARD RESET)
// =======================================================
/**
 * @brief Ejecuta una purga de capacitores y reinicio forzado del silicio del ESP32
 */
void ESP32_Ejecutar_Hardware_Reset(void) {
    UART_Enviar_String("[WATCHDOG] ESP32 declarado MUERTO. Iniciando Resurrección...\r\n");
    
    // 1. Tirar el pin EN a Tierra (0V). El ESP32 se apaga físicamente al instante.
    HAL_GPIO_WritePin(ESP32_EN_PORT, ESP32_EN_PIN, GPIO_PIN_RESET);
    
    // 2. Esperar 100ms. Este tiempo es CRÍTICO para que los capacitores internos 
    // del módulo ESP32 se descarguen por completo y la memoria RAM se limpie.
    osDelay(100); 
    
    // 3. Restaurar el voltaje a 3.3V. El ESP32 comienza su secuencia de Boot (Arranque).
    HAL_GPIO_WritePin(ESP32_EN_PORT, ESP32_EN_PIN, GPIO_PIN_SET);
    
    UART_Enviar_String("[WATCHDOG] Voltaje restaurado. Esperando Boot del ESP32...\r\n");
    
    // 4. Darle tiempo al RTOS del ESP-IDF para inicializar y abrir su puerto UART.
    osDelay(3000); // 3 segundos de gracia
    
    UART_Enviar_String("[WATCHDOG] Coprocesador reiniciado. Reanudando operaciones.\r\n");
}

// =======================================================
// TAREA DEL STM32: EL SUPERVISOR INCANSABLE
// =======================================================
void Task_ESP_Watchdog(void *argument) {
    
    uint8_t contador_fallos = 0;
    const uint8_t MAXIMAS_FALLAS_PERMITIDAS = 3;
    
    // Trama Binaria a enviar (Ping de vida)
    Trama_Binaria_t ping_trama;
    ping_trama.header.sync_word = FRAME_SYNC_WORD;
    ping_trama.header.longitud  = 0; // Sin payload
    ping_trama.header.comando   = CMD_ARE_YOU_ALIVE;
    ping_trama.crc8             = Calcular_CRC8((uint8_t*)&ping_trama, sizeof(Trama_Header_t));
    
    for (;;) {
        // 1. Limpiamos la bandera de respuestas anteriores
        osEventFlagsClear(uart_rx_flags_id, FLAG_ESP_ALIVE);
        
        // 2. Disparamos el Ping hacia el ESP32
        HAL_UART_Transmit(&huart1, (uint8_t*)&ping_trama, sizeof(Trama_Header_t) + 1, 100);
        
        // 3. Esperamos la respuesta asíncrona del ESP32 (El ACK)
        // Le damos exactamente 500 milisegundos para responder.
        uint32_t resultado = osEventFlagsWait(uart_rx_flags_id, FLAG_ESP_ALIVE, osFlagsWaitAny, 500);
        
        if (resultado == (uint32_t)osErrorTimeout) {
            
            // ¡FALLO! El ESP32 no respondió. 
            contador_fallos++;
            char msg[64];
            snprintf(msg, sizeof(msg), "[WATCHDOG] Alerta: ESP32 Mudo. Falla %d/%d\r\n", 
                     contador_fallos, MAXIMAS_FALLAS_PERMITIDAS);
            UART_Enviar_String(msg);
            
            if (contador_fallos >= MAXIMAS_FALLAS_PERMITIDAS) {
                // Terapia de Shock
                ESP32_Ejecutar_Hardware_Reset();
                contador_fallos = 0; // Borrón y cuenta nueva
            }
            
        } else {
            // ¡Éxito! El ESP32 respondió su ACK. Está sano y procesando.
            contador_fallos = 0; // Reiniciamos el contador de tolerancia
        }
        
        // 4. El STM32 interroga la salud del WiFi cada 10 segundos
        osDelay(10000); 
    }
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Alta Disponibilidad (High Availability) y Tolerancia a Fallos Electromagnéticos (EMI).

Las estaciones de Gas LP son entornos eléctricamente ruidosos. Los motores de bombeo masivo generan arcos eléctricos y picos inductivos que viajan por el aire. Ningún diseño de PCB es mágicamente inmune al 100% de los cuelgues del silicio inducidos por el ruido electromagnético. Si tu máquina de Gas LP se congela y pierde conexión con la Nube, la gasolinera tendría que llamar a un técnico para que viaje una hora en tráfico, abra el gabinete y presione un miserable botón de Reset manual. Tu empresa perdería reputación y dinero.

Al diseñar el **Hardware Watchdog Out-of-Band**, tu Despachador de Gas se ha vuelto autocurativo (Self-Healing). El STM32, protegido por su propio chasis lógico, actúa como el supervisor del módulo IoT. Si un pico de voltaje "asfixia" al ESP32 y detiene su FreeRTOS interno, el STM32 se dará cuenta a los 30 segundos (3 fallos x 10 segundos). Con precisión clínica, cortará la corriente al pin `EN`, resucitando al módulo de comunicaciones sin que el despachador deje de medir ni una sola gota de gas (ya que el STM32 no se reinicia, solo reinicia a su esclavo). Este pequeño circuito y línea de código reduce las visitas físicas de mantenimiento (Truck Rolls) en más de un 80% en despliegues a nivel nacional.

📝 Resumen del Día