BootLoader es un término común para muchas personas, e incluso se utiliza con frecuencia. Por ejemplo, lo necesitamos cuando actualizamos el sistema en línea o ejecutamos el programa en la memoria externa. En esta publicación, presentaremos cómo diseñar un programa BootLoader para la serie MCU STM32.
Principio básico del gestor de arranque
Dado que queremos implementar un programa BootLOader para STM32, primero debemos comprender los principios básicos del programa BootLOader.
Como sabemos, el programa BootLOader debe servir para guiar al sistema, que es la función básica del programa BootLOader. Para la serie MCU STM32, el programa se ejecutará desde la dirección de inicio de la memoria Flash interna después de que el sistema se inicie. A continuación, se introduce el programa de aplicación y se ejecuta según el orden establecido. En este momento, el BootLoader y el programa de aplicación están integrados, como se muestra en la figura:

Pero a veces no queremos que la aplicación se ejecute directamente, como cuando queremos implementar IAP para el sistema; o no queremos que la aplicación se ejecute en nuestra memoria Flash interna; o la aplicación se ejecuta en la memoria Flash interna, pero queremos que se ejecute desde la dirección de memoria Flash interna que especifiquemos, etc. En estos casos, necesitamos un programa BootLoader independiente. El sistema inicia primero el programa BootLoader y, una vez que el sistema está listo, entra en la ejecución del programa de aplicación, como se muestra en la figura:

En la imagen anterior, almacenamos la aplicación en la ubicación especificada de la memoria Flash interna, lo que, por supuesto, nos permite satisfacer algunas de nuestras necesidades, como el IAP del sistema. Por supuesto, también podemos almacenar el programa de aplicación en la memoria Flash externa, y entonces el programa BootLoader salta a la memoria Flash externa para ejecutar el programa de aplicación, pero la premisa es que la memoria Flash externa adquiera el programa de ejecución. El proceso específico es el siguiente:

Por supuesto, esto es solo un ejemplo, y solo tenemos que modificar la dirección para diferentes memorias. En cuanto a las funciones que se implementarán en el programa BootLoader, depende del uso. En principio, podemos añadir cualquier función que queramos, como detección de hardware, actualización del sistema, etc.
Diseño del cargador de arranque para STM32
Planificación rápida
Utilizamos STM32F407IGT6 como MCU de destino, que tiene 1 MB de memoria Flash y 192 KB de SRAM. Dividimos la memoria Flash en dos partes, una es el área del programa de arranque (0x0800 0000 – 0x0800 3FFF) con un tamaño de 16 Kbytes, y el resto es el área del programa de aplicación (0x0800 4000 – 0x080F FFFF). La distribución específica es la siguiente:

Dejamos que el programa BootLoader ocupe 16 K de espacio de almacenamiento. Pero puede operar todo el espacio de almacenamiento Flash.
Estructura del gestor de arranque
Consideremos la estructura del programa BootLoader. El objetivo principal de nuestro diseño del programa BootLoader es actualizar el programa de aplicación. Entonces, ¿cuáles son las funciones principales que deben implementarse en el programa BootLoader? Hay varios aspectos que deben incluirse. Uno es la configuración básica, como el reloj, etc., que implementamos en el programa principal; el otro es el funcionamiento de la memoria Flash, y sin duda comprobaremos y escribiremos la memoria Flash cuando actualicemos el programa de aplicación; es el programa de control de salto, necesitamos ejecutar el programa de aplicación al final, y la función de salto es esencial. Por supuesto, puede haber otras necesidades según las diferentes necesidades. Concretamente, como se muestra en la siguiente figura:

En la figura anterior, además de las tres implementaciones básicas de firma, también hemos añadido la función de obtener archivos IAP. Esta parte de la función también es necesaria, pero puede haber una gran diferencia entre los distintos modos. Esto se debe a que la forma de obtener los archivos puede ser a través de diversos tipos de comunicación, como el puerto Ethernet, el puerto serie, etc. También puede ser a través de diversos tipos de memoria, como tarjetas SD, discos U, etc. Por lo tanto, aunque esta función es esencial, el método de implementación es muy flexible. En la implementación posterior, analizaremos en detalle cuestiones específicas.
Implementación del gestor de arranque
Ahora que hemos determinado la división de Flash y comprendemos el flujo de trabajo básico de BootLoader, a continuación explicaré cómo implementar un programa BootLoader.
Codificación del gestor de arranque
Sabemos que cuando se enciende el chip, primero ejecuta el programa BootLoader y, a continuación, salta al área del programa de aplicación para ejecutar el programa de aplicación. Por lo tanto, cuando escribimos el programa BootLoader, primero evaluamos si el sistema tiene requisitos IAP. Si hay una solicitud IAP, entrará en el modo IAP. Una vez completado, saltará al programa de aplicación para su ejecución. Si no hay ninguna solicitud IAP, saltará directamente al programa de aplicación para su ejecución. El proceso específico es el siguiente:

En cuanto al procesamiento de IAP, habrá diferentes métodos de procesamiento en diferentes situaciones. Aquí nos centraremos principalmente en el programa de control de salto. Primero, defina la primera dirección de la aplicación y declare un tipo de puntero de función. Los detalles son los siguientes:
#define ApplicationAddress 0x08004000 //Application first address definition
typedef void (*pFunction)(void); //Define the jump function pointer type
Algunas personas pueden preguntarse qué define ese tipo de puntero de función, ya que finalmente saltamos a la función Reset_Handler, por lo que debemos tener un puntero de función que pueda apuntar a esta función. A continuación, podemos implementar el programa de salto.
/*jump to application processing function*/
static void JumpToApplication(void)
{
uint32_tStackAddr; //Application stack address
uint32_tResetVector; //The address of the application interrupt vector table
pFunctionJumpToApp; //Define the jump function pointer
__set_PRIMASK(1); //Turn off global interrupt
StackAddr= *(__IO uint32_t*)ApplicationAddress; //0x08004000;
ResetVector = *(__IO uint32_t*)(ApplicationAddress + 4); //0x08004004;
if((StackAddr&0x2FFC0000)==0x20000000) //Check whether the stack top address is legal.
{
__set_MSP(StackAddr); //Initialize the application stack pointer
JumpToApp = (pFunction)ResetVector;
JumpToApp();
}
}
Procesamiento de aplicaciones
Después de realizar la codificación del BootLoader, si queremos pasar a la aplicación para que se ejecute correctamente, debemos modificar la aplicación en consecuencia. Hay dos cambios importantes. Si la aplicación es un programa bare-metal, debemos habilitar el rango medio global antes de configurar el reloj.
/*Enable global interrupt, closed in BootLoader*/
__set_PRIMASK(0);
Al mismo tiempo, también es necesario modificar la dirección de desplazamiento de la tabla de vectores de gama media. Para el STM32F07 que utilizamos, se puede modificar directamente en el archivo system_stm32f4xx.c.
#define VECT_TAB_OFFSET 0x4000 /*!< Vector Table base offsetfield.
A continuación, también debemos realizar las modificaciones necesarias en el entorno de desarrollo, tomando como ejemplo el IAR EWARM V8.4 que utilizamos. Modifique la configuración de la tabla de vectores de interrupción y el área de almacenamiento Flash en el archivo icf. Los detalles son los siguientes:


Después de completar la configuración anterior, podemos descargar el programa de aplicación y el programa BootLoader para realizar el salto correcto.
Resumen
En este artículo, solo hemos implementado un programa BootLoader sencillo. Tras descargarlo en la MCU de destino, se realiza el salto y el programa de aplicación también se ejecuta con normalidad, lo que demuestra que nuestro diseño es correcto y que se pueden añadir diversas funciones sobre esta base para realizar la aplicación IAP correspondiente.
Cabe señalar que hemos desactivado la interrupción global en el programa BootLoader, y hay que recordar habilitar la interrupción global antes de que la aplicación inicialice el reloj del sistema, de lo contrario SystemTick no podrá funcionar y se producirá un fallo de hardware (hardfault). Sin embargo, si la aplicación se ejecuta en el RTOS, puede ser un error activar la interrupción, lo que requiere atención.




