Escribir en una memoria no volátil no es como escribir en la RAM. La RAM acepta los datos al instante. La EEPROM o la Flash SPI necesitan quemar celdas de silicio mediante alto voltaje interno, un proceso lento y delicado. Por protección, el chip exige un protocolo de seguridad estricto:
0x06 (WREN). Esto quita un "candado" interno que permite la escritura.0x02, envías la dirección de memoria (16 o 24 bits), y luego puedes "escupir" hasta 256 bytes de corrido (Una página). Luego subes el pin CS.0x05 (RDSR) si el bit WIP (Write In Progress) ya volvió a cero.Una memoria está dividida en páginas físicas de hardware (usualmente de 256 bytes). El chip tiene un búfer interno de ese tamaño. Si empiezas a escribir en la dirección 250 y le mandas 10 bytes seguidos, el hardware no saltará inteligentemente a la página siguiente. Dará la vuelta y sobrescribirá el inicio de la misma página (dirección 0 a 3), destruyendo datos críticos. Por eso, el código industrial debe ser consciente de las páginas y dividir las escrituras largas.
Ejercicio 1: Crea el Driver de la EEPROM utilizando el driver SPI1 (Día 119). Implementa las secuencias Write_Enable, la escritura en página y el Wait_Ready (Polling del bit WIP). Luego, diseña una estructura en C (Struct) que empaquete los litros despachados y envíalos como una secuencia de bytes hacia la memoria.
/**
* @file eeprom_25LC.c
* @brief Driver de Memoria SPI EEPROM (Protocolo Serie 25LCxx)
*/
#include "stm32f401xe.h"
#include <stdint.h>
// Comandos universales de memoria SPI Flash/EEPROM
#define EEPROM_CMD_WREN 0x06 // Write Enable
#define EEPROM_CMD_WRITE 0x02 // Escribir Datos
#define EEPROM_CMD_READ 0x03 // Leer Datos
#define EEPROM_CMD_RDSR 0x05 // Leer Status Register
#define EEPROM_WIP_FLAG 0x01 // Bit 0: Write In Progress
// Dependencias de nuestro driver SPI1 (Día 119)
extern void SPI_CS_BAJO(void);
extern void SPI_CS_ALTO(void);
extern uint8_t spi_transferir_byte(uint8_t dato);
/**
* @brief Habilita el seguro de escritura del chip de silicio.
*/
void EEPROM_WriteEnable(void) {
SPI_CS_BAJO();
spi_transferir_byte(EEPROM_CMD_WREN);
SPI_CS_ALTO();
}
/**
* @brief Atrapa al procesador hasta que el hardware de memoria termine de quemar datos.
*/
void EEPROM_WaitReady(void) {
uint8_t status = 0;
do {
SPI_CS_BAJO();
spi_transferir_byte(EEPROM_CMD_RDSR);
status = spi_transferir_byte(0xFF); // Leer respuesta
SPI_CS_ALTO();
// (Opcional en SO: Podrías llamar a un yield/osDelay aquí para no bloquear
// al 100% el CPU durante los 5ms que tarda la EEPROM).
} while(status & EEPROM_WIP_FLAG);
}
/**
* @brief Escribe una secuencia de bytes consecutivos (Page Write).
* ¡PRECAUCIÓN!: El desarrollador debe asegurarse de que la longitud
* no sobrepase el límite de la página de la EEPROM (Ej. 64 o 256 bytes).
*/
void EEPROM_PageWrite(uint16_t direccion_16b, uint8_t* datos, uint16_t longitud) {
// 1. Pedir permiso al chip
EEPROM_WriteEnable();
// 2. Iniciar transacción de escritura
SPI_CS_BAJO();
spi_transferir_byte(EEPROM_CMD_WRITE);
// Enviar Dirección (MSB First)
spi_transferir_byte((uint8_t)(direccion_16b >> 8)); // Parte Alta
spi_transferir_byte((uint8_t)(direccion_16b & 0xFF)); // Parte Baja
// 3. Empujar arreglo de datos completo a máxima velocidad
for(uint16_t i = 0; i < longitud; i++) {
spi_transferir_byte(datos[i]);
}
// 4. Subir CS. En ESTE MICROSEGUNDO la memoria comienza a quemar.
SPI_CS_ALTO();
// 5. Esperar confirmación de guardado
EEPROM_WaitReady();
}
// ==========================================================
// INTEGRACIÓN CON EL DESPACHADOR DE GAS LP
// ==========================================================
// Estructura de Datos de la Transacción Actual
typedef struct {
uint32_t litros_despachados_x1000;
uint32_t precio_total_centavos;
uint32_t crc32; // Código de verificación de integridad
} RegistroVenta;
RegistroVenta transaccion_actual;
void guardar_respaldo_antiapagones(void) {
// Transformar el struct a un arreglo de bytes utilizando un puntero crudo (Casting)
uint8_t* array_bytes = (uint8_t*)&transaccion_actual;
uint16_t tamaño_bytes = sizeof(RegistroVenta);
// Escribir en la Dirección de Memoria 0x0000 de la EEPROM
EEPROM_PageWrite(0x0000, array_bytes, tamaño_bytes);
}
int main(void) {
// inicializar_spi1();
while(1) {
// (Flujo de Gas girando la turbina... Interrupciones EXTI actualizan la venta)
// Guardamos el estado cada vez que se despacha un litro completo
// Si cortan la luz con un machetazo, la máquina sabe exactamente
// a quién y cuánto cobrarle cuando la planta eléctrica de emergencia arranque.
guardar_respaldo_antiapagones();
}
return 0;
}
Objetivo del día: Memoria Incorruptible y Auditoría Fiscal.
El fraude en la venta de hidrocarburos suele involucrar desconexiones intencionales de la corriente eléctrica. El cliente carga 50 litros, el empleado apaga la máquina con el interruptor principal, y cuando la enciende, la máquina marca "0.0 Litros", permitiendo que el empleado cobre el efectivo y lo embolse sin registrar la venta en la computadora central.
Al dotar a tu placa de un chip EEPROM/SPI, conectado directamente mediante el driver Bare-Metal que acabas de escribir, blindas el equipo contra el "Apagón Mágico". Tu firmware empaqueta toda la información de la venta en una estructura de C (struct), la convierte en bytes crudos y la quema a 5 Megabits por segundo en el silicio no volátil (Page Write). Cuando el procesador arranca de nuevo tras el corte de energía (y lee la dirección 0x0000), restaura inmediatamente en la pantalla LCD la venta en curso exigiendo el cobro al operador. Tu máquina es ahora un Auditor Fiscal de hierro.
¡Hemos terminado la etapa más técnica y pesada de la ingeniería de sistemas! Lo que has construido en la **Fase 2** no es código, es una arquitectura sólida:
for bloqueantes.