← Notas desde el banco de trabajo.
Bare-metal o RTOS en un MCU pequeño
El firmware de tu producto creció más allá del punto en que un solo bucle y unas cuantas interrupciones se sienten cómodos. Alguien del equipo quiere FreeRTOS o Zephyr. Alguien más dice que un RTOS es exceso en una parte con 32 KB de RAM y que una máquina de estados basta. Ambos tienen razón en algo, y la decisión la toma quien argumenta más fuerte en lugar de mirar lo que el producto realmente tiene que hacer.
Esta nota es la versión de ese argumento que tendríamos con nosotros mismos antes de empezar un diseño nuevo con STM32, nRF52 o ESP32.
En qué es bueno un superloop y dónde se rompe
Un diseño bare-metal es un bucle while(1) que revisa banderas mediante polling, más manejadores de interrupción que las activan. No hay planificador. Lo único que puede interrumpir el bucle principal es una interrupción, y el único estado compartido es lo que tocan las interrupciones. Es un sistema pequeño sobre el que razonar. Puedes leerlo completo en una tarde, puedes ver cada camino desde un evento hasta una respuesta y puedes medir el tiempo de bucle en el peor caso con un osciloscopio en un pin GPIO.
Se rompe de una forma predecible. El bucle es cooperativo, así que una operación larga retrasa todo lo que está detrás. Un borrado de flash, una transacción I2C bloqueante con un esclavo atorado o un CRC largo sobre una imagen de firmware detienen el bucle, y entonces la interfaz deja de responder o se pierde una muestra de un sensor. La solución habitual es dividir el trabajo largo en una máquina de estados que hace una porción por iteración. Eso funciona, y un producto bien construido puede operar toda su vida así. Pero cada trabajo largo que divides agrega una máquina de estados más, y las interacciones entre ellas viven en tu cabeza y no en el código.
Una regla que nos ha servido: si puedes enumerar cada requisito de tiempo del producto y todos se cumplen con el tiempo de bucle del peor caso con margen, quédate en bare-metal. Si te encuentras escribiendo un planificador, aunque sea uno diminuto con una tabla de punteros a función y periodos, ya empezaste a escribir un RTOS sin las partes de un RTOS que lo hacen depurable.
Lo que un RTOS realmente da y lo que realmente cuesta
Lo que te da un RTOS no es «multitarea». Es preemption con prioridades. Una tarea de alta prioridad que atiende una radio o un lazo de control de motor se ejecuta cuando ocurre su evento, sin importar en qué estaba la tarea de registro de baja prioridad. Dejas de dividir los trabajos largos en máquinas de estados. Cada tarea se escribe como código lineal que se bloquea en una cola o un semáforo, y el kernel se encarga de intercalarlas.
Los costos son concretos.
Flash. El kernel de FreeRTOS es pequeño. El FAQ del propio proyecto ubica el kernel en aproximadamente 5 a 10 KB de ROM con una configuración típica, y señala que un crecimiento inesperado en un programa de prueba diminuto suele venir del código de cadenas y de punto flotante de la biblioteca de C, no del kernel (FAQ de uso de memoria de FreeRTOS). Zephyr es más grande porque incluye un modelo de dispositivos y una capa de controladores, y su tamaño depende mucho de lo que habilites mediante Kconfig.
RAM, y esta es la que importa. Cada tarea tiene su propio stack. En un diseño bare-metal hay un solo stack y el linker te dice qué tan grande es. Con un RTOS ahora tienes un stack por tarea más los datos propios del kernel, y dimensionas cada stack adivinando y luego midiendo. Si te quedas corto en uno, obtienes una corrupción que aparece como una falla en código sin relación. Si te pasas en todos, una parte de 32 KB se llena antes de escribir la aplicación. Cualquier formateo tipo printf, TLS o una llamada al sistema de archivos dentro de una tarea agrega cientos de bytes al stack de esa tarea de formas difíciles de ver en el código fuente.
Depuración. Una falla en bare-metal tiene un solo stack que desenrollar. Una falla en un RTOS tiene varios, y el que falló puede no ser el que causó la falla. Los kernels tienen herramientas para esto. FreeRTOS ofrece dos métodos de revisión de desbordamiento de stack y una consulta de la marca de agua máxima por tarea, y su propia documentación es honesta al decir que ninguno de los dos métodos garantiza detectar todos los desbordamientos (revisión de desbordamiento de stack en FreeRTOS). El modo usuario de Zephyr va más lejos en partes con unidad de protección de memoria: los stacks de los hilos se disponen de modo que excederlos genera una falla de hardware, y los hilos de usuario se tratan como no confiables, con seguimiento de permisos en los objetos del kernel y los controladores (descripción del modo usuario de Zephyr). Es una característica real de seguridad, pero cuesta esfuerzo de configuración y solo aplica a los hilos que pusiste deliberadamente en modo usuario.
Estado compartido. En cuanto tienes dos tareas, cada variable que ambas tocan necesita un mutex, una cola o una operación atómica. El código bare-metal tiene el mismo problema entre el bucle y sus manejadores de interrupción, pero la superficie es menor y las herramientas son más simples.
A veces la decisión ya está tomada
Antes de debatir, revisa qué asume el SDK del fabricante del silicio.
ESP-IDF de Espressif está construido sobre un FreeRTOS modificado con soporte de multiprocesamiento simétrico. En el ESP32 escribes tareas de FreeRTOS lo llames así o no, y en los destinos de un solo núcleo corre el mismo kernel con un núcleo (guía de FreeRTOS SMP de ESP-IDF). No hay una opción bare-metal significativa para un producto Wi-Fi o Bluetooth en esa familia, porque la pila de radio misma corre como tareas.
El nRF Connect SDK de Nordic integra Zephyr y agrega sus propias bibliotecas, controladores y el bootloader MCUboot encima (nRF Connect SDK y Zephyr). El SDK bare-metal más antiguo de Nordic todavía existe para la línea nRF52, pero el trabajo nuevo de BLE en nRF54 y los controladores SoftDevice actuales se orientan hacia Zephyr. Elegir bare-metal ahí significa elegir quedar fuera del camino principal del fabricante en actualizaciones y ejemplos.
STMicroelectronics es el caso opuesto. Las partes STM32 funcionan bien con nada más que los controladores HAL o LL, y la misma herramienta puede generar un proyecto de FreeRTOS mediante la capa CMSIS-RTOS. Las familias SAM y PIC de Microchip y el MSP430 de TI son similares: bare-metal es un camino de primera clase y con soporte.
Así que la primera pregunta honesta no es «RTOS o no», sino «qué ecosistema de fabricante, y qué asume». Un producto BLE en Nordic es un producto Zephyr. Un producto Wi-Fi en Espressif es un producto FreeRTOS. Un nodo sensor en un STM32L0 o un MSP430 sí es una elección real.
Las revisiones que hace un ingeniero cuidadoso antes de comprometerse
Cuando la elección es real, repasamos esta lista en lugar de discutir por gusto.
| Pregunta | Apunta a bare-metal | Apunta a un RTOS |
|---|---|---|
| ¿Cuántos requisitos de tiempo independientes hay? | Uno o dos, todos rápidos | Varios, a distintas frecuencias |
| ¿Hay alguna operación que deba bloquear por mucho tiempo? | No, o se puede dividir | Sí, y dividirla es feo |
| ¿Quién lo mantiene dentro de tres años? | El mismo ingeniero | Alguien nuevo, que necesita estructura |
| ¿El SDK del fabricante asume un kernel? | No | Sí, usa el suyo |
| ¿Se necesita aislamiento entre código confiable y no confiable? | No | Sí, usa un kernel que aproveche la MPU |
Después, en cualquier caso, aplica la misma verificación. Mide el tiempo del peor caso en el banco con un cambio de GPIO y un osciloscopio, no por inspección — la misma disciplina de banco que encuentra un problema de corriente en reposo que la tarea idle de un RTOS puede esconder. Si es un RTOS, activa la revisión de stack del kernel durante el desarrollo, lee las marcas de agua máxima después de una prueba larga y solo entonces fija los tamaños finales de stack con margen. Si es bare-metal, instrumenta el tiempo de bucle de la misma manera y registra el máximo. En ambos casos, el número que quieres es el medido en la placa real con la radio real y el flash real, porque esas son las partes que se detienen de forma inesperada.
Una revisión más que la gente se salta: piensa desde ahora en la ruta de actualización del firmware. Un bootloader que tiene que validar una imagen e intercambiar slots es una operación larga y bloqueante. En un RTOS es una tarea. En un diseño bare-metal suele correr antes de que empiece el bucle principal, lo cual está bien, siempre que lo hayas decidido a propósito.
Hacemos trabajo bare-metal y con RTOS en partes STM32, Nordic y Espressif, y lo más útil que puedes enviarnos es la lista de cosas que el producto debe hacer al mismo tiempo, con el tiempo que necesita cada una.
¿Decidiendo entre bare-metal y un RTOS para tu próxima placa? Envíanos los requisitos y escribimos el firmware de cualquiera de las dos formas.
Herramientas para este tema
- Grabador ESP32 en el navegador Graba un .bin por USB desde el navegador. Lee primero el chip y el archivo, y rechaza firmware compilado para otro chip, otra revisión u otro tamaño de flash.
- Grabador STM32 en el navegador Graba un .dfu, .hex o .bin por USB DFU desde el navegador. Lee primero el mapa de flash y la identidad del chip y rechaza firmware cuyos bytes o tabla de vectores no le pertenecen. Nunca toca los option bytes.
- Terminal serie en el navegador Conecta una placa USB y lee o envía texto y hex por serie desde el navegador. Velocidad y formato, perfiles de reset DTR/RTS para ESP32 y Arduino, marcas de tiempo y registro guardado. Nada sale de tu computadora.
Notas relacionadas
- Preparing for the CRA 24-hour vulnerability reporting duty What triggers a CRA report, the 24-hour, 72-hour and final deadlines, and the firmware and process pieces a small hardware maker needs in place first.
- Aprovisionar números de serie en la línea Dónde van los seriales, las llaves y los bloqueos de depuración por unidad en STM32, nRF52 y ESP32, qué es irreversible y cómo planear el paso de programación.
- Actualizaciones de firmware con recuperación y reversión Planea las actualizaciones de firmware en torno a la recuperación: validación de imagen, reversión, confirmación, datos compatibles y pruebas de falla.