Cargador de arranque personalizado que pasa el control al código de la aplicación en STM32

Estoy tratando de entender que si para STM32F405 MCU se usa un cargador de arranque personalizado en la MCU, entonces cada uno de los dos proyectos para el cargador de arranque personalizado y el código de la aplicación tendrán sus propios archivos "startup.s".

Lo que entiendo es que los dos binarios, es decir, el gestor de arranque y el código de la aplicación, residen en ubicaciones diferentes en la memoria flash.

Ahora, cuando el gestor de arranque personalizado salga y devuelva el control, el control debería pasar al código de inicio del código de la aplicación. Pero no sé cómo sucede realmente. ¿Los dos programas binarios residen en ubicaciones contiguas para que después de que finalice el gestor de arranque, la siguiente instrucción sea la del código de inicio?

¿O están en diferentes ubicaciones y de alguna manera la dirección de inicio del código de la aplicación se guarda como dirección de salto al final del binario del gestor de arranque?

¿Hará una diferencia en la forma en que se implementa realmente si uso el compilador Keil o GCC?

Si bien ha recibido respuestas que en su mayor parte son correctas, pasan por alto muchos detalles clave. Hay varias preguntas existentes aquí que cubren las dificultades prácticas que probablemente encuentre al transferir el control de un programa a otro, particularmente con respecto a la configuración del chip... En muchos casos, es mejor establecer una bandera, reiniciar la CPU y luego detecte el indicador en el ensamblado de inicio y bifurque al objetivo antes de que se puedan ejecutar las funciones de inicialización del cargador de arranque y vuelva a poner el chip en un estado diferente al que espera el programa principal.
¿Por qué necesitamos restablecer la CPU para controlar la transferencia del gestor de arranque al programa principal?

Respuestas (2)

La imagen compilada de una aplicación STM32 comienza con una tabla de vectores, en la que la primera palabra contiene el valor del puntero de pila inicial, la siguiente tiene la dirección de la primera instrucción.

El cargador de arranque obviamente debe saber la dirección en la que se carga la aplicación (¿cómo podría cargarla de otra manera?), para que pueda ver las dos primeras palabras de la imagen que acaba de mostrar.

Debe tener en cuenta el diseño de los sectores flash al decidir la dirección de inicio de la aplicación. Si partes del cargador de arranque y la aplicación terminan en el mismo sector flash, entonces el cargador de arranque no podrá actualizar la aplicación.

ingrese la descripción de la imagen aquí

Los diseñadores de este MCU habían dispuesto algunos sectores más cortos al comienzo del flash exactamente para este propósito. Es posible que desee reservar 32k para el cargador de arranque y colocar la aplicación en, 0x08008000por ejemplo, depende de usted (y de la complejidad del cargador de arranque).

¿Hará una diferencia en la forma en que se implementa realmente si uso el compilador Keil o GCC?

La única diferencia estaría en los archivos de configuración del enlazador, que le indican al enlazador dónde cargar la aplicación. El enlazador GNU lo toma de un script de enlazador ( *.ld), Keil lo llama archivo de dispersión . Tienen el mismo propósito, pero diferente sintaxis. También debe ajustar la secuencia de comandos del enlazador/archivo de dispersión del cargador de arranque, limitando la cantidad de flash disponible para él.

El compilador no importa, uno puede usarse para el gestor de arranque y otro para la aplicación. Primero escribes el cargador de arranque y ves qué tan grande es. Luego, redondea al límite del sector flash más cercano, ya que no desea borrar un sector con el código del cargador de arranque. Haga que el gestor de arranque salte al inicio del primer sector libre. Y luego indique al enlazador que genere código para que el código de la aplicación no se cargue al inicio de flash (el cargador de arranque está allí) sino al inicio del primer sector libre después del cargador de arranque.

"Haz que el gestor de arranque salte al inicio del primer sector libre". ¿Significa que mientras escribimos el 'Bootloader' debemos saber de antemano dónde saltar después de que salga el cargador de arranque? Entonces, ¿escribiremos esa dirección de salto como la última instrucción en el código del gestor de arranque? ¿O tenemos que escribir la dirección de salto fuera del código del gestor de arranque en algún otro lugar de los otros archivos?
Si lo hace como sugerí, sí, entonces usted mismo predetermina la dirección de inicio de la aplicación y hace que el gestor de arranque y la aplicación conozcan sus direcciones. Siéntase libre de implementar esquemas más complejos si lo desea. Sí, el cargador de arranque saltará fuera de su espacio de código, a la dirección que especifique en el código del cargador de arranque, y esa es la dirección donde comienza el espacio de código de la aplicación. Cuando estos archivos binarios se cargan en MCU, no hay concepto de archivos, solo direcciones a las que puede saltar. Disculpa si no entiendo lo que preguntas.
En esencia, lo que se propone aquí no es saltar a una dirección fija, sino poner un puntero a la dirección adecuada en un lugar fijo. Dado que así es como el hardware inicia el chip de todos modos, tomar prestado ese mecanismo tiene mucho sentido. Y si hace esto, puede simplemente copiar el bloque vectorial de la aplicación al inicio de flash donde iría el cargador de arranque, y ejecutar la aplicación sin el cargador de arranque también, lo que a veces simplifica la depuración.
@ChrisStratton en realidad eso es lo que debe suceder. Es la forma estándar en que se inicia el STM32, carga el puntero de pila y el puntero de instrucciones desde el comienzo del flash. Y por la misma lógica, como la aplicación debe vincularse para comenzar en una dirección posterior, el gestor de arranque debe conocer esta dirección donde buscar el puntero de pila y el puntero de instrucción de la aplicación, y luego saltar a esa dirección. Por lo tanto, la aplicación es solo una aplicación estándar, pero se puede vincular normalmente para habilitar la depuración sin cargador de arranque, o vincularla especialmente a una dirección posterior.