Proteger los datos puede hacerse en dos niveles:
Ejercicio 1: Desarrollaremos una estructura Variable_TMR_t. El Súper Bucle jamás leerá el "Precio" o el "Total de Litros" directamente. Utilizará una función envoltorio (Getter) que lee las 3 variables. Si las tres coinciden, retorna feliz. Si una difiere (ej. por radiación), asume que las dos iguales tienen la razón (Mayoritario), sobrescribe a la corrupta reparando la RAM, y le entrega al programa el valor seguro.
/**
* @file ecc_tmr.c
* @brief Implementación de Paridad Par y Triple Modular Redundancy (TMR)
*/
#include "stm32f401xe.h"
#include <stdint.h>
#include <stdbool.h>
extern void Bloqueo_Legal_Fatal(uint32_t codigo_error); // Día 158
#define ERR_CORRUPCION_RAM_FATAL 0xF005
// =========================================================================
// 1. CÁLCULO DE PARIDAD (Para detección simple en buses internos)
// =========================================================================
/**
* @brief Calcula el bit de paridad Par de una variable de 32 bits.
* Muy útil si almacenas datos en EEPROM externa sin espacio para TMR.
* @return 0 si los bits '1' son pares, 1 si son impares.
*/
uint8_t Calcular_Paridad_Par_32b(uint32_t data) {
// Usamos el poder aritmético del procesador ARM
// Colapsamos los 32 bits a 1 solo bit mediante corrimientos XOR
data ^= data >> 16;
data ^= data >> 8;
data ^= data >> 4;
data ^= data >> 2;
data ^= data >> 1;
return (uint8_t)(data & 1);
}
// =========================================================================
// 2. TRIPLE MODULAR REDUNDANCY (TMR) PARA VARIABLES CRÍTICAS EN RAM
// =========================================================================
// Estructura que protege un solo valor multiplicándolo por 3
typedef struct {
uint32_t copia_A;
uint32_t copia_B;
uint32_t copia_C;
} Variable_TMR_t;
/**
* @brief Escribe un valor en la variable protegida (Actualiza las 3 copias)
*/
void TMR_Escribir(Variable_TMR_t *var, uint32_t valor_nuevo) {
// Para evitar que una interrupción rompa la atomicidad
__disable_irq();
var->copia_A = valor_nuevo;
var->copia_B = valor_nuevo;
var->copia_C = valor_nuevo;
__enable_irq();
}
/**
* @brief Lee la variable aplicando el algoritmo del "Votador" (Voter)
* Detecta y corrige errores de bit simples instantáneamente.
*/
uint32_t TMR_Leer(Variable_TMR_t *var) {
uint32_t a = var->copia_A;
uint32_t b = var->copia_B;
uint32_t c = var->copia_C;
// Escenario Perfecto: Ningún rayo cósmico ha golpeado la RAM
if (a == b && b == c) {
return a;
}
// ALERTA: Ocurrió un Bit-Flip. Aplicamos lógica de Voto Mayoritario (2 de 3)
if (a == b) {
// C está corrupta. La reparamos y retornamos.
var->copia_C = a;
return a;
}
if (b == c) {
// A está corrupta. La reparamos y retornamos.
var->copia_A = b;
return b;
}
if (a == c) {
// B está corrupta. La reparamos y retornamos.
var->copia_B = a;
return a;
}
// Escenario Apocalíptico: Un fallo eléctrico masivo ha destruido toda
// la sección de la SRAM. Ninguna variable se parece a la otra.
// Detener la máquina expendedora incondicionalmente.
Bloqueo_Legal_Fatal(ERR_CORRUPCION_RAM_FATAL);
return 0; // Inalcanzable, el bloqueo detiene el programa
}
// =========================================================================
// APLICACIÓN EN EL DESPACHADOR DE GAS
// =========================================================================
// Esta es la variable más crítica de todo el sistema. Si se corrompe y
// baja su valor, el operador de la gasolinera pierde dinero. Si sube, roba al cliente.
Variable_TMR_t precio_por_litro_oficial;
int main(void) {
// Al inicializar el sistema (Ej. descargando el precio del servidor SCADA)
uint32_t precio_descargado = 1055; // $10.55 MXN
TMR_Escribir(&precio_por_litro_oficial, precio_descargado);
while(1) {
// Supongamos que la máquina está calculando la venta en la pantalla...
// ... Un contactor trifásico cercano genera un chispazo y un bit
// de la "copia_A" de nuestra RAM cambia de 0 a 1 por la interferencia EMI.
// El Súper Bucle NO accede a la RAM directamente. Usa el "Votador".
uint32_t precio_seguro = TMR_Leer(&precio_por_litro_oficial);
// El votador silenciosamente notó que la Copia A estaba mal.
// Usó las copias B y C para arreglar la A en tiempo real,
// y nos devolvió el 1055 perfecto. El cliente nunca nota nada,
// el código jamás colapsa.
// uint32_t importe_total = litros * precio_seguro;
// lcd_actualizar_venta(importe_total);
}
return 0;
}
Objetivo del día: Certificación de Misión Crítica (SIL-3 Hardware Inmunity).
A nivel industrial, la protección no termina en aislar la placa en una caja metálica. La vibración, el calor extremo y los campos magnéticos severos causarán fallos transitorios en el silicio (Soft Errors) eventualmente. Si programas las variables críticas de la máquina (`Precio`, `Odómetro_Fiscal`, `Estado_Valvula`) como simples float o int, un solo bit invertido en la RAM convertirá un precio de $10.00 en $266.00.
Al introducir la estructura **TMR (Redundancia Modular Triple)**, has dotado a tu firmware de capacidad "Self-Healing" (Autosanación). Aunque el hardware interno del STM32 sea bombardeado por EMI durante el encendido del compresor de gas, el software detectará la celda de memoria corrupta y la planchará con el dato correcto usando la mayoría de votos. Has elevado el nivel de tu arquitectura metrológica al estándar exigido por reguladores médicos, automotrices (ISO 26262) y de seguridad de instrumentación pesada (SIL-3).