Pourquoi avons-nous besoin d'un chargeur de démarrage distinct de notre programme d'application dans les microcontrôleurs?

28

Pourquoi avons-nous besoin d'un programme distinct dans la même mémoire de programme flash d'un microcontrôleur, en particulier STM32F103, qui est appelé un chargeur de démarrage?

Quelle est la particularité de le garder séparé du programme d'application principal?

De manière générale, un chargeur de démarrage d'un système à microprocesseur (par exemple PowerPC MPC8270) fait-il le même travail que celui d'un microcontrôleur (par exemple ARM STM32F103) ou fait-il des travaux fondamentalement différents les uns des autres et pourtant les deux sont appelés un `` chargeur de démarrage '' ?

alt-rose
la source
2
la même raison pour laquelle vous avez des puces et des pièces individuelles et pas une seule structure monolithique géante
Emobe
Non. Entrez simplement votre programme avec les interrupteurs et les voyants de la console d'ordinateur.
Hot Licks
1
À strictement parler, vous n'avez pas besoin d'un programme de chargeur de démarrage distinct sur un microcontrôleur. Mais nous choisissons le plus souvent d'en avoir un pour les fonctions utilitaires supplémentaires qu'il offre. Si ces fonctions ne sont pas nécessaires, non souhaitées, vous pouvez supprimer le chargeur de démarrage. Le chargeur de démarrage du microcontrôleur est généralement utilisé pour graver un nouveau programme en flash. Il peut parfois être utilisé pour les fonctions de débogage, certains points d'arrêt de support et d'autres fonctions agréables à avoir. Sur un micro-ordinateur, le chargeur de démarrage charge généralement les programmes à partir de la mémoire de masse et y sera nécessaire.
ghellquist

Réponses:

55

Un chargeur de démarrage sur un microcontrôleur est responsable de la mise à jour du micrologiciel principal sur un canal de communication autre que l'en-tête de programmation. Ceci est utile pour mettre à jour le firmware sur le terrain via BLE, UART, I2C, cartes SD, USB, etc. Il serait extrêmement gênant d'exiger des clients qu'ils achètent des programmeurs juste pour mettre à jour le firmware sur leurs appareils.

La raison pour laquelle le chargeur de démarrage est conservé séparément est pour la fiabilité. Le chargeur de démarrage et le code d'application sont placés dans des sections distinctes de Flash, de sorte que le code d'application peut être effacé et réécrit par le chargeur de démarrage sans changer quoi que ce soit lié au code du chargeur de démarrage.

Si le chargeur de démarrage et l'application étaient conservés ensemble, le code du chargeur de démarrage devrait être copié dans la RAM avant de pouvoir s'exécuter, car toute mise à jour du micrologiciel effacerait le code du chargeur de démarrage en flash. Si l'alimentation était coupée avec le code du chargeur de démarrage dans la RAM et que le flash était effacé, l'appareil serait maçonné.

CurtisHx
la source
3
La nôtre est la même raison. Ils sont dans le même flash, mais le chargeur de démarrage est aligné sur les limites de l'effacement du flash et suffisamment intelligent pour effacer le flash uniquement plus haut que ses propres adresses.
Joshua
3
Dans certains cas, l'en-tête de programmation du microprocesseur peut en fait être inaccessible sans avoir à démonter le châssis du produit, donc pouvoir le reprogrammer sur le bus de communication sans matériel supplémentaire est un facteur clé de fiabilité.
John Go-Soco
6
@ alt-rose Le chargeur de démarrage et le programme d'application sont des programmes compilés séparément, chacun avec son propre code de démarrage et sa propre main()fonction. À la mise sous tension, le code de démarrage du chargeur de démarrage s'exécute et appelle le chargeur de démarrage main(). Le programme de chargeur de démarrage recherche un programme d'application valide, puis passe au code de démarrage du programme d'application qui appelle celui-ci main(). Le code de démarrage de chaque programme initialise l'environnement d'exécution C pour le programme respectif (c'est-à-dire initialise les variables, la pile, etc.) et généralement, aucun des programmes main()ne revient jamais au code de démarrage.
kkrambo
1
@ alt-rose: De la même manière que le CPU obtient l'adresse de départ du chargeur de démarrage - ce n'est pas le cas. Au lieu de cela, le CPU spécifie ce qu'il utilisera comme adresse de démarrage du chargeur de démarrage et le chargeur de démarrage spécifie ce qu'il utilisera comme adresse de démarrage du programme d'application.
MSalters
4
@kkrambo Bien que cela soit généralement vrai, il n'y a aucune exigence (ni fait universellement vrai) qu'un chargeur de démarrage soit écrit en C ou dans un langage dérivé de C avec a maindu tout.
Yakk
26
  1. Pour que le processus de chargement puisse récupérer des erreurs. Supposons qu'il y ait une erreur de communication ou une coupure d'alimentation pendant une mise à niveau. Si le chargeur de démarrage faisait partie de l'application que vous mettiez à niveau, l'utilisateur ne pourrait pas réessayer sans utiliser de matériel spécial pour reflasher le chargeur de démarrage.

  2. Certains microcontrôleurs ne peuvent pas exécuter de code à partir de la RAM. Si le chargeur de démarrage était mélangé avec le reste du logiciel, vous ne seriez pas en mesure de mettre à niveau votre logiciel car vous ne pouvez pas effacer les pages de flash que vous exécutez actuellement. La solution consiste à graver d'abord le nouveau code dans la seconde moitié du flash, puis à y accéder. Le nouveau code se copie ensuite dans la première moitié du flash. Bien sûr, l'inconvénient est que la gravure du flash est généralement lente et maintenant que vous devez le faire deux fois, le processus de chargement peut prendre jusqu'à deux fois plus de temps. Cette solution de contournement limite également la taille de votre application à pas plus de la moitié de votre flash total.

  3. Des chargeurs de démarrage bien écrits essaient de vérifier qu'un code valide existe sur le périphérique avant d'essayer de l'exécuter. Si le chargeur de démarrage et d'autres codes étaient mélangés, comment pourriez-vous être sûr que votre routine de validation fonctionnerait si tout le code ne se chargeait pas?

  4. Authentification. Les chargeurs de démarrage sécurisé essaient de vérifier que l'application chargée correspond à une signature numérique avant de s'exécuter. Mais si le chargeur de démarrage et d'autres codes ont été mélangés, vous ne pouvez pas contrôler ce qui s'exécute sur l'appareil, car une fois que l'utilisateur a chargé le nouveau code, vous ne pouvez pas contrôler ce qui se passe au démarrage.

user4574
la source
4
À titre d'exemple du point 2, certains microcontrôleurs peuvent même ne pas avoir de RAM accessible au démarrage: par exemple, le Raspberry Pi utilise son GPU pour charger le chargeur de démarrage à partir d'une carte SD, qui active ensuite le processeur ARM et la mémoire.
ErikF
11

Ils sont généralement là pour vous permettre de mettre à jour votre programme d'application principal.

Vous avez besoin d'un code qui sait comment effacer et reprogrammer une partie du flash interne, qui ne peut pas être le programme principal car lorsqu'il est effacé, il ne pourra pas reprogrammer.

Colin
la source
9

Le chargeur de démarrage permet au MCU de communiquer avec quelque chose d'autre pour accepter un nouveau programme, le stocker et l'exécuter après une réinitialisation. Si vous n'aviez pas de chargeur de démarrage, un programmeur est nécessaire pour accéder à la mémoire et mettre le programme en place.

Carrefour
la source
2
C'est à peu près ça. Le MCU peut uniquement obtenir du code via un sous-système de programmation spécial (comme AVRICE ou JTAG) ou en ayant déjà un chargeur de démarrage en flash. C'est une décision d'application quant à la complexité du chargeur de démarrage, par exemple, certains systèmes peuvent charger du code à partir du WiFi. Sur les microcontrôleurs très bas de gamme comme un ATTiny, un chargeur de démarrage (et des broches série) sont un gros frais généraux, vous utilisez donc toujours un programmeur.
Rich
7

En plus des autres bonnes réponses sur la possibilité de reprogrammer le micrologiciel principal à partir du chargeur de démarrage, un autre avantage de la séparation du chargeur de démarrage est que vous pouvez logiquement séparer les tâches "ne faire qu'une fois au démarrage" du code dont vous avez besoin pendant l'exécution. Ensuite, une fois que le chargeur de démarrage a terminé ses tâches de configuration initiales, le micrologiciel principal peut expulser le chargeur de démarrage avec tout son code qui n'est plus nécessaire de la mémoire, économisant ainsi un espace RAM important. Il est possible d'y parvenir par d'autres moyens, mais la répartition chargeur de démarrage / micrologiciel facilite beaucoup les choses sur de nombreuses architectures.

Nate S - Réintégrer Monica
la source
1
Sur un microcontrôleur, le code n'est probablement jamais en RAM, il ne peut donc pas être expulsé. Vous pouvez bien sûr supprimer les données du chargeur de démarrage de la RAM.
Ben Voigt
@BenVoigt, cela dépend du microcontrôleur. Certains (principalement ceux avec flash NOR) vous permettent d'exécuter directement hors flash, mais d'autres (généralement avec flash NAND, qui deviennent de plus en plus courants) vous obligent à exécuter en mémoire vive. Parfois, il n'y a même pas de flash intégré et vous devez copier le code d'une puce flash externe dans la SRAM locale avant de pouvoir exécuter quoi que ce soit.
Nate S - Rétablir Monica le
2

La réponse courte est que le logiciel est génial.

Vous pourriez avoir tout ce que le chargeur de démarrage est "purement matériel". Mais il est de loin, beaucoup, beaucoup plus facile d'avoir les tâches que le chargeur de démarrage soit écrites en tant que logiciel, puis interprétées par le matériel.

Ces tâches peuvent impliquer la configuration du matériel pour que le "vrai" logiciel s'exécute (par exemple, sur un Raspberry Pi (via @ErikF)), ayant un protocole pour remplacer le "vrai" programme avant son exécution (vérifiez une broche, si cette broche est définie puis reflasher le programme réel), ou même configurer l'environnement logiciel pour le programme "réel".

Sur des logiciels moins à petite échelle, lorsque vous exécutez un exécutable, le chargeur d'application déplace des choses comme le chargement de parties de vos données en mémoire, corrige parfois des adresses, configure des arguments sur des éléments principaux ou autres, fait tourner les bibliothèques fournies par votre système d'exploitation et saute ensuite au début du _maincode. Certaines de ces choses peuvent être effectuées par un chargeur de démarrage.

Dans un microcontrôleur, certaines des tâches effectuées par un chargeur de démarrage peuvent être réparties dans le programme. Le compilateur de votre plateforme pourrait injecter automatiquement le code "setup" dans chaque exécutable.

Mais, l'avoir dans le chargeur de démarrage signifie que le même compilateur peut fonctionner sur un matériel différent, car le chargeur de démarrage peut «masquer» la différence entre les plates-formes.

Ajoutez à cela le fait qu'un flash du programme principal ne risque pas le chargeur de démarrage (et la possibilité de reflasher le programme principal), et avoir un chargeur de démarrage non trivial est une très bonne chose.

Yakk
la source
-1

Une réponse qui n'a pas été abordée est la nécessité de séparer les préoccupations en raison des limites du langage C.

Généralement, les chargeurs de démarrage sont écrits dans un mélange d'Assembly et de C, avec le tout premier stade de démarrage dans Assembly.

Ceci est fait pour configurer certaines choses comme:

  • allouer la pile C
  • lecture du pointeur de pile dans le registre
  • lecture du compteur de programme dans le registre
  • déclaration des vecteurs de réinitialisation
  • chargement de la deuxième étape (initramfs) dans la RAM.

Il s'agit d'une approximation très approximative des étapes suivies et je décris le processus de démarrage ARM, il est à nouveau différent pour x86 et d'autres architectures.

Cependant, la raison principale reste la même: l'allocation de la pile C doit se faire depuis l'assemblage.

BitShift
la source
Pourquoi le downvote? C'est à la fois pertinent et précis.
BitShift
-1

Une partie de la question à laquelle on n'a pas répondu jusqu'à présent est la différence entre les chargeurs de démarrage sur les microcontrôleurs et les systèmes à microprocesseurs.

Microcontrôleur

La plupart des microcontrôleurs ont une mémoire ROM intégrée qui contient leur code de programme. La modification de ce code nécessite généralement un dispositif de programmation qui se connecte à l'interface de programmation du microcontrôleur (par exemple ISP sur ATMega). Mais ces interfaces de programmation ne sont généralement pas très pratiques à utiliser, par rapport à d'autres interfaces, car elles peuvent ne pas être facilement disponibles dans le contexte donné. Ainsi, par exemple, alors que presque tous les ordinateurs sont équipés de ports USB, l'interface SPI requise pour le FAI est beaucoup plus rare, et d'autres interfaces comme l'interface PID utilisée sur ATXMega ne sont prises en charge que par du matériel de programmation dédié.

Ainsi, par exemple, si vous souhaitez mettre à jour le logiciel à partir d'un ordinateur ordinaire sans aucun matériel externe, vous pouvez utiliser un chargeur de démarrage qui lit à partir d'un autre type d'interface (par exemple RS232, USB ou RS232 sur USB comme sur l'Arduino) pour programmer l'appareil sur des interfaces communes.

Cela dit, si vous n'avez pas besoin de cette fonctionnalité, le chargeur de démarrage est complètement facultatif. Le microcontrôleur peut toujours exécuter son code complètement sans le chargeur de démarrage.

Microprocesseur

Sur un microprocesseur, les choses sont un peu différentes. Alors que la plupart des microprocesseurs disposent d'une ROM suffisamment grande pour un chargeur de démarrage, ces ROM ne sont pas assez grandes pour contenir un système d'exploitation complet. Le but du chargeur de démarrage est donc d'initialiser le matériel, de rechercher un système d'exploitation amorçable, de le charger et de l'exécuter. Le chargeur de démarrage est donc essentiel pour chaque démarrage.

Sur les systèmes x86 / x64, ce chargeur de démarrage est soit le BIOS, soit l'UEFI (essentiellement une version plus récente d'un BIOS).

Parfois, vous pouvez même avoir plusieurs chargeurs de démarrage exécutés dans une chaîne. Par exemple, si vous avez un système à double démarrage avec Windows et Linux, vous pourriez vous retrouver avec ce qui suit:

  • Le BIOS / UEFI démarre et trouve GRUB installé. Il charge ensuite GRUB (= Grand Unified Bootloader)
  • GRUB trouve une sorte de Linux et le chargeur de démarrage Windows. L'utilisateur sélectionne le chargeur de démarrage Windows.
  • Le chargeur de démarrage Windows démarre et trouve Windows 7 et Windows 10 installés. L'utilisateur sélectionne Windows 10.
  • Windows 10 démarre enfin.

Donc, dans ce cas, il y avait trois logiciels qui peuvent être considérés comme un chargeur de démarrage. GRUB et Windows Bootloader sont principalement là pour donner à l'utilisateur une option de sélection de démarrage plus pratique que le BIOS / UEFI ne leur donnerait. Il permet également de lancer plusieurs systèmes d'exploitation à partir du même disque dur ou même de la même partition.

TLDR

Donc, alors que dans les deux systèmes, le chargeur de démarrage fait des choses un peu similaires (aidant l'utilisateur à choisir le code à démarrer), ils diffèrent tous deux considérablement dans la façon dont ils accomplissent cela et ce qu'ils font exactement.

Dakkaron
la source
Bien qu'il soit utile de distinguer les systèmes avec suffisamment de stockage non volatile à accès aléatoire (ROM ou flash) pour contenir l'ensemble du programme de ceux qui doivent exécuter du code à partir de la RAM, il existe des microcontrôleurs des deux types et des microprocesseurs des deux types.
supercat
Bien sûr, la différence entre un microcontrôleur et un microprocesseur n'est pas une frontière dure et certains microcontrôleurs se comportent plus comme un microprocesseur et vice versa. C'est pourquoi j'ai pris l'AtMega / Arduino et le x86 / x64 comme exemples, car ils se comportent de cette façon.
Dakkaron
"Les microprocesseurs disposent d'une ROM suffisamment grande pour un chargeur de démarrage ... Sur les systèmes x86 / x64, ce chargeur de démarrage est soit le BIOS, soit l'UEFI" Nope. Le BIOS ou l'UEFI sont stockés dans une mémoire flash hors puce. La ROM sur puce est destinée à des fonctions de niveau encore plus bas, comme l'initialisation du microcode.
Ben Voigt
@Dkkaron: Je ferais la distinction entre un microprocesseur et un microcontrôleur selon que la puce est conçue pour être utilisable à des fins non triviales sans rien d'autre sur le bus d'adresse. Le 8031 ​​ne serait pas qualifié, sauf qu'il s'agit du 8051 fonctionnellement (qui est certainement un microcontrôleur) qui n'est pas spécifié comme ayant quelque chose d'utile dans la ROM interne, mais serait autrement conçu pour être entièrement utilisable à partir du stockage interne). Quelque chose comme un RCA / CDP 1802 ne se qualifierait pas, même s'il peut être utilisé pour piloter une
plaque signalétique
... sans RAM et ROM externe, car les conceptions sans RAM / sans ROM sont limitées à des tâches triviales. Quelque chose comme un TMS 32050 qui, si je me souviens bien, a un chargeur de démarrage et quelques milliers de mots de 16 bits de RAM en interne serait cependant considéré comme un microcontrôleur; bien que de nombreuses applications nécessitent davantage d'ajout de RAM, si elles sont connectées via UART à un autre système, elles peuvent servir à de nombreuses fins sans rien sur son bus mémoire.
supercat