¿Qué es un gestor de arranque y cómo desarrollaría uno?

He conocido muchos proyectos en los que se usa un microcontrolador AVR con un gestor de arranque (como el Arduino), pero no entiendo muy bien el concepto.

¿Cómo puedo hacer un gestor de arranque (para cualquier microcontrolador)?

Después de escribir mi cargador de arranque, ¿cómo se programa el microcontrolador (como cualquier programa .hex grabado en la memoria flash del AVR, o algún otro método)?

Lo etiquetó con la etiqueta del cargador de arranque , ¿lo leyó? Si es así, ¿ha leído las preguntas Arduino Bootloader , Arduino Bootloader Follow On , Arduino Bootloader , Buenas herramientas o métodos para comprender la estructura del cargador de arranque y Detalles del cargador de arranque Arduino ? Todos ellos abordan partes de su pregunta inicial. Lo he recortado a las cosas nuevas.
Un artículo sobre el método de diseño de BootLoader: beningo.com/wp-content/uploads/images/Papers/…
@KevinVermeer Creo que su pregunta es más sencilla.

Respuestas (3)

Un gestor de arranque es un programa que se ejecuta en el microcontrolador para ser programado. Recibe nueva información del programa externamente a través de algún medio de comunicación y escribe esa información en la memoria del programa del procesador.

Esto contrasta con la forma normal de introducir el programa en el microcontrolador, que es a través de un hardware especial integrado en el micro para ese fin. En PIC, esta es una interfaz similar a SPI. Si no recuerdo mal, los AVR usan Jtag, o al menos algunos de ellos lo hacen. De cualquier manera, esto requiere algún hardware externo que mueva los pines de programación a la perfección para escribir la información en la memoria del programa. El archivo HEX que describe el contenido de la memoria del programa se origina en una computadora de uso general, por lo que este hardware se conecta a la computadora por un lado y los pines de programación especiales del micro por el otro. Mi empresa fabrica programadores de PIC, entre otras cosas, como actividad secundaria, por lo que estoy bastante familiarizado con este proceso en PIC.

El punto importante de la programación externa a través de hardware especializado es que funciona independientemente del contenido existente de la memoria del programa. Los microcontroladores comienzan con la memoria del programa borrada o en un estado desconocido, por lo que la programación externa es el único medio para obtener el primer programa en un micro.

Si está seguro del programa que desea cargar en su producto y sus volúmenes son lo suficientemente altos, puede hacer que el fabricante o un distribuidor programe chips para usted. El chip se suelda a la placa como cualquier otro chip y la unidad está lista para funcionar. Esto puede ser apropiado para algo como un juguete, por ejemplo. Una vez que el firmware está listo, está casi terminado y se producirá en grandes volúmenes.

Si sus volúmenes son más bajos o, lo que es más importante, espera un desarrollo de firmware continuo y correcciones de errores, no querrá comprar chips preprogramados. En este caso, los chips en blanco se montan en la placa y el firmware debe cargarse en el chip como parte del proceso de producción. En ese caso, las líneas de programación de hardware deben estar disponibles de alguna manera. Esto puede ser a través de un conector explícito o almohadillas de pines pogo si está dispuesto a crear un accesorio de prueba de producción. A menudo, estos productos deben probarse y tal vez calibrarse de todos modos, por lo que el costo adicional de escribir el programa en el procesador suele ser mínimo. A veces, cuando se utilizan procesadores pequeños, primero se carga un firmware de prueba de producción especial en el procesador. Esto se utiliza para facilitar la prueba y calibración de la unidad, luego, el firmware real se carga después de que se sabe que el hardware es bueno. En este caso, hay algunas consideraciones de diseño de circuito para permitir el acceso a las líneas de programación lo suficiente para que funcione el proceso de programación, pero también para no incomodar demasiado al circuito. Para más detalles sobre esto, vea miescritura de programación en circuito .

Hasta ahora todo bien, y no se necesita gestor de arranque. Sin embargo, considere un producto con un firmware relativamente complejo que desee actualizar en el campo o incluso permitir que el cliente final lo actualice. No puede esperar que el cliente final tenga un dispositivo de programador o sepa cómo usarlo correctamente, incluso si se lo proporcionó. En realidad, uno de mis clientes hace esto. Si compra su opción de personalización de campo especial, obtiene uno de mis programadores con el producto.

Sin embargo, en la mayoría de los casos, solo desea que el cliente ejecute un programa en una PC y tenga el firmware actualizado mágicamente. Aquí es donde entra en juego un cargador de arranque, especialmente si su producto ya tiene un puerto de comunicaciones que puede interactuar fácilmente con una PC, como USB, RS-232 o ethernet. El cliente ejecuta un programa de PC que se comunica con el cargador de arranque que ya está en el micro. Esto envía el nuevo binario al cargador de arranque, que lo escribe en la memoria del programa y luego hace que se ejecute el nuevo código.

Suena simple, pero no lo es, al menos no si desea que este proceso sea sólido. ¿Qué pasa si ocurre un error de comunicación y el nuevo firmware está corrupto cuando llega al gestor de arranque? ¿Qué sucede si se interrumpe la alimentación durante el proceso de arranque? ¿Qué pasa si el cargador de arranque tiene un error y se caga en sí mismo?

Un escenario simplista es que el gestor de arranque siempre se ejecuta desde el reinicio. Intenta comunicarse con el anfitrión. Si el host responde, le dice al gestor de arranque que no tiene nada nuevo o le envía un código nuevo. A medida que llega el código nuevo, el código anterior se sobrescribe. Siempre incluye una suma de verificación con el código cargado, para que el cargador de arranque pueda saber si la nueva aplicación está intacta. Si no, permanece en el gestor de arranque constantemente solicitando una carga hasta que se cargue en la memoria algo con una suma de comprobación válida. Esto podría ser aceptable para un dispositivo que siempre está conectado y posiblemente donde se ejecuta una tarea en segundo plano en el host que responde a las solicitudes del cargador de arranque. Este esquema no es bueno para las unidades que son en gran parte autónomas y solo ocasionalmente se conectan a una computadora host.

Por lo general, el cargador de arranque simple como se describe anteriormente no es aceptable ya que no hay seguridad contra fallas. Si una nueva imagen de la aplicación no se recibe intacta, desea que el dispositivo continúe ejecutando la imagen anterior, que no esté muerto hasta que se realice una carga exitosa. Por esta razón, normalmente hay dos módulos especiales en el firmware, un cargador y un gestor de arranque. El cargador es parte de la aplicación principal. Como parte de las comunicaciones regulares con el host, se puede cargar una nueva imagen de la aplicación. Esto requiere una memoria separada de la imagen de la aplicación principal, como una EEPROM externa o usar un procesador más grande para que la mitad del espacio de la memoria del programa se pueda asignar para almacenar la nueva imagen de la aplicación. El cargador simplemente escribe la nueva imagen de la aplicación recibida en algún lugar, pero no la ejecuta. Cuando se reinicia el procesador, lo que podría ocurrir por orden del host después de una carga, se ejecuta el gestor de arranque. Este es ahora un programa totalmente autónomo que no necesita capacidad de comunicación externa. Compara las versiones de la aplicación actual y cargada, verifica sus sumas de verificación y copia la nueva imagen en el área de la aplicación si las versiones difieren y la suma de verificación de la nueva imagen se verifica. Si la nueva imagen está dañada, simplemente ejecuta la aplicación anterior como antes.

He hecho un montón de gestores de arranque, y no hay dos iguales. No existe un cargador de arranque de propósito general, a pesar de lo que algunas de las compañías de microcontroladores quieren que creas. Cada dispositivo tiene sus propios requisitos y circunstancias especiales al tratar con el host. Estas son solo algunas de las configuraciones del cargador de arranque y, a veces, del cargador que he usado:

  1. Cargador de arranque básico. Este dispositivo tenía una línea serie y se conectaría a un host y se encendería según fuera necesario. El cargador de arranque se ejecutó desde el reinicio y envió algunas respuestas de solicitud de carga al host. Si el programa de carga se estaba ejecutando, respondería y enviaría una nueva imagen de la aplicación. Si no respondía dentro de los 500 ms, el cargador de arranque se daría por vencido y ejecutaría la aplicación existente. Por lo tanto, para actualizar el firmware, primero tenía que ejecutar la aplicación de actualización en el host, luego conectar y encender el dispositivo.

  2. Cargador de memoria de programa. Aquí usamos el siguiente tamaño de PIC que tenía el doble de memoria de programa. La memoria del programa se dividió aproximadamente en 49 % de la aplicación principal, 49 % de la nueva imagen de la aplicación y 2 % del gestor de arranque. El cargador de arranque se ejecutaría desde el reinicio y copiaría la nueva imagen de la aplicación en la imagen de la aplicación actual en las condiciones adecuadas.

  3. Imagen EEPROM externa. Como el n.° 2, excepto que se usó una EEPROM externa para almacenar la nueva imagen de la aplicación. En este caso, el procesador con más memoria también habría sido físicamente más grande y en una subfamilia diferente que no tenía la combinación de periféricos que necesitábamos.

  4. Cargador de arranque TCP. Este fue el más complejo de todos. Se utilizó un PIC 18F grande. El último 1/4 de la memoria contenía el gestor de arranque, que tenía su propia copia completa de una pila de red TCP. El cargador de arranque se ejecutó desde el reinicio e intentó conectarse a un servidor de carga especial en un puerto conocido en una dirección IP previamente configurada. Esto era para grandes instalaciones donde siempre había una máquina de servidor dedicada para todo el sistema. Cada dispositivo pequeño se registraría en el servidor de carga después del reinicio y se le daría una nueva copia de la aplicación según corresponda. El cargador de arranque sobrescribiría la aplicación existente con la nueva copia, pero solo la ejecutaría si se verificara la suma de verificación. De lo contrario, volvería al servidor de carga y volvería a intentarlo.

    Dado que el cargador de arranque era en sí mismo una pieza de código complicada que contenía una pila de red TCP completa, también tenía que ser actualizable en el campo. La forma en que lo hicimos fue hacer que el servidor de carga lo alimentara con una aplicación especial cuyo único propósito era sobrescribir el cargador de arranque una vez que se ejecutaba, luego reiniciar la máquina para que se ejecutara el nuevo cargador de arranque, lo que haría que el servidor de carga enviara el última imagen principal de la aplicación. Técnicamente, una falla de energía durante los pocos milisegundos que le tomó a la aplicación especial copiar una nueva imagen sobre el cargador de arranque sería una falla irreparable. En la práctica esto nunca sucedió. Estábamos de acuerdo con la posibilidad muy poco probable de que eso sucediera, ya que estos dispositivos eran parte de grandes instalaciones donde ya había personas que se encargarían del mantenimiento del sistema, lo que ocasionalmente significaba reemplazar los dispositivos integrados por otras razones de todos modos.

Es de esperar que pueda ver que hay una serie de otras posibilidades, cada una con sus propias compensaciones de riesgo, velocidad, costo, facilidad de uso, tiempo de inactividad, etc.

Todos los AVR excepto la familia Xmega (que tiene una nueva interfaz de 2 hilos) usan una interfaz SPI mientras se mantienen en reinicio. Los más grandes también tienen JTAG, algunos tienen programación paralela y los más pequeños pueden requerir alto voltaje si el reinicio se ha reconfigurado como E/S. Algunas MCU, como las familias Parallax Propeller y Motorola/Freescale 68HC08, no tienen hardware de programación mínimo, sino cargadores de arranque en ROM.
Compara las versiones de la aplicación actual y cargada, verifica sus sumas de verificación y copia la nueva imagen en el área de la aplicación si las versiones difieren y la suma de verificación de la nueva imagen se verifica. Sí, pero ¿y si se interrumpe la energía en medio de esta acción? Habría una imagen corrupta en el "área de la aplicación". Supongo que puede ser mejor tener una aplicación bootloader-failsafe que escriba la nueva aplicación en el flash mcu y si la suma de verificación es válida, también escribe en algún lugar "ok para iniciar la nueva aplicación". Entonces, al inicio, verifica si está bien iniciar la nueva aplicación, si no es así, continúa ejecutándose (aplicación a prueba de fallas)
@Erv: si falla la energía en medio de la copia de la nueva versión en la actual, la suma de verificación de la versión actual fallará cuando vuelva la energía y el cargador de arranque se ejecute nuevamente. Por lo general, coloco la palabra de suma de verificación al final de la imagen para que cualquier escritura parcial tenga una muy buena posibilidad de fallar en la suma de verificación.
Hola. Puedo recomendarle el cargador de arranque tipo 5: en lugar de la pila TCP, puede implementar UDP. Luego use TFTP para descargar la actualización o el protocolo nativo.
No estoy seguro si "Un cargador de arranque es un programa que se ejecuta en el microcontrolador para ser programado". siempre es 100% correcto. Puede haber cargadores de arranque que solo carguen la aplicación y luego salten a ella. Proporcionar capacidad de actualización es una necesidad típica, pero no imprescindible, diría yo.

¿Cuál es el concepto del gestor de arranque?

Imagínese este escenario: tiene una buena cantidad de almacenamiento en su microcontrolador, suficiente para almacenar más de 2 o 3 programas o aplicaciones que son independientes entre sí. Suponga que cuando inicia su dispositivo, es posible que desee poder elegir cuál ejecutar. Entonces, ¿qué necesitarías para apoyar esto? Necesitará un programa de inicio que luego le permita elegir entre los demás en el momento del arranque.

¿Cómo funciona?

Un cargador de arranque es ese programa: es lo primero que se ejecuta y puede cargar otras aplicaciones en lugares específicos de la memoria (ya sea persistente como FLASH o volátil como RAM) y luego salta al programa deseado donde luego se hará cargo de la ejecución desde allí. .

¿Cómo hacer un cargador de arranque avr (o para cualquier microcontrolador)?

Nunca he creado un gestor de arranque, pero así es como creo que lo haría: comience a escribir un programa de firmware tal como lo haría normalmente, pero asegúrese de que esté ubicado en un área tal que siempre sea lo primero que se ejecute cuando el dispositivo arranca. En la parte superior de mi cabeza, algunas de las funciones que me gustaría tener en este pequeño programa: la capacidad de cargar un nuevo programa en un lugar disponible en la memoria, borrar un programa previamente cargado, elegir qué programa ejecutar (si hay más de one), y tener algún tipo de estructura de almacenamiento de datos (¿tabla de saltos que se pueda hacer crecer?) para poder recordar dónde están los otros programas y saltar a ellos. La interacción se puede realizar a través de UART, donde puede presentarle un menú de terminal muy simple y la capacidad de cargar firmware a través de ese mismo canal.

¿Cómo se programa el microcontrolador (como cualquier programa .hex grabado en la flash rom del avr, o algún otro método)?

Si se trata de un chip completamente en blanco sin un gestor de arranque existente que pueda actualizarse a sí mismo, entonces deberá grabarlo en FLASH como lo describió utilizando cualquier técnica necesaria para lograrlo (ICSP en el caso de AVR).

Esto de ninguna manera es completo de lo que son los "cargadores de arranque". Dependiendo de lo que desee de uno o del sistema para el que está diseñado, puede diseñar uno para cargar cosas en una ubicación específica en RAM en lugar de FLASH, y comenzar la ejecución en cualquier ubicación de memoria arbitraria. O tal vez desee uno que sea capaz de elegir qué sistema operativo cargar cuando se inicia su PC (ver grub , por ejemplo). Los cargadores de arranque para microcontroladores de 8 bits tienden a ser muy simples.

Una nota sobre Arduino: este cargador de arranque solo administra un programa AFAIK, también se hace cargo del puerto serie para administrar la carga de firmware y otras cosas .

FYI, la respuesta se escribió para abordar los puntos originales que ahora se han eliminado.

El concepto de un cargador de "arranque" es similar al concepto de "cebar" una bomba. En otras palabras, necesita "algo" que cargue un programa en una dirección dada y luego comience a ejecutar el programa en esa dirección dada. Ese algo, es el gestor de arranque. En el caso más simple, el cargador de arranque "aparece" en la dirección de inicio designada de la CPU (cero, lo más probable), carga el programa en el segmento de memoria requerido, le transfiere el control y "desaparece". La aparición y desaparición están controladas por hardware "externo". Una posible implementación sería mediante el uso de una ROM que se activa a través de un reinicio de "hardware" y se desactiva con un reinicio de "software". El cargador en la ROM puede ser tan simple o tan complejo como se requiera, y debe escribirse en la forma binaria que la CPU en particular entienda. Si no se necesita el espacio de direcciones utilizado por la ROM, no será necesaria la desactivación de la ROM. Obviamente, se podría usar EEPROM, ePROM, flash PROM, etc. en lugar de la ROM.