DÍA 110 DE 365

Fase 2: Fundamentos de Hardware y Electrónica

📖 Teoría a Estudiar

El Perro Guardián de Ventana (WWDG)

A diferencia del IWDG, el WWDG funciona con el reloj principal del sistema (Bus APB1). Esto significa que está atado a la salud del cristal de cuarzo y al PLL. Su propósito no es salvarnos de un fallo total de hardware, sino auditar la exactitud temporal de nuestro código.

El WWDG tiene un contador descendente de 7 bits (valores de 0x7F a 0x40). Para que el sistema funcione normalmente, debes recargar ("patear") el contador solo cuando su valor haya caído por debajo de un umbral que tú configuras, llamado Ventana (Window Value), pero antes de que alcance el fatídico valor de 0x3F.

El Truco del Bit T6

El hardware de STMicroelectronics implementó esto de manera brillante usando matemáticas binarias simples. El bit número 6 del contador (T6) vale 64 (que en hexadecimal es 0x40). Mientras el contador esté entre 0x7F (127) y 0x40 (64), el bit T6 es '1'. En el instante en que la cuenta baja a 0x3F (63), el bit T6 pasa a '0'. El hardware vigila este único bit: si pasa a 0, activa el pin físico de RESET.

ZONAS DE OPERACIÓN DEL WWDG (WINDOW WATCHDOG) 0x7F (127) ZONA PROHIBIDA: REINICIO (Pateaste muy temprano) 0x5F (95) Valor de Ventana (W) ZONA SEGURA: ¡Aquí debes patear al perro! 0x3F (63) Bit T6 = 0 (RESET) ZONA DE REINICIO (Pateaste muy tarde) KICK! KICK OK (Recarga a 0x7F)

Interrupción de Despertar Temprano (EWI)

El WWDG tiene una característica espectacular llamada **EWI (Early Wakeup Interrupt)**. Justo antes de que el contador llegue a `0x3F` (específicamente al llegar a `0x40`), dispara una interrupción de altísima prioridad. Esto te da unos microsegundos críticos para escribir "¡FALLO DE SOFTWARE!" en la memoria EEPROM y cerrar las válvulas justo antes de que el procesador muera reiniciado.

⚙️ Ejercicios Prácticos

Ejercicio 1: Asumiendo un reloj APB1 de 42MHz, configuralo para que la ventana segura se abra después de ~25 milisegundos y el reset ineludible ocurra a los ~50 milisegundos. Escribe la rutina para "patear" al perro correctamente.


/**
 * @file wwdg_driver.c
 * @brief Driver Bare-Metal para el Window Watchdog Timer
 */

#include "stm32f401xe.h"
#include "valve_driver.h" // Para cerrar válvulas en emergencia

// Valores calculados para una ventana entre ~25ms y ~50ms (APB1 = 42MHz)
#define VALOR_RECARGA  0x7F  // 127 (Máximo valor permitido)
#define VALOR_VENTANA  0x5F  // 95 (La ventana segura abre debajo de este número)

void inicializar_perro_ventana(void) {
    
    // 1. Habilitar reloj del WWDG en el bus APB1
    RCC->APB1ENR |= RCC_APB1ENR_WWDGEN;
    
    // 2. Configurar el Registro de Configuración (CFR)
    // - Limpiamos configuración previa
    WWDG->CFR &= ~(WWDG_CFR_WDGTB | WWDG_CFR_W | WWDG_CFR_EWI);
    
    // - Configurar Prescaler: WDGTB = 11 (Divisor /8)
    WWDG->CFR |= (3 << WWDG_CFR_WDGTB_Pos);
    
    // - Asignar valor de la ventana (0x5F)
    WWDG->CFR |= (VALOR_VENTANA & WWDG_CFR_W);
    
    // - Habilitar Interrupción de Despertar Temprano (Early Wakeup)
    WWDG->CFR |= WWDG_CFR_EWI;
    NVIC_SetPriority(WWDG_IRQn, 0); // Prioridad ineludible
    NVIC_EnableIRQ(WWDG_IRQn);
    
    // 3. Arrancar y Cargar primer valor
    // El bit WDGA (bit 7) enciende el módulo, y los bits [6:0] cargan el tiempo
    WWDG->CR = WWDG_CR_WDGA | VALOR_RECARGA;
}

// Función estricta para refrescar al WWDG
void refrescar_wwdg(void) {
    // IMPORTANTE: Escribir en el registro CR cuando el contador es MAYOR 
    // al valor de la ventana causará un RESET inmediato por hardware.
    // Nosotros solo recargamos a 0x7F, pero debemos asegurarnos de llamar
    // a esta función en el momento matemático correcto.
    WWDG->CR = VALOR_RECARGA;
}

// --- INTERRUPCIÓN DE MUERTE INMINENTE (LAST WORDS) ---
void WWDG_IRQHandler(void) {
    
    // Entramos aquí si el contador bajó a 0x40. 
    // ¡En el próximo ciclo de reloj del WWDG (0x3F), la máquina morirá!
    
    // 1. Limpiar bandera
    WWDG->SR &= ~WWDG_SR_EWIF;
    
    // 2. ACCIÓN DE EMERGENCIA CIBERFÍSICA
    VALVULA_OFF();
    
    // 3. Guardar estado de error en RAM estática o EEPROM I2C
    // eeprom_write(DIR_ERROR, ERROR_WWDG_TIMEOUT);
    
    // (El microcontrolador se reiniciará violentamente tras salir de aquí)
}

int main(void) {
    
    inicializar_perro_ventana();
    
    uint32_t tiempo_previo = 0;
    extern volatile uint32_t milisegundos_globales; // Del SysTick (Día 98)
    
    while(1) {
        
        // Nuestro bucle de control crítico.
        // Simulamos tareas que toman tiempo.
        // ejecutar_lecturas();
        
        // REFRESCAR WWDG: Solo dentro de la ventana de 25ms a 50ms
        uint32_t delta_tiempo = milisegundos_globales - tiempo_previo;
        
        if (delta_tiempo > 30 && delta_tiempo < 45) {
            refrescar_wwdg();
            tiempo_previo = milisegundos_globales;
        }
        
        // Si otra tarea bloquea el bucle y delta_tiempo sube a 50... ¡RESET!
        // Si un bug corrompe el bucle y esto corre antes de 25ms... ¡RESET!
    }
    
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Sincronización Estricta del Protocolo Modbus RTU.

La red Modbus que utilizará tu despachador para comunicarse con la computadora de la oficina central (a través de RS485) es implacable con el tiempo. El estándar Modbus dicta que el silencio entre tramas de datos no debe exceder los 3.5 caracteres de tiempo.

Si tu bucle principal se ejecuta demasiado lento (asfixiando al UART) o demasiado rápido (leyendo basura en la línea antes de tiempo), la comunicación colapsará. Al vincular el bucle de procesamiento del protocolo Modbus con el **WWDG**, el hardware mismo audita que la lectura de paquetes y la lógica del Despachador tomen exactamente el tiempo estipulado (entre 25ms y 50ms). Si el flujo del programa se altera por cualquier fallo electromagnético, el WWDG_IRQHandler cierra la válvula físicamente y fuerza un reinicio seguro para recuperar la comunicación. Esto es arquitectura de software verdaderamente robusta.

📝 Resumen del Día