Interface logicielle (API) - Cœur (Cortex-M*) - Bootstrap

De Wiki Techno-Innov
< Technique‎ | Logiciel‎ | API‎ | Use‎ | Core
Aller à la navigation Aller à la recherche


Note préalable :
Les éléments décrits ici sont ceux utilisés par l'API décrite dans ces pages pour les micro-contrôleurs LPC de NXP, cependant ces principes restent applicables pour de nombreux micro-contrôleurs d'autres familles ou d'autres fabricants.

Mécanisme de démarrage

Lors de la mise sous tension, les micro-contrôleurs LPC commencent par l'exécution du code de leur "Boot ROM" qui a la charge de mettre le micro-contrôleur dans son état par défaut (valeurs des registres initialisées à leur valeur par défaut), de vérifier l'état de la pin "ISP" pour déterminer le mode de démarrage (programmation ou normal), et de vérifier la validité du programme présent en Flash (checksum des premières entrées de la table des vecteurs d'interruption).

En démarrage normal, le micro-contrôleur commence l'exécution du code utilisateur en chargeant l'adresse du "reset handler" présent dans la table des vecteurs d'interruption.
Voir la section sur le fonctionnement des Interruptions pour plus d'informations sur cette table et l'enregistrement des handlers (routines de gestion des interruptions / exceptions).

L'exécution commence donc par la routine de gestion de l'exception "Reset", qui doit obligatoirement être définie.

Initialisations

La routine de gestion de l'exception "Reset" a la charge des initialisations qu'un programme "classique" délègue à la bibliothèque C, puisque nous n'avons pas de bibliothèque C ni de système d'exploitation.

RAM

Sa fonction principale est l'initialisation de la RAM du micro-contrôleur.
Lors de la compilation, toutes les variables initialisées à une valeur non nulle sont placées dans une section spécifique du binaire qui est mis en Flash. Les données présente en Flash ne sont pas modifiables octet par octet ou mot par mot, et ne peuvent donc pas être utilisées telles quelles depuis la flash par le programme.
Elles doivent être préalablement copiées en RAM, à l'adresse définie par le compilateur (l'éditeur de liens pour être précis) en fonction du contenu du script d'édition de liens. (Voir la section Édition de lien et création des binaires pour plus de détails sur cette opération).
Le"Reset_handler" copie les valeurs initiales des variables depuis la Flash vers leur adresse en RAM, et charge ensuite de mettre à 0 une partie de la RAM pour les données initialisées à 0. Les adresses et les tailles nécessaires à la copie et à l'initialisation sont stockées dans une série de variables dont les valeurs sont remplies par l'éditeur de lien :

extern unsigned int _end_text;
extern unsigned int _start_data;
extern unsigned int _end_data;
extern unsigned int _start_bss;
extern unsigned int _end_bss;

Autres initialisations

Cette routine se charge aussi d'initialiser les routines ROM en faisant appel à la fonction rom_helpers_init(), dont le contenu dépends de chaque micro-contrôleur et des routines ROM présentes.

Le choix a été fait de limiter les initialisations à ces quelques éléments, pour laisser le contrôle de l'initialisation des différents périphériques à la personne en charge d'écrire le programme (à partir d'un exemple au besoin), pour ne pas masquer le fonctionnement du système, et coller au plus prêt à ce que le programmeur peut retrouver dans un programme en C classique. (Par opposition au choix fait par d'autres interfaces qui contraignent l'utilisateur à utiliser deux fonctions "setup" et "loop" en masquant le reste du fonctionnement du programme embarqué).

Appel du main()

Une fois les initialisations terminées, le "Reset_handler" fait appel à la fonction main(), qui est le point d'entrée d'un programme classique en C.

La fonction main() doit avoir l'une des définitions suivantes :

int main(void);
void main(void);

Aucun paramètre n'est passé à la fonction main(), car cela n'a pas de sens sur un micro-contrôleur, le programme n'étant pas appelé par un système de plus bas niveau, puisque le programme constitue le système fonctionnant sur le micro-contrôleur.

La valeur de retour est ignorée si il y en a une. Cependant, la fonction main() ne DOIT PAS se terminer. Elle doit inclure une boucle infinie correspondant au cycle d'exécution normal du programme, précédée par les initialisations nécessaires au fonctionnement du programme.