DÍA 146 DE 365

Fase 3: Comunicaciones y Redes Industriales

📖 Teoría a Estudiar

El Castigo de la Borradura: Sectores Asimétricos

A diferencia de la RAM (donde puedes reescribir un solo byte a placer), la memoria Flash de los microcontroladores es terca. Físicamente, solo puede convertir unos (1) en ceros (0). Si tienes guardado un 0x00 y quieres escribir un 0xFF, la Flash te dirá que no puede. Tienes que borrarla primero. Borrar significa regresar los transistores a estado 1 (0xFFFFFFFF).

Aquí radica el desafío Bare-Metal: No puedes borrar bytes individuales. Estás obligado a borrar un bloque entero de memoria llamado Sector. Y en el STM32F401RE (512 KB), la arquitectura de sectores es diabólicamente asimétrica.

Las Llaves del Controlador Flash (FPEC)

Al igual que el Dominio VBAT, la memoria Flash está sellada lógicamente para evitar que un código corrupto (un puntero loco) se ponga a borrar el programa de tu propia máquina. Antes de realizar cualquier borrado o escritura, debes inyectar dos llaves criptográficas de 32 bits consecutivamente en el registro FLASH_KEYR.

MAPA FÍSICO DE MEMORIA FLASH (STM32F401RE - 512 KB) Dirección Base 0x0800 0000 0x0800 4000 0x0800 8000 0x0800 C000 0x0801 0000 0x0802 0000 0x0804 0000 0x0806 0000 0x0807 FFFF Sector 0 (16 KB) Sector 1 (16 KB) Sector 2 (16 KB) Sector 3 (16 KB) Sector 4 (64 KB) Sector 5 (128 KB) Sector 6 (128 KB) Sector 7 (128 KB) Firmware (Código del Súper Bucle) Tu programa inicia en 0x08000000. Ocupa los primeros sectores naturalmente. ¡PELIGRO: NUNCA borres el Sector 0! Borrarás tu propio programa. Sectores de Datos (User Storage) 1. Se deben DESBLOQUEAR primero. 2. Se borran COMPLETOS (128KB a la vez). 3. Se escriben palabra por palabra (32 bits). 4. La escritura bloquea (Stall) al CPU. FLASH->KEYR = 0x45670123; 0xCDEF89AB;

⚙️ Ejercicios Prácticos

Ejercicio 1: Vamos a crear un driver Bare-Metal para borrar y escribir en el Sector 5 (Dirección 0x08020000). Implementaremos la secuencia de desbloqueo, el comando de borrado de sector (Sector Erase), y escribiremos un arreglo de configuración simulando la temperatura del tanque de gas.


/**
 * @file flash_memory.c
 * @brief Driver Bare-Metal para almacenamiento persistente en Flash interna
 */

#include "stm32f401xe.h"
#include <stdint.h>

// El Sector 5 de un STM32F401 inicia en esta dirección física absoluta
#define DIR_SECTOR_5  0x08020000 
#define NUM_SECTOR_5  5

/**
 * @brief Desbloquea el Controlador de la Memoria Flash
 */
void flash_desbloquear(void) {
    // Si la Flash está bloqueada (Bit LOCK = 1)
    if (FLASH->CR & FLASH_CR_LOCK) {
        // Secuencia secreta obligatoria según el Datasheet (Reference Manual)
        FLASH->KEYR = 0x45670123;
        FLASH->KEYR = 0xCDEF89AB;
    }
}

/**
 * @brief Bloquea la Flash para prevenir escrituras accidentales
 */
void flash_bloquear(void) {
    FLASH->CR |= FLASH_CR_LOCK;
}

/**
 * @brief Borra un sector completo (¡Ojo! Todos los bytes se volverán 0xFF)
 * @param sector Número de sector (0 a 7)
 */
void flash_borrar_sector(uint8_t sector) {
    
    // 1. Esperar a que la Flash esté libre (Busy flag)
    while (FLASH->SR & FLASH_SR_BSY);
    
    // 2. Limpiar bits de sector anteriores en el Control Register
    FLASH->CR &= ~FLASH_CR_SNB; 
    
    // 3. Colocar el nuevo número de sector (Se desplaza 3 posiciones según manual)
    FLASH->CR |= (sector << FLASH_CR_SNB_Pos);
    
    // 4. Activar la orden de Borrado de Sector (Sector Erase)
    FLASH->CR |= FLASH_CR_SER;
    
    // 5. Apretar el gatillo (Start)
    FLASH->CR |= FLASH_CR_STRT;
    
    // 6. ADVERTENCIA BARE-METAL: El CPU se quedará paralizado aquí.
    // Borrar un sector de 128KB toma casi 1 segundo o más. 
    // Durante este tiempo no se pueden procesar interrupciones eficientemente.
    while (FLASH->SR & FLASH_SR_BSY);
    
    // 7. Apagar la orden de borrado para regresar a la normalidad
    FLASH->CR &= ~FLASH_CR_SER;
}

/**
 * @brief Escribe una Palabra (Word de 32-bits) en una dirección de Flash
 * @param direccion Puntero crudo a la memoria
 * @param dato Número a grabar
 */
void flash_escribir_palabra(uint32_t direccion, uint32_t dato) {
    
    // Esperar a que la Flash esté lista
    while (FLASH->SR & FLASH_SR_BSY);
    
    // Activar modo Programación (PG)
    FLASH->CR |= FLASH_CR_PG;
    
    // El tamaño a grabar depende del voltaje PSIZE. Por defecto es x32 (Palabras)
    // Escribimos directamente en la memoria física mediante cast de punteros
    *(__IO uint32_t*)direccion = dato;
    
    // Esperar a que el proceso químico del silicio termine
    while (FLASH->SR & FLASH_SR_BSY);
    
    // Apagar modo programación
    FLASH->CR &= ~FLASH_CR_PG;
}

/**
 * @brief Lectura directa desde Flash (¡A la velocidad de la luz!)
 */
uint32_t flash_leer_palabra(uint32_t direccion) {
    // La lectura de Flash no necesita desbloqueos. Se lee como si fuera RAM.
    return *(__IO uint32_t*)direccion;
}

int main(void) {
    
    // Ejemplo: Grabando la Tabla de Compensación API para LPG
    // Esto lo ejecutaríamos una sola vez, cuando el Servidor Central envía 
    // la orden de actualización masiva por RS485.
    
    // 1. Romper el seguro
    flash_desbloquear();
    
    // 2. Destruir los datos viejos (Obligatorio para que pasen a 0xFF)
    // ADVERTENCIA: Apaga válvulas y suspende red, el CPU se va a congelar.
    flash_borrar_sector(NUM_SECTOR_5);
    
    // 3. Escribir nuevos datos en direcciones consecutivas (+4 bytes por palabra)
    flash_escribir_palabra(DIR_SECTOR_5,       0xAABBCCDD); // Metadatos versión
    flash_escribir_palabra(DIR_SECTOR_5 + 4,   1450);       // Densidad factor 1
    flash_escribir_palabra(DIR_SECTOR_5 + 8,   1520);       // Densidad factor 2
    // ... Podrías guardar 32,000 parámetros de 32-bits en este sector.
    
    // 4. Volver a proteger el sistema
    flash_bloquear();
    
    while(1) {
        // Durante la venta de gas, el STM32 puede leer las direcciones de memoria
        // a 84MHz para buscar el factor correcto según la temperatura.
        uint32_t factor = flash_leer_palabra(DIR_SECTOR_5 + 4);
    }
    
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Almacenamiento Masivo y Parametrización en Silicio.

El Gas Licuado de Petróleo (LP) cambia radicalmente de volumen dependiendo del clima. Un litro en invierno pesa distinto que un litro en verano. Por norma metrológica, tu máquina expendedora debe tener cargada una Tabla de Conversión Dinámica API 2540, que mapea temperaturas contra coeficientes de expansión. ¡Esta tabla es inmensa! No cabe en la pequeña EEPROM I2C, ni mucho menos en los Backup Registers.

Al dominar el **Controlador de Memoria Flash Interna**, has habilitado a tu Despachador para almacenar Megabytes de datos estáticos en sus propios transistores sin añadir costos de componentes SD u otras memorias. El Servidor de la gasera puede mandar la gigantesca tabla por la red RS485; tu STM32 la recibirá por el DMA, borrará el Sector 5, y quemará permanentemente los coeficientes en su cerebro. La máquina ahora operará con precisión milimétrica sin importar las estaciones del año.

📝 Resumen del Día