DÍA 001 DE 365

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

📖 Teoría Explícita a Estudiar

La Naturaleza del Main() y el Contador de Programa (PC)

En el desarrollo de software para PC, tu programa se ejecuta, llega a un return 0; y le devuelve el control al Sistema Operativo (Windows, Linux). En el desarrollo Bare-Metal y RTOS, el STM32 es el universo entero. No existe ningún "afuera" al cual retornar.

Si la función main() termina, el Program Counter (PC) del microcontrolador (el registro que apunta a la siguiente instrucción de memoria a ejecutar) seguirá avanzando secuencialmente hacia direcciones de memoria no inicializadas o prohibidas. Esto provocará que el procesador intente ejecutar "basura" hexadecimal como si fuesen comandos válidos, disparando de inmediato una excepción de hardware irreversible llamada Hard Fault. Un sistema bloqueado en un Hard Fault con una válvula despachadora de gas abierta es una bomba de tiempo. El microcontrolador nunca, bajo ninguna circunstancia, debe salir de su programa.

El Ecosistema del Bucle con FreeRTOS

Al introducir un Sistema Operativo en Tiempo Real (FreeRTOS) para gestionar la telemetría IoT y el despacho simultáneamente, el paradigma del ciclo infinito muta:

ARQUITECTURA DE ARRANQUE SEGURO (STM32 + FREERTOS) Reset Vector / Startup Code Hardware_Init() (GPIOs a LOW) xTaskCreate() (Reserva de Heap) vTaskStartScheduler() FALLO: while(1) { Safe_Shutdown() } ÉXITO: Control Multi-Hilo Activo (Tasks)

⚡ Diseño de Circuito (Reglas Base en KiCad)

El código no salvará a la placa si el hardware colapsa eléctricamente. En la etapa esquemática de KiCad para el cerebro de la gasera, debes asegurar el entorno de supervivencia del microcontrolador:

⚙️ Ejercicios Prácticos

Ejercicio 1: Programa la arquitectura base del main.c. Incorpora la función Safe_Shutdown() que captura el control total del procesador si el inicio de la multitarea aborta.


/**
 * @file    main.c
 * @brief   Día 001 - Despachador de Gas LP (Fase 1).
 *          Estructura de ejecución base, inicialización y prevención de Hard Fault.
 */

#include "stm32f4xx.h"  // Archivo de cabecera de registros ARM Cortex-M
#include "FreeRTOS.h"
#include "task.h"
#include <stdbool.h>

// --- Prototipos Privados (Encapsulamiento estricto) ---
static void Hardware_Init(void);
static void Safe_Shutdown(void);
static void vTask_MonitorSistema(void *pvParameters);

/**
 * @brief Función principal y punto de entrada. No debe retornar jamás.
 */
int main(void) {
    
    // 1. Inicialización Bare-Metal
    // Configurar reloj, inicializar pines de válvulas en estado cerrado (LOW).
    Hardware_Init();

    // 2. Despliegue de Tareas del RTOS
    BaseType_t estado_tarea;
    
    estado_tarea = xTaskCreate(
        vTask_MonitorSistema, 
        "MonitorSalud", 
        configMINIMAL_STACK_SIZE, 
        NULL, 
        configMAX_PRIORITIES - 1, // Tarea de altísima prioridad
        NULL
    );

    if (estado_tarea != pdPASS) {
        // La creación falló porque el Heap del sistema está agotado.
        Safe_Shutdown();
    }

    // 3. Ceder control al Scheduler
    // Si la memoria es suficiente, el RTOS secuestra el Program Counter aquí.
    vTaskStartScheduler();

    // ==========================================
    // 4. EL FALLBACK CRÍTICO (Red de Seguridad)
    // ==========================================
    // Si el flujo de código avanza a esta línea, vTaskStartScheduler falló 
    // y devolvió el control. El sistema está degradado.
    
    while(1) {
        Safe_Shutdown();
        
        // En un escenario real, aquí disparamos un parpadeo de LED de error 
        // a través de un retardo básico por software, y refrescamos el Watchdog 
        // para que no reinicie la placa infinitamente, sino que se mantenga
        // en este estado seguro apagado.
    }

    return 0; // Convención sintáctica. Físicamente inalcanzable.
}

/* --- Implementación de Rutinas --- */

static void Hardware_Init(void) {
    // Código de inicialización de registros periféricos
    // Lo desarrollaremos a fondo en el Día 002 y Día 004.
}

static void Safe_Shutdown(void) {
    // BOTÓN DE PÁNICO EN SOFTWARE:
    // 1. Escribir ceros (0) lógicos directos en los registros ODR 
    //    de los pines GPIO de las electroválvulas.
    // 2. Apagar señal PWM de las bombas.
    // 3. Forzar el display a mostrar "ERROR CRITICO 01".
}

static void vTask_MonitorSistema(void *pvParameters) {
    // Todo hilo de FreeRTOS debe contener su propio ciclo infinito
    for(;;) {
        // Lógica de validación de hardware y sensores de gas
        
        // Bloquear tarea por 1000 Ticks, liberando CPU al resto del equipo
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Hito Logrado: Control determinista de la ejecución y arquitectura Fail-safe.

Al implementar este bloque, le has dado al despachador un protocolo inquebrantable para "morir con dignidad" en caso de una falla catastrófica de memoria durante el encendido. La función Safe_Shutdown() representa la máxima de la automatización industrial: asumes anticipadamente que el hardware o el RTOS pueden fallar, y configuras una respuesta absoluta para que las electroválvulas bloqueen el flujo de combustible al instante. Tu placa ahora es inherentemente segura desde el instante en que recibe voltaje.

📝 Resumen del Día

❓ Cuestionario de Autoevaluación

1. ¿Qué suceso físico ocurre dentro del silicio del STM32 si omites el ciclo `while(1)` al final del `main()` y el FreeRTOS no logra arrancar?
Respuesta: El Program Counter (PC) incrementa su dirección, pidiendo a la memoria Flash la siguiente instrucción. Como no hay código tuyo allí, el bus lee datos aleatorios (basura estática). El decodificador de instrucciones de la CPU intentará ejecutar esta basura, generando una excepción de instrucción indefinida que dispara una interrupción no enmascarable (NMI) hacia el HardFault_Handler. El chip queda vegetal, y si una válvula estaba en ALTO (abierta) durante la inicialización, jamás será apagada.