Qu'est-ce qu'un chargeur de démarrage et comment pourrais-je en développer un?

53

J'ai rencontré de nombreux projets dans lesquels un microcontrôleur AVR utilise un chargeur de démarrage (tel que l'Arduino), mais je ne comprends pas très bien le concept.

Comment puis-je créer un chargeur de démarrage (pour n'importe quel microcontrôleur)?

Après avoir écrit mon chargeur de démarrage, comment est-il programmé sur le microcontrôleur (comme tout programme .hex gravé sur la mémoire flash de l’AVR, ou une autre méthode)?

mina_g
la source
10
Vous l'avez étiquetée avec la balise bootloader , l'avez-vous lue? Si oui, avez - vous lu l' Arduino Bootloader , Arduino Bootloader Follow On , Arduino Bootloader , De bons outils ou méthodes pour la structure de compréhension bootloader et Arduino Bootloader Détails questions? Ceux-ci répondent tous à des parties de votre question initiale. Je l'ai réduit aux nouvelles choses.
Kevin Vermeer
Un article sur la méthode de conception de BootLoader: beningo.com/wp-content/uploads/images/Papers/…
yahya tawil
2
@ KevinVermeer Je pense que sa question est plus simple.
richieqianle

Réponses:

103

Un chargeur de démarrage est un programme qui s'exécute dans le microcontrôleur à programmer. Il reçoit les nouvelles informations de programme de manière externe via certains moyens de communication et les écrit dans la mémoire de programme du processeur.

Ceci est en contraste avec la manière habituelle de faire entrer le programme dans le microcontrôleur, via un matériel spécial intégré au micro à cette fin. Sur les PIC, il s'agit d'une interface de type SPI. Si je me souviens bien, les AVR utilisent Jtag, ou du moins certains d'entre eux. Quoi qu'il en soit, cela nécessite un matériel externe qui remue les broches de programmation juste pour écrire les informations dans la mémoire du programme. Le fichier HEX décrivant le contenu de la mémoire du programme provient d'un ordinateur à usage général. Ce matériel se connecte donc à l'ordinateur d'un côté et aux broches de programmation spéciales du micro de l'autre. Ma société fabrique des programmeurs PIC entre autres comme activité secondaire. Je connais donc assez bien ce processus pour les PIC.

Le point important de la programmation externe via un matériel spécialisé est qu’il fonctionne indépendamment du contenu existant de la mémoire programme. Les microcontrôleurs démarrent avec la mémoire de programme effacée ou dans un état inconnu. La programmation externe est donc le seul moyen de transférer le premier programme dans un micro.

Si vous êtes sûr du programme que vous souhaitez charger dans votre produit et que vos volumes sont suffisamment élevés, vous pouvez demander au fabricant ou à un distributeur de programmer des puces. La puce est soudée à la carte comme n'importe quelle autre puce et l'unité est prête à fonctionner. Cela peut être approprié pour quelque chose comme un jouet, par exemple. Une fois le micrologiciel terminé, c'est à peu près terminé et il sera produit en gros volumes.

Si vos volumes sont inférieurs ou, plus important encore, si vous attendez du développement de microprogrammes et des corrections de bogues en cours, vous ne souhaitez pas acheter de puces préprogrammées. Dans ce cas, des puces vierges sont montées sur la carte et le micrologiciel doit être chargé sur la puce dans le cadre du processus de production. Dans ce cas, les lignes de programmation matérielles doivent être mises à disposition. Cela peut être via un connecteur explicite, ou des pin pads pogo si vous êtes prêt à créer un montage de test de production. De tels produits doivent souvent être testés et éventuellement calibrés. Le coût supplémentaire de l’écriture du programme sur le processeur est généralement minime. Parfois, lorsque de petits processeurs sont utilisés, un microprogramme de test de production spécial est d'abord chargé dans le processeur. Ceci est utilisé pour faciliter les tests et le calibrage de l'unité, alors le vrai firmware est chargé après que le matériel soit connu pour être bon. Dans ce cas, certaines considérations relatives à la conception du circuit permettent un accès suffisant aux lignes de programmation pour que le processus de programmation fonctionne, mais également pour ne pas trop gêner le circuit. Pour plus de détails à ce sujet, voir monrédaction de la programmation en circuit .

Jusqu'ici tout va bien, et aucun chargeur de démarrage n'est nécessaire. Toutefois, envisagez un produit avec un micrologiciel relativement complexe que vous souhaitez mettre à niveau sur site ou même autorisez le client final à effectuer la mise à niveau. Vous ne pouvez pas vous attendre à ce que le client final ait un gadget de programmation ou sache l’utiliser correctement, même si vous en avez fourni un. En fait, un de mes clients le fait. Si vous achetez leur option spéciale de personnalisation sur le terrain, vous obtenez l'un de mes programmeurs avec le produit.

Cependant, dans la plupart des cas, vous voulez simplement que le client exécute un programme sur un PC et que le firmware soit mis à jour comme par magie. C’est là qu’un chargeur de démarrage entre en jeu, en particulier si votre produit dispose déjà d’un port de communication permettant une interface simple avec un PC, tel que USB, RS-232 ou Ethernet. Le client exécute un programme PC qui communique avec le chargeur de démarrage déjà présent dans le micro. Cela envoie le nouveau fichier binaire au chargeur de démarrage, qui l'écrit dans la mémoire programme et entraîne l'exécution du nouveau code.

Cela semble simple, mais ce n'est pas le cas, du moins si vous voulez que ce processus soit robuste. Que se passe-t-il si une erreur de communication se produit et que le nouveau micrologiciel est corrompu au moment où il arrive au chargeur de démarrage? Que se passe-t-il si le courant est interrompu pendant le processus de démarrage? Et si le chargeur de démarrage a un bug et craps sur lui-même?

Un scénario simpliste est que le chargeur de démarrage est toujours exécuté à partir de la réinitialisation. Il essaie de communiquer avec l'hôte. Si l'hôte répond, il indique alors au chargeur de démarrage qu'il n'a rien de nouveau ou lui envoie un nouveau code. Lorsque le nouveau code arrive, l'ancien code est écrasé. Vous incluez toujours une somme de contrôle avec le code téléchargé afin que le chargeur de démarrage puisse dire si la nouvelle application est intacte. Sinon, il reste dans le chargeur de démarrage en demandant constamment un téléchargement jusqu'à ce que quelque chose avec une somme de contrôle valide soit chargé en mémoire. Cela peut être acceptable pour un périphérique toujours connecté et éventuellement lorsqu'une tâche en arrière-plan est exécutée sur l'hôte et qui répond aux demandes du chargeur de démarrage. Ce système ne convient pas aux unités largement autonomes qui ne se connectent qu'occasionnellement à un ordinateur hôte.

Habituellement, le chargeur de démarrage simple décrit ci-dessus n'est pas acceptable, car il n'y a pas de sécurité intégrée. Si une nouvelle image d'application n'est pas reçue intacte, vous voulez que l'appareil continue d'exécuter l'ancienne image et ne soit pas mort tant qu'un téléchargement réussi n'a pas été effectué. Pour cette raison, il existe généralement deux modules spéciaux dans le micrologiciel, un téléchargeur et un chargeur de démarrage. Le téléchargeur fait partie de l'application principale. Dans le cadre des communications régulières avec l'hôte, une nouvelle image d'application peut être téléchargée. Cela nécessite une mémoire séparée de l'image principale de l'application, comme une EEPROM externe ou un processeur plus important, de sorte que la moitié de la mémoire programme puisse être allouée au stockage de la nouvelle image d'application. Le téléchargeur écrit simplement la nouvelle image d'application reçue quelque part, mais ne l'exécute pas. Lorsque le processeur est réinitialisé, ce qui peut arriver sur commande de l'hôte après un téléchargement, le chargeur de démarrage s'exécute. Il s’agit maintenant d’un programme totalement autonome qui n’a pas besoin de capacités de communication externes. Il compare les versions actuelle et téléchargée des applications, vérifie leurs sommes de contrôle et copie la nouvelle image dans la zone d'application si les versions diffèrent et les nouvelles vérifications de contrôle de l'image. Si la nouvelle image est corrompue, il exécute simplement l'ancienne application comme auparavant.

J'ai fait beaucoup de chargeurs de démarrage, et il n'y en a pas deux pareils. Il n'y a pas de chargeur de démarrage à usage général, malgré ce que certaines sociétés de microcontrôleurs veulent que vous croyiez. Chaque appareil a ses propres exigences et circonstances spéciales pour traiter avec l'hôte. Voici quelques-unes des configurations de chargeur de démarrage et parfois de téléchargement que j'ai utilisées:

  1. Chargeur de base. Cet appareil avait une ligne série et serait connecté à un hôte et allumé si nécessaire. Le chargeur de démarrage a été réinitialisé et a envoyé quelques réponses de demande de téléchargement à l'hôte. Si le programme de téléchargement était en cours d'exécution, il répondrait et enverrait une nouvelle image d'application. S'il ne répond pas dans les 500 ms, le chargeur de démarrage abandonnera et exécutera l'application existante. Par conséquent, pour mettre à jour le micrologiciel, vous deviez d'abord exécuter l'application de mise à jour sur l'hôte, puis connecter et allumer l'appareil.

  2. Programme de téléchargement de mémoire. Ici, nous avons utilisé le PIC de taille supérieure, qui avait deux fois plus de mémoire programme. La mémoire du programme était grossièrement divisée en 49% d'application principale, 49% de nouvelle image d'application et 2% de programme d'amorçage. Le chargeur de démarrage s'exécutera à partir de la réinitialisation et copiera la nouvelle image d'application sur l'image d'application actuelle dans les bonnes conditions.

  3. Image EEPROM externe. Comme # 2, sauf qu'une EEPROM externe était utilisée pour stocker la nouvelle image d'application. Dans ce cas, le processeur avec plus de mémoire aurait également été physiquement plus gros et dans une sous-famille différente ne disposant pas du mélange de périphériques dont nous avions besoin.

  4. Chargeur de démarrage TCP. C'était le plus complexe de tous. Un grand PIC 18F a été utilisé. Le dernier quart de la mémoire contenait le chargeur de démarrage, qui disposait de sa propre copie complète d'une pile réseau TCP. Le chargeur de démarrage a démarré à partir de la réinitialisation et a essayé de se connecter à un serveur de téléchargement spécial sur un port connu à une adresse IP précédemment configurée. C'était pour les grandes installations où il y avait toujours un serveur dédié pour l'ensemble du système. Chaque petit appareil s'enregistrerait auprès du serveur de téléchargement après la réinitialisation et se verrait attribuer une nouvelle copie de l'application, le cas échéant. Le chargeur de démarrage écraserait l'application existante avec la nouvelle copie, mais ne l'exécuterait que si la somme de contrôle était cochée. Sinon, il reviendrait sur le serveur de téléchargement et réessayer.

    Comme le chargeur de démarrage était lui-même un morceau de code complexe contenant une pile réseau TCP complète, il devait également être mis à niveau sur site. Nous avions pour objectif que le serveur de téléchargement alimente une application spéciale dont le seul but était d’écraser le chargeur de démarrage une fois celui-ci exécuté, puis de réinitialiser la machine afin que le nouveau chargeur de démarrage s’exécute, ce qui obligerait le serveur de téléchargement à envoyer le message. dernière image principale de l'application. Techniquement, un problème de puissance pendant les quelques millisecondes nécessaires à l'application spéciale pour copier une nouvelle image sur le chargeur de démarrage constituerait un échec irrémédiable. En pratique, cela n'est jamais arrivé. Cela nous convenait très peu, car ces périphériques faisaient partie de grandes installations où il y avait déjà des personnes chargées de la maintenance du système, ce qui impliquait parfois de remplacer les périphériques intégrés pour d'autres raisons.

Si tout va bien, vous constaterez qu'il existe un certain nombre d'autres possibilités, chacune avec ses propres compromis de risque, de rapidité, de coût, de facilité d'utilisation, de temps d'arrêt, etc.

Olin Lathrop
la source
1
Tous les AVR, à l'exception de la famille Xmega (qui possède une nouvelle interface à 2 fils), utilisent une interface SPI tout en étant réinitialisés. Les plus grands ont aussi JTAG, certains ont une programmation parallèle et les plus petits peuvent nécessiter une haute tension si la réinitialisation a été reconfigurée en tant qu'E / S. Certains MCU, tels que les familles Parallax Propeller et Motorola / Freescale 68HC08, ne disposent que d’un matériel de programmation minimal, à part des chargeurs de démarrage en ROM.
Yann Vernier
Il compare les versions actuelle et téléchargée des applications, vérifie leurs sommes de contrôle et copie la nouvelle image dans la zone d'application si les versions diffèrent et les nouvelles vérifications de contrôle de l'image. Oui, mais que se passe-t-il si le courant est interrompu au milieu de cette action, il y aurait une image corrompue dans la "zone d'application". Je suppose qu'il serait peut-être préférable d'avoir une application bootloader-fail-safe qui écrit la nouvelle application dans le flash mcu et si la somme de contrôle est valide, elle écrit également quelque part "ok pour démarrer la nouvelle application". Donc, au début, il vérifie s'il est correct de démarrer la nouvelle application, sinon, il continue à s'exécuter lui-même (application sécurisée)
Ervadac
@ Erv: Si une panne de courant survient pendant la copie de la nouvelle version sur la version actuelle, le total de contrôle de la version actuelle échouera à la mise sous tension et le chargeur de démarrage sera à nouveau exécuté. Je mets généralement le mot de somme de contrôle à la toute fin de l'image pour qu'une écriture partielle ait de très bonnes chances d'échouer.
Olin Lathrop
Salut. Je peux vous recommander le chargeur de démarrage de type 5 - au lieu de la pile TCP, vous pouvez implémenter UDP. Ensuite, utilisez TFTP pour télécharger la mise à jour ou le protocole natif.
i486
22

Quel est le concept du chargeur de démarrage?

Imaginez ce scénario: votre microcontrôleur dispose d'une quantité de stockage suffisante, suffisante pour stocker plus de 2 ou 3 programmes ou applications indépendants les uns des autres. Supposons que lorsque vous démarrez votre appareil, vous souhaitiez pouvoir choisir lequel exécuter. Alors, de quoi auriez-vous besoin pour supporter cela? Vous auriez besoin d'un programme de démarrage qui vous permet ensuite de choisir entre les autres au démarrage.

Comment ça fonctionne?

Un programme d'amorçage est ce programme - c'est la première chose à exécuter. Il peut charger d'autres applications dans des emplacements spécifiques de la mémoire (soit persistant comme FLASH, soit volatile comme de la RAM), puis passe au programme souhaité où il prendra ensuite en charge l'exécution. .

Comment faire un chargeur de démarrage avr (ou pour n'importe quel microcontrôleur)?

Je n'ai jamais fabriqué de chargeur de démarrage, mais voici comment je pense que je m'y prendrais bien: commencez à écrire un programme de firmware comme vous le feriez normalement - mais assurez-vous qu'il est placé dans une zone telle que c'est toujours la première chose à faire fonctionner l'appareil démarre. D’emblée, certaines des fonctionnalités que je souhaiterais utiliser dans ce petit programme: possibilité de télécharger un nouveau programme vers un emplacement disponible en mémoire, d’effacer un programme précédemment chargé, de choisir le programme à exécuter (s’il existe plus de un), et avoir une sorte de structure de données de stockage (table de saut évolutive?) pour pouvoir se rappeler où sont les autres programmes et y accéder directement. L'interaction pourrait se faire sur UART, où il peut vous présenter un menu de terminal très simple et la possibilité de télécharger un micrologiciel sur ce même canal.

Comment est-il programmé sur le microcontrôleur (comme tout programme .hex gravé sur la mémoire flash du avr, ou une autre méthode)?

S'il s'agit d'une puce totalement vierge sans aucun chargeur de démarrage existant pouvant se mettre à jour, vous devrez alors graver en FLASH de la même manière que vous avez décrit à l'aide de la technique requise (ICSP dans le cas d'AVR).

Ceci n’est nullement exhaustif sur ce que sont les "chargeurs de démarrage". En fonction de ce que vous voulez sur l'un des systèmes ou sur le système pour lequel ils ont été conçus, vous pouvez en concevoir un pour télécharger des éléments à un emplacement spécifié dans la RAM au lieu de FLASH et commencer l'exécution à n'importe quel emplacement de mémoire arbitraire. Ou vous en voulez peut-être un qui soit capable de choisir le système d’exploitation à charger lors du démarrage de votre PC (voir grub par exemple). Les chargeurs de démarrage pour les microcontrôleurs 8 bits ont tendance à être très simples.

Remarque à propos d'Arduino: ce chargeur de démarrage ne gère qu'un seul programme, autant que je sache, mais il prend également en charge le port série pour gérer le téléchargement du micrologiciel et d'autres éléments .

Jon L
la source
FYI, la réponse a été écrite pour traiter les points de balle originaux qui ont maintenant été supprimés.
Jon L
3

Le concept de chargeur "d'amorçage" est similaire au concept "d'amorçage" d'une pompe. En d'autres termes, vous avez besoin de "quelque chose" qui charge un programme à une adresse donnée, puis commence à exécuter le programme à cette adresse donnée. Ce quelque chose, c'est le chargeur de démarrage. Dans le cas le plus simple, le chargeur de démarrage "apparaît" à l'adresse de départ spécifiée par la CPU (zéro, très probablement), charge le programme dans le segment de mémoire requis, y transfère le contrôle et "disparaît". L'apparition et la disparition sont contrôlées par du matériel "externe". Une implémentation possible consisterait à utiliser une ROM activée par une réinitialisation "matérielle" et désactivée par une réinitialisation "logicielle". Le chargeur dans la ROM peut être aussi simple ou aussi complexe que nécessaire, et doit être écrit sous la forme binaire que le processeur particulier comprend. Si l'espace d'adressage utilisé par la ROM n'est pas nécessaire, la désactivation de la ROM n'est pas requise. Bien évidemment, EEPROM, ePROM, flash PROM, etc. pourraient être utilisés à la place de la ROM.

Guill
la source