DÍA 054 DE 365

Fase 1: Fundamentos de C y Lógica de Software

📖 Teoría a Estudiar

El Fault Handler y la Rutina de Estado Seguro

En el software de escritorio, si un puntero accede a memoria inválida o divides entre cero, el programa se cierra (Crash) y ves un mensaje de error en Windows. En un microcontrolador bare-metal, no hay sistema operativo que cierre la aplicación. Cuando la CPU (como el ARM Cortex-M del STM32) detecta un error fatal, aborta la ejecución normal y salta a una interrupción especial de máxima prioridad llamada HardFault_Handler.

El código generado automáticamente por las herramientas (como STM32CubeIDE) implementa el HardFault_Handler como un bucle infinito vacío (while(1);). Esto es inaceptable en la industria. Si el microcontrolador se congela en ese bucle mientras los pines que controlan válvulas y motores estaban en estado ALTO (ON), el hardware físico se quedará encendido para siempre. La solución es inyectar una Rutina de Estado Seguro (Safe State Routine) dentro del manejador de fallos.

SÚPER BUCLE Válvula = ON ERROR FATAL (Ej. Stack Overflow) HardFault_Handler() Excepción de Hardware SAFE STATE ROUTINE 1. Acceso Directo a Registros 2. Válvula = OFF, Bomba = OFF 3. Guardar código de error en Flash while(1) { Esperar Watchdog } SIN SAFE STATE: El actuador sigue activo.

Los Pasos del Diseño Seguro

  1. Sobrescribir el Handler: Localizar la función HardFault_Handler en tu archivo de interrupciones (ej. stm32_it.c) y modificar su contenido.
  2. Acceso Bare-Metal (Sin Librerías): Dentro de un estado de fallo, no debes confiar en librerías complejas como la HAL de ST ni en funciones del RTOS, ya que sus estructuras en RAM podrían estar corruptas. Debes escribir 0 lógicos directamente en los registros de memoria de los puertos GPIO.
  3. Bloqueo y Rescate: Una vez aseguradas las salidas físicas, atrapas la CPU en un bucle while(1). Esto impide que el código errático siga ejecutándose. Un temporizador independiente por hardware (Watchdog) detectará el congelamiento y forzará un reinicio eléctrico completo del chip.

⚙️ Ejercicios Prácticos

Ejercicio 1: Implementa una rutina de estado seguro bare-metal dentro de la excepción de HardFault, diseñada para apagar inmediatamente los actuadores críticos (Válvula y Bomba) antes de quedar en estado de coma inducido.


#include <stdint.h>

// Direcciones de memoria ficticias (Simulando registros de un Cortex-M STM32)
// En un código real, incluirías <stm32xxxx.h> para usar GPIOA->BSRR
#define GPIOA_BSRR (*((volatile uint32_t *) 0x40020018)) // Bit Set/Reset Register

// Constantes de hardware para los pines de tu diseño
#define PIN_VALVULA_GAS  (1 << 5)  // Supongamos que la válvula está en PA5
#define PIN_BOMBA_MOTOR  (1 << 6)  // Supongamos que la bomba está en PA6

/**
 * @brief Excepción de Máxima Prioridad: Manejador de Falla Severa de Hardware.
 * Se invoca automáticamente si la CPU choca (ej. desbordamiento de pila, 
 * acceso a memoria no alineada, puntero nulo).
 */
void HardFault_Handler(void) {
    
    // =========================================================================
    // 1. SAFE STATE ROUTINE (RUTINA DE ESTADO SEGURO)
    // =========================================================================
    // NO usamos HAL_GPIO_WritePin(). La memoria puede estar corrupta.
    // Hablamos directamente al hardware de silicio usando registros (Bare-Metal).
    // En STM32, el registro BSRR apaga pines escribiendo un 1 en la mitad superior (Reset bits).
    
    // Apagar Válvula inmediatamente (Desplazamos 16 bits para acceder al Reset)
    GPIOA_BSRR = (PIN_VALVULA_GAS << 16); 
    
    // Apagar Bomba inmediatamente
    GPIOA_BSRR = (PIN_BOMBA_MOTOR << 16);
    
    // (Opcional): Si tienes un LED rojo de error en hardware puro, enciéndelo aquí.


    // =========================================================================
    // 2. BLOQUEO TERMINAL
    // =========================================================================
    // Deshabilitar todas las interrupciones enmascarables para evitar que 
    // otro proceso intente tomar el control sobre un sistema corrupto.
    __asm("cpsid i"); 
    
    // Bucle infinito. 
    // El microcontrolador se quedará atrapado aquí.
    // El Independent Watchdog Timer (IWDG) de hardware notará que el Súper Bucle
    // dejó de "alimentarlo" y forzará un reinicio del sistema (Hard Reset).
    while (1) {
        // En desarrollo: Poner un punto de interrupción (Breakpoint) aquí 
        // para analizar los registros de la CPU con el depurador (Debugger JTAG).
    }
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Tolerancia a Fallas en Software Crítico.

Trabajando con Gas LP, las consecuencias de un "Bug" son drásticamente distintas a las de una aplicación web. Imagina que durante un despacho de gas, un pico de ruido electromagnético corrompe el Program Counter (PC) del STM32, o un error en la reserva de memoria del ESP32 provoca un HardFault. Si el procesador colapsa, la última instrucción física dictada a los pines GPIO se mantendrá retenida.

Si la válvula y la bomba estaban encendidas, se quedarán encendidas indefinidamente, ignorando cualquier barrera de volumen y sobrellenando el tanque. Al reescribir el HardFault_Handler, garantizas que, incluso en los últimos nanosegundos de "vida" del procesador antes de colapsar, su prioridad absoluta será cortar la energía a los relevadores de alta tensión, despresurizando el sistema instantáneamente. Esto transforma un equipo amateur en un equipo industrial Fail-Safe.

📝 Resumen del Día

❓ Cuestionario de Autoevaluación

1. ¿Por qué no simplemente llamamos a nuestra función `hardware_apagar_todo()` dentro del HardFault_Handler?
Respuesta: Porque no sabes el estado de la RAM o del Stack. Si tu función hardware_apagar_todo() utiliza variables locales, llama a funciones de la HAL que verifican punteros de estructuras (ej. &hgpioa), o intenta hacer un `printf` por UART, es casi seguro que causará una nueva excepción que provocará un bloqueo total del núcleo sin haber apagado los actuadores. La manipulación de registros a través de constantes de hardware es la única vía garantizada.

2. Si nos quedamos atrapados en el `while(1)` del Fault Handler, ¿cómo revive la máquina?
Respuesta: A través del Hardware Watchdog (que estudiarás a fondo más adelante, diferente al watchdog lógico). El Watchdog es un temporizador independiente que corre en su propio reloj de silicio. Si el Súper Bucle deja de resetear este temporizador (porque la CPU está atrapada en el Fault Handler), el temporizador llega a cero y activa un pin interno de Reset físico, reiniciando el microcontrolador de forma limpia para que vuelva a iniciar su operación normal de forma segura.