DÍA 118 DE 365

Fase 2: Fundamentos de Hardware y Electrónica

📖 Teoría a Estudiar

El Perro Guardián Analógico (Analog Watchdog - AWD)

A diferencia del IWDG (que vigila que el código C no se congele) y el WWDG (que vigila que el código se ejecute a tiempo), el Analog Watchdog es un componente del ADC que vigila físicamente el voltaje de entrada sin involucrar instrucciones de software.

El AWD te permite configurar dos umbrales matemáticos:

Cada vez que el ADC completa una conversión (movida por el DMA), el hardware pasa el número resultante a través de un comparador digital. Si el número está por encima del HTR o por debajo del LTR, el hardware levanta inmediatamente la bandera AWD en el registro de estado y dispara la interrupción ADC_IRQn.

Discriminación de Interrupciones

En el Día 114 activamos la interrupción del ADC usando el bit EOCIE (End of Conversion Interrupt Enable). El CPU se despertaba cada vez que una lectura estaba lista. En el Día 117 le pasamos ese trabajo al DMA y apagamos la interrupción del CPU. Hoy, volveremos a encender la interrupción del ADC, pero SOLO para el Analog Watchdog (AWDIE). El CPU seguirá ignorando las conversiones normales, y solo despertará abruptamente si ocurre un evento de sobrepresión.

ZONAS DE PROTECCIÓN: ANALOG WATCHDOG (AWD) Tiempo ADC HTR = 3030 (~120 PSI) SOBREPRESIÓN (HARDWARE INTERRUPT) ZONA SEGURA (Transferencias Silenciosas vía DMA) LTR = 300 (~Cable Roto) 1. CPU Suspende Tareas de inmediato 2. Ejecuta VALVULA_OFF();

⚙️ Ejercicios Prácticos

Ejercicio 1: Tomaremos el código del Día 117 (ADC disparado por TIM3 + DMA) y le agregaremos la configuración del AWD exclusivamente para el Canal 1 (Presión en PA1). Calcularemos el umbral crudo equivalente a 120 PSI. Si la lectura cruza este umbral, apagaremos la válvula desde la interrupción.


/**
 * @file awd_safety.c
 * @brief Implementación del Analog Watchdog para Sobrepresión
 */

#include "stm32f401xe.h"
#include "valve_driver.h" // Macro VALVULA_OFF()

// Cálculos de Punto Fijo (Día 112): 0 PSI = 409, 150 PSI = 3685
// Para 120 PSI el valor aproximado es: 409 + ((3685-409)*120)/150 = 3030
#define UMBRAL_SOBREPRESION_CRUDO 3030

void inicializar_seguridad_analogica(void) {
    
    // (Asumimos que el ADC, Timer 3 y DMA ya fueron inicializados como en el Día 117)
    // ADC1->CR2 &= ~ADC_CR2_ADON; // Apagar para configurar
    
    // ====================================================
    // 1. CONFIGURACIÓN DE LOS LÍMITES DEL WATCHDOG
    // ====================================================
    // Límite Superior: 120 PSI
    ADC1->HTR = UMBRAL_SOBREPRESION_CRUDO;
    
    // Límite Inferior: 0 (No nos interesa disparar por baja presión en este ejemplo, 
    // lo manejamos en el main, pero podríamos setearlo en 200 para detectar cables rotos)
    ADC1->LTR = 0;
    
    // ====================================================
    // 2. CONFIGURACIÓN DEL COMPORTAMIENTO (CR1)
    // ====================================================
    
    // Habilitar Analog Watchdog para un Solo Canal (Single Channel Mode)
    ADC1->CR1 |= ADC_CR1_AWDSGL;
    
    // Seleccionar cuál canal vigilar. Queremos el Canal 1 (Presión PA1).
    // Limpiamos los bits de selección y aplicamos el valor '1'.
    ADC1->CR1 &= ~ADC_CR1_AWDCH;
    ADC1->CR1 |= 1;
    
    // Habilitar la vigilancia del AWD en los canales regulares (Los que lee el DMA)
    ADC1->CR1 |= ADC_CR1_AWDEN;
    
    // ====================================================
    // 3. ACTIVAR INTERRUPCIÓN EXCLUSIVA DEL AWD
    // ====================================================
    // IMPORTANTE: NO activamos EOCIE. El CPU seguirá ignorando conversiones normales.
    // Solo activamos AWDIE (Analog Watchdog Interrupt Enable)
    ADC1->CR1 |= ADC_CR1_AWDIE;
    
    // Asignar prioridad casi absoluta en el NVIC (ej. Nivel 1)
    NVIC_SetPriority(ADC_IRQn, 1);
    NVIC_EnableIRQ(ADC_IRQn);
    
    // ADC1->CR2 |= ADC_CR2_ADON; // Re-encender ADC
}

// --- VECTOR DE INTERRUPCIÓN ---
void ADC_IRQHandler(void) {
    
    // Revisar si la interrupción fue causada por el Analog Watchdog (AWD flag)
    if (ADC1->SR & ADC_SR_AWD) {
        
        // 1. CORTAR FLUJO DE ENERGÍA / CERRAR VÁLVULAS INSTANTÁNEAMENTE
        VALVULA_OFF();
        
        // 2. Desactivar el PWM de rampa si estaba activo
        // TIM3->CCR2 = 0;
        
        // 3. (Opcional) Levantar bandera global para que el main() avise a la oficina central
        // flag_falla_presion = true;
        
        // 4. Limpiar la bandera del AWD para evitar un bucle infinito
        // En los STM32, las banderas SR suelen limpiarse escribiendo un 0 en el bit específico
        ADC1->SR &= ~ADC_SR_AWD;
    }
}

int main(void) {
    
    // inicializar_adquisicion_autonoma(); (Día 117)
    inicializar_seguridad_analogica();
    
    while(1) {
        // Tu CPU está libre. El DMA recolecta datos normales.
        // Si hay una explosión o taponamiento, el hardware 
        // cerrará la válvula por ti en fracciones de milisegundo.
    }
    
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Hard Real-Time Fault Detection (Normas IEC 61508).

En el diseño de sistemas críticos (Functional Safety), el software principal en el bucle while(1) se considera "No Confiable" debido a su naturaleza asíncrona. Si el operador del camión dobla la manguera mientras despacha, la presión dentro del equipo se disparará de 80 PSI a 150 PSI en una onda de choque milisegundos antes de reventar el tubo de cobre.

Al implementar el Analog Watchdog, has construido un circuito de intervención que puentea completamente al software. El ADC, que ya estaba siendo disparado por el Timer cada 1ms, compara automáticamente el valor contra `3030` mediante compuertas lógicas físicas. Al detectar el cruce, dispara el ADC_IRQn, detiene la tarea actual del CPU (Preemption), y la válvula de gas LP se cierra instantáneamente (VALVULA_OFF). Tu tesis acaba de cumplir con principios de seguridad funcional de grado industrial pesado.

📝 Resumen del Día