El hardware del UART está compuesto por dos cajas separadas: el Shift Register (Registro de Desplazamiento) y el Data Register (DR). Cuando llega un pulso por el cable RX, los bits entran uno a uno al Shift Register. Cuando los 8 bits se completan, el hardware los empuja de golpe hacia el Data Register (DR), y dispara la bandera RXNE para avisarle a tu CPU que venga a recogerlos.
¿Qué ocurre si llega un segundo byte, se arma en el Shift Register, intenta pasar al DR, pero el CPU todavía no ha sacado el primer byte? Ocurre una colisión fatal. El hardware preserva el primer byte en el DR, pero el segundo byte (el nuevo) es destruido, y se levanta la bandera ORE en el registro de estado (SR).
En el STM32, si la bandera ORE está encendida, el hardware asume que el sistema está corrupto. Aunque sigan llegando datos válidos por el cable, el USART se niega a pasarlos al DR y se niega a disparar interrupciones. El programador inexperto ve su equipo funcionando, pero la comunicación serial "mágicamente" deja de responder tras un par de horas de operación. La solución Bare-Metal no es reiniciar el equipo, es atrapar el error en la interrupción y purgarlo.
La secuencia mágica oficial de STMicroelectronics para limpiar un Overrun Error es: Leer el registro SR, y posteriormente leer el registro DR.
Ejercicio 1: Intervendremos tu código de interrupción USART2_IRQHandler del Día 132. Ahora, además de leer el registro de datos, le preguntaremos al hardware si se levantaron las banderas ORE (Overrun Error), FE (Framing Error - Ruido en el cable) o NE (Noise Error). Si alguna está encendida, ejecutaremos la secuencia de purgado del registro para resucitar el bus sin reiniciar la máquina.
/**
* @file uart_rx_overrun.c
* @brief Manejo robusto de errores UART en Interrupciones (ORE, FE, NE)
*/
#include "stm32f401xe.h"
#include <stdbool.h>
// Búferes del Día 132
#define RX_BUFFER_SIZE 64
volatile char rx_buffer[RX_BUFFER_SIZE];
volatile uint8_t rx_indice = 0;
volatile bool comando_listo = false;
// Contadores de diagnóstico de la máquina
volatile uint32_t fallos_comunicacion_ore = 0;
volatile uint32_t fallos_ruido_cable = 0;
/**
* @brief Vector de Interrupción del USART2 Modificado para Industria
*/
void USART2_IRQHandler(void) {
uint32_t status_register = USART2->SR;
// ====================================================
// 1. MANEJO DE ERRORES CRÍTICOS (HARDWARE LOCKUP)
// ====================================================
// ORE: Overrun Error (CPU lento, datos perdidos)
if (status_register & USART_SR_ORE) {
// Secuencia oficial de purgado en ARM Cortex-M:
// Leer SR (ya lo hicimos arriba) y luego leer el DR para descartar la basura.
volatile uint32_t limpieza = USART2->DR;
(void)limpieza; // Evita warning de variable sin usar
fallos_comunicacion_ore++;
// Si hay overrun, la trama actual está corrupta. Reiniciamos el búfer.
rx_indice = 0;
}
// FE (Framing Error) o NE (Noise Error)
// El hardware detectó pulsos espurios o interferencia electromagnética
if (status_register & (USART_SR_FE | USART_SR_NE)) {
// El ruido eléctrico arruinó el byte actual. Lo purgamos.
volatile uint32_t limpieza = USART2->DR;
(void)limpieza;
fallos_ruido_cable++;
rx_indice = 0;
}
// ====================================================
// 2. RECEPCIÓN NORMAL DE DATOS (RXNE)
// ====================================================
// Si no hubo errores, o después de procesarlos, revisamos si hay datos sanos
if (status_register & USART_SR_RXNE) {
char caracter = (char)USART2->DR;
if (caracter == '\r') {
return; // Ignorar carriage return
}
if (caracter == '\n') {
rx_buffer[rx_indice] = '\0';
comando_listo = true;
}
else {
if (rx_indice < (RX_BUFFER_SIZE - 1)) {
rx_buffer[rx_indice] = caracter;
rx_indice++;
} else {
rx_indice = 0; // Desbordamiento lógico del búfer
}
}
}
}
int main(void) {
// inicializar_usart2_interrupcion(); (Día 132)
while(1) {
// Ejecución normal de la metrología...
if (comando_listo) {
// procesar_comando_remoto();
// comando_listo = false;
}
// --- DIAGNÓSTICO DEL SISTEMA ---
// Si en 1 hora registramos muchos "fallos_ruido_cable", significa que
// nuestro cableado de red está pasando demasiado cerca del motor eléctrico.
// Si hay muchos "fallos_comunicacion_ore", el CPU está haciendo tareas
// bloqueantes demasiado pesadas y necesitamos optimizar el algoritmo de ventas.
}
return 0;
}
Objetivo del día: Tolerancia a Fallos y Prevención de "Zombies" de Red.
El estándar RS485 en un patio de gasolinera es un infierno electromagnético. Los cables de datos viajan por decenas de metros junto a cables de potencia de 220V que alimentan bombas y contactores. El ruido eléctrico inyecta pulsos falsos en tu cable UART, y el tráfico denso de varios despachadores hablando al mismo tiempo genera colisiones de procesamiento.
Si no hubiéramos implementado la purga del registro ORE, la primera chispa eléctrica en el cable RX bloquearía la línea de comunicaciones de tu STM32 permanentemente. Tu máquina seguiría vendiendo gas y la pantalla LCD seguiría funcionando, pero el Servidor Central jamás la volvería a escuchar. La máquina se convertiría en un nodo "Zombie". Al manejar los errores ORE y NE/FE a bajo nivel, garantizas un auto-recuperamiento instantáneo. El microcontrolador absorbe el golpe de ruido, lo ignora, limpia la basura y vuelve a escuchar el siguiente paquete sano como si nada hubiera pasado.
Data Register (DR).