EmbeddedEra EmbeddedEra

← Notas desde el banco de trabajo.

Encontrar por qué un dispositivo se reinicia en campo

6 oct 2026 firmwaredesign-for-test Traducido del original en inglés con ayuda de IA. Aún no ha sido revisado por una persona.

Leer el original en inglés ›

Una unidad en el sitio de un cliente se reinicia más o menos una vez al día. El mismo firmware en tu banco, con un depurador conectado, corre una semana sin un solo tropiezo. No se registró nada, porque el código que lo habría registrado es el código que se reinició.

Este es uno de los problemas más comunes en los productos embebidos ya enviados, y rara vez se resuelve mirando fijamente el código fuente. Se resuelve haciendo que el dispositivo te diga lo que pasó. Eso requiere dos piezas de instrumentación, ambas pequeñas, y ambas mucho más fáciles de agregar antes de que el producto se envíe que después.

Lee la causa del reset, y léela correctamente

Todo microcontrolador con el que trabajamos registra por qué salió de reset la última vez. En el Nordic nRF52 es el registro RESETREAS del periférico POWER. En las piezas de Espressif, ESP-IDF lo envuelve como esp_reset_reason(), que separa encendido, brownout, panic y los distintos watchdogs. En Zephyr, la llamada portable es hwinfo_get_reset_cause(). Las piezas STM32 guardan un conjunto de banderas de reset en un registro de estado del RCC; el nombre del registro y las banderas exactas difieren entre familias, así que revisa el manual de referencia de la pieza que está en la placa.

Leer el registro es una línea. Leerlo correctamente requiere más cuidado. Tres errores aparecen una y otra vez.

No limpiarlo. La documentación de Nordic es directa: a menos que se limpie, RESETREAS es acumulativo, y un campo se limpia escribiéndole un 1. Zephyr documenta el mismo comportamiento para su API: las llamadas sucesivas devuelven el mismo valor hasta que se llama a hwinfo_clear_reset_cause(). Si el firmware nunca limpia las banderas, un reset por watchdog del martes pasado se sigue reportando hoy, junto a cada reset desde entonces. Lee una vez, temprano en el arranque, guarda el valor y luego limpia.

Dejar que el bootloader se lo coma. Si un bootloader corre primero y lee y limpia las banderas, la aplicación no ve nada útil. Decide qué etapa es dueña del registro, y haz que pase el valor hacia adelante.

Suponer que toda causa tiene una bandera. En el nRF52832, que no haya ninguna bandera activada significa que el reset vino del generador de reset del chip, que Nordic describe como un reset de encendido o un reset por brownout. El registro por sí solo no puede distinguir entre esos dos. Un diseño que necesite distinguirlos tiene que obtener esa información de otra manera, como una medición de la alimentación tomada al arrancar.

Causa reportadaA qué suele apuntarSiguiente revisión
Brownout o encendidoCaída de la alimentación, caída de la batería, conectorMide el riel con osciloscopio, disparado por el reset
WatchdogUn cuelgue, un deadlock, un lazo bloqueadoQué tarea dejó de reportarse
Reset por software o panicSe disparó un manejador de fallas o un assertEl registro de falla guardado
Pin de resetRuido o ESD en la línea de resetEl circuito de reset contra la hoja de datos
Lockup de la CPUUna falla dentro de un manejador de fallasLa pila y el código del manejador

Guarda la causa junto con un contador de arranques en memoria no volátil. Un conteo de resets por causa, leído de una unidad devuelta, a menudo reduce el problema a hardware o firmware antes de que alguien abra un depurador.

Captura la falla antes del reinicio

La causa del reset dice qué tipo de evento fue. No dice dónde. Para las fallas de firmware, el dispositivo necesita guardar un registro pequeño en el momento de la falla.

En las piezas Arm Cortex-M, que incluyen STM32, nRF52 y Microchip SAM, el núcleo empuja ocho registros a la pila activa cuando se atiende una excepción: r0 a r3, r12, el registro de enlace, el contador de programa y el registro de estado del programa. Los registros de estado de fallas en el System Control Block registran la clase de falla. Un manejador de fallas que guarde el contador de programa apilado, el registro de enlace y los registros de estado de fallas tiene lo suficiente para nombrar la función que falló, dada la compilación correspondiente. Una salvedad importa aquí. Algunas fallas de bus se reportan como imprecisas, lo que significa que el contador de programa apilado no es la instrucción que causó la falla. El registro de estado lo señala, así que regístralo e interpreta la dirección en consecuencia.

El lugar a donde va el registro importa tanto como lo que contiene. Escribir en flash desde dentro de un manejador de fallas es arriesgado. No se puede confiar en el estado del sistema, y si la causa raíz es una alimentación que falla, una escritura en flash es lo peor que se puede empezar. El patrón habitual es escribir el registro en una región de RAM que el código de arranque no inicializa, marcarlo con un valor mágico y un checksum, y reiniciar. En el siguiente arranque, el firmware ya sano valida el registro y lo mueve a flash o lo envía. Esto funciona para resets en caliente en los que la alimentación se mantiene. Confirma en tu pieza específica que el contenido de la RAM sobrevive a los tipos de reset que te importan.

Los frameworks ya ofrecen buena parte de esto. ESP-IDF puede guardar un core dump en una partición de flash dedicada o enviarlo por UART, y idf.py coredump-info lo decodifica en registros y pilas de llamadas. Zephyr tiene un subsistema de core dump con backends de registro y de partición de flash. Un valor predeterminado de Zephyr merece atención: el manejador de errores fatales de fábrica detiene el sistema. En un producto sin watchdog en funcionamiento, eso es un dispositivo que se queda muerto hasta que alguien le corta y vuelve a dar la alimentación. El manejador es un símbolo débil para que la aplicación pueda definir su propia política, y un producto que se envía debería hacerlo.

Nada de esto ayuda sin la compilación correspondiente. Un valor de contador de programa solo tiene sentido contra el archivo ELF de ese firmware exacto. Pon la versión del firmware en el registro de falla, y archiva el ELF de cada release que salga del edificio.

Haz que el watchdog diga algo

Un reset por watchdog de hardware deja un solo bit. El firmware se colgó, en algún lugar.

La manera de obtener más es arreglar que haya una advertencia antes de que el watchdog de hardware se dispare. Una interrupción de temporizador configurada para vencer un poco antes puede registrar qué tareas habían dejado de reportarse, y el contador de programa interrumpido, y luego dejar que ocurra el reset. La guía de watchdog timers del blog Interrupt recorre este patrón en un nRF52 y vale la pena leerla completa.

Revisa también los valores predeterminados. ESP-IDF corre dos watchdogs. El watchdog de interrupciones invoca el manejador de panic al vencer. El watchdog de tareas, por defecto, imprime una advertencia y un backtrace y sigue corriendo. En un dispositivo desplegado donde nadie lee la consola, esa advertencia no va a ninguna parte. Se puede configurar para que entre en panic.

El lugar donde se alimenta el watchdog también importa. Alimentarlo desde una interrupción de temporizador solo prueba que las interrupciones siguen corriendo. Aliméntalo desde un lugar al que se llegue únicamente cuando todas las tareas que importan se hayan reportado.

Distinguir un problema de alimentación de un bug de firmware

Los resets por brownout tienden a coincidir con eventos. Arranca un motor, se cierra un relé, transmite un radio, una batería se enfría o envejece. Si el registro de arranque incluye el tiempo de operación y, donde haya un canal de ADC disponible, una lectura de la alimentación, el patrón normalmente se muestra solo. En el banco, pon un osciloscopio en el riel y dispáralo con la línea de reset, y luego reproduce el evento de carga. Aquí también es donde el depurador engaña. Una unidad alimentada con una fuente de banco a través de un cable corto no es la unidad en el campo con un arnés largo.

Las causas por pin de reset apuntan al circuito de reset. Compáralo con el circuito recomendado en la hoja de datos, y fíjate en qué más está ruteado cerca de esa pista.

Los desbordamientos de pila son la falla de firmware que mejor se esconde. El desbordamiento corrompe a un vecino, y el fallo aparece más tarde en código que no hizo nada mal. ESP-IDF lo aborda poniendo un watchpoint cerca del final de la pila de cada tarea, como se describe en su guía de errores fatales. En las piezas Cortex-M con una unidad de protección de memoria, una región de guarda hace un trabajo parecido. Un conjunto de registros de falla que apuntan a lugares sin relación es una razón para medir primero el uso de la pila.

Por último, prueba la instrumentación a propósito. Fuerza una falla, deja sin alimentar al watchdog, haz caer la alimentación, y confirma que el registro nombra cada una correctamente. Un manejador de fallas que nunca se ha ejecutado es una suposición.

Cuando tomamos un problema de resets empezamos con la causa del reset y un registro de falla, así que envíanos el esquemático, el código fuente del firmware o la compilación exacta, y lo que sepas sobre cuándo ocurren los resets.

NOTAS DE INGENIERÍA

Una nota a la semana sobre diseño de PCB, firmware y cómo se construye hardware. Sin correos de ventas.

Doble confirmación. Puedes darte de baja con un clic.