DÍA 324 DE 365

Fase 5: Diseño Industrial y Hardware

📖 Teoría a Estudiar

¿Qué es un Bootloader Personalizado?

Un Bootloader es un mini-programa de software que vive en el Sector 0 de la memoria Flash de tu STM32. Es inmutable. Jamás se actualiza a sí mismo. Su único propósito en la vida es despertar al encender la máquina y hacerse una pregunta: "¿Hay una nueva actualización esperando ser instalada, o salto directo a ejecutar la Aplicación Principal?"

El Flujo de OTA (Over-The-Air) en Hardware Segregado

Dado que diseñaste tu hardware segregando el chip de red (ESP32) del chip de control de gas (STM32) en el Día 313, el STM32 no tiene idea de cómo conectarse al Wi-Fi. El flujo debe ser el siguiente:

  1. El ESP32 se conecta a AWS, detecta la versión `v1.0.1` y descarga el archivo .bin en su propia memoria externa (SPIFFS/SD).
  2. El ESP32 apaga todas las válvulas, detiene el despacho comercial y envía un comando por UART al STM32: [CMD_REBOOT_TO_BOOTLOADER].
  3. El STM32 se reinicia. El Bootloader despierta, detecta la petición, y comienza a recibir fragmentos del archivo `.bin` vía UART directamente desde el ESP32 (usando un protocolo como YMODEM), grabándolos en el Sector 1 de su memoria Flash.
ARQUITECTURA DE BOOTLOADER: MEMORY MAP Y TRANSFERENCIA OTA DOMINIO DE RED ESP32 (Wi-Fi) Descarga parche AWS Internet SPIFFS / Flash ESP32 patch_v1.0.1.bin (Descargado y Verificado) YMODEM (UART TX) Inyección bloque a bloque STM32 MCU (MEMORIA FLASH INTERNA) 0x0800 0000 0x0802 0000 0x0804 0000 0x0807 FFFF SECTOR 0: BOOTLOADER (16 KB) Inmutable. Recibe datos UART y graba Flash. El "JUMP" (Reset Handler) SECTOR 5+: APLICACIÓN PRINCIPAL Main Firmware v1.0.1 (El Parche) Vector Table Relocation (VECT_TAB_OFFSET) RTOS Tasks, Metrología, Seguridad (Se sobreescribe por completo en cada OTA)

⚙️ Procedimiento Práctico: Desplazamiento del Código (Linker Script)

Paso 1: Modificar el Script de Enlazado (Linker Script).
Por defecto, tu compilador asume que tu código vivirá en el principio de la memoria (0x0800_0000). Pero ahí ahora vivirá el Bootloader. Debes abrir el archivo STM32F401RETx_FLASH.ld de tu aplicación y cambiar el origen:
FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 384K

Paso 2: Relocalizar la Tabla de Vectores (Vector Table Offset).
Cuando el hardware de la CPU sufre una interrupción (Ej. llega un pulso del caudalímetro), el procesador ARM busca instintivamente qué función ejecutar en la dirección 0x0800_0000. Si no le dices al procesador que la tabla se movió, saltará al Bootloader en lugar de a tu aplicación. Debes ir al archivo system_stm32f4xx.c y modificar:
#define VECT_TAB_OFFSET 0x20000U.

💻 Firmware: El Código del Bootloader ("El Salto")

El Bootloader es un proyecto separado en C. Una vez que termina de descargar el firmware por UART y grabarlo en la Flash (usando la API HAL_FLASH_Program), debe "suicidarse" cediendo el control absoluto de la CPU al nuevo código parcheado. Esto requiere manipular registros a muy bajo nivel mediante punteros a funciones.


/**
 * @file bootloader_core.c
 * @brief Función crítica para ejecutar el Application Firmware desde un sector alto.
 */

#include "stm32f4xx_hal.h"
#include <stdio.h>

// Dirección donde el Linker Script de la Aplicación ubicó el código
#define MAIN_APP_START_ADDRESS  (0x08020000U)

typedef void (*pFunction)(void);

// =========================================================================
// EL "SALTO DE FE" A LA APLICACIÓN PRINCIPAL
// =========================================================================
/**
 * @brief Deshabilita interrupciones, configura el Stack Pointer y salta a la App.
 */
void Bootloader_JumpToApplication(void) {
    
    printf("\r\n[BOOTLOADER] Actualización finalizada o no requerida.\r\n");
    printf("[BOOTLOADER] Preparando Salto a 0x%08X...\r\n", MAIN_APP_START_ADDRESS);

    // 1. Validar que exista código válido en esa dirección de memoria.
    // El primer registro en la memoria debe ser un apuntador a la memoria RAM (Stack).
    // La SRAM del STM32 siempre comienza en 0x20000000.
    if (((*(__IO uint32_t*)MAIN_APP_START_ADDRESS) & 0x2FFE0000) == 0x20000000) {
        
        printf("[BOOTLOADER] Imagen de aplicación válida encontrada.\r\n");

        // 2. Deshabilitar todas las interrupciones globales antes de saltar.
        // Si el bootloader recibe una interrupción de UART *mientras* está saltando,
        // el sistema colapsará catastróficamente (HardFault).
        __disable_irq();

        // 3. Obtener la dirección del Reset Handler de la aplicación principal.
        // El Reset Handler vive exactamente 4 bytes después de la dirección de inicio.
        uint32_t jump_address = *(__IO uint32_t*)(MAIN_APP_START_ADDRESS + 4);
        pFunction app_reset_handler = (pFunction)jump_address;

        // 4. Mover el Main Stack Pointer (MSP) al Stack de la nueva aplicación.
        // Esto le entrega a la aplicación su propia memoria RAM temporal.
        __set_MSP(*(__IO uint32_t*)MAIN_APP_START_ADDRESS);

        // 5. ¡Ejecutar la aplicación! (Esta función jamás retornará).
        app_reset_handler();
        
    } else {
        printf("[BOOTLOADER] [ERROR] No hay aplicación válida. Pantalla de Muerte.\r\n");
        // Aquí encendemos un LED Rojo y esperamos a que el técnico venga con un ST-Link.
        while(1);
    }
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Mantenibilidad a Largo Plazo y Resiliencia en Despliegue Masivo (OTA).

El error que cometen las startups de hardware es asumir que el software que envían en la Versión 1.0 es definitivo. Cuando instalaste las 5 máquinas piloto ayer y descubriste que los botones rebotaban, tenías un problema: las máquinas estaban a 40 kilómetros de distancia y tu procesador STM32 estaba bloqueado criptográficamente (RDP 1). Sin un Bootloader, tu única opción habría sido desinstalar la tarjeta de las gaseras y traerlas al laboratorio, costándole a tu empresa cientos de dólares en soporte técnico.

Al diseñar este **Bootloader Personalizado**, has dotado a la arquitectura de tu máquina de "Inmortalidad Lógica". Tu chip secundario de red (ESP32) descargó silenciosamente el parche `v1.0.1` de AWS anoche. Al amanecer, la máquina se reinició sola, y el Bootloader, operando desde su búnker inmutable en el Sector 0, inyectó el nuevo código de filtros RC y la máquina de estados de botones en la Flash principal. Has actualizado el alma matemática e industrial de una máquina de alto riesgo desde la comodidad de tu escritorio. Esta infraestructura de actualización remota, separando el vector de red del vector de ejecución, es el sello definitivo de madurez de un producto de Hardware de Misión Crítica.

📝 Resumen del Día