Que se passe-t-il dans un processeur intégré lorsque l'exécution atteint cette return
déclaration finale? Tout se bloque tel quel; consommation d'énergie, etc., avec un long NOP éternel dans le ciel? ou les NOP sont-ils exécutés en continu, ou un processeur sera-t-il complètement arrêté?
Je demande en partie si je me demande si un processeur doit être mis hors tension avant de terminer l'exécution et s'il le fait, comment finit-il jamais l'exécution s'il a déjà été mis hors tension?
Réponses:
C'est une question que mon père me posait toujours. " Pourquoi ne passe-t-il pas par toutes les instructions et ne s'arrête-t-il pas à la fin? "
Jetons un coup d'œil à un exemple pathologique. Le code suivant a été compilé dans le compilateur C18 de Microchip pour le PIC18:
Il produit la sortie d'assembleur suivante:
Comme vous pouvez le voir, main () est appelée et contient à la fin une déclaration de retour, bien que nous ne l'ayons pas explicitement placée là-bas. Lorsque principal revient, le CPU exécute l'instruction suivante qui est simplement un GOTO pour revenir au début du code. main () est simplement appelée maintes et maintes fois.
Cela dit, ce n'est pas ainsi que les gens font les choses habituellement. Je n'ai jamais écrit de code embarqué qui permettrait à main () de sortir comme ça. Généralement, mon code ressemblerait à ceci:
Donc je ne laisserais jamais normalement main () sortir.
"OK ok" vous dites. Tout cela est très intéressant car le compilateur s'assure qu'il n'y a jamais de dernière déclaration de retour. Mais que se passe-t-il si nous forçons le problème? Et si je codais à la main mon assembleur et ne remettais pas au début?
Eh bien, évidemment, le CPU continuerait simplement d'exécuter les prochaines instructions. Cela ressemblerait à ceci:
L'adresse mémoire suivante après la dernière instruction dans main () est vide. Sur un microcontrôleur avec mémoire FLASH, une instruction vide contient la valeur 0xFFFF. Sur un PIC au moins, ce code op est interprété comme un «nop» ou «aucune opération». Cela ne fait tout simplement rien. Le CPU continuerait à exécuter ces nops jusqu'à la fin de la mémoire.
Qu'y a-t-il après ça?
À la dernière instruction, le pointeur d'instruction du CPU est 0x7FFe. Lorsque le CPU ajoute 2 à son pointeur d'instructions, il obtient 0x8000, ce qui est considéré comme un débordement sur un PIC avec seulement 32k FLASH, et il revient donc à 0x0000, et le CPU continue joyeusement à exécuter les instructions au début du code , comme s'il avait été réinitialisé.
Vous avez également demandé s'il fallait éteindre. Fondamentalement, vous pouvez faire ce que vous voulez et cela dépend de votre application.
Si vous aviez une application qui n'avait besoin que de faire une chose après la mise sous tension, puis de ne rien faire d'autre, vous pourriez simplement mettre un certain temps (1); à la fin de main () afin que le CPU cesse de faire quoi que ce soit de notable.
Si l'application nécessite la mise hors tension du CPU, alors, selon le CPU, il y aura probablement différents modes de veille disponibles. Cependant, les processeurs ont l'habitude de se réveiller à nouveau, vous devez donc vous assurer qu'il n'y a pas de limite de temps pour le sommeil, et qu'aucune horloge de surveillance n'est active, etc.
Vous pouvez même organiser des circuits externes qui permettraient au processeur de couper complètement sa propre alimentation une fois terminé. Voir cette question: Utilisation d'un bouton-poussoir momentané comme interrupteur à bascule on-off à verrouillage .
la source
Pour le code compilé, cela dépend du compilateur. Le compilateur Rowley CrossWorks gcc ARM que j'utilise passe au code dans le fichier crt0.s qui a une boucle infinie. Le compilateur Microchip C30 pour les périphériques 16 bits dsPIC et PIC24 (également basé sur gcc) réinitialise le processeur.
Bien sûr, la plupart des logiciels embarqués ne se terminent jamais ainsi et exécutent du code en continu en boucle.
la source
Il y a deux points à souligner ici:
Le concept d'arrêt d'un programme n'existe normalement pas dans un environnement intégré. À un niveau bas, un CPU exécutera des instructions tant qu'il le pourra; il n'y a pas de "déclaration de retour final". Un CPU peut arrêter l'exécution s'il rencontre un défaut irrécupérable ou s'il est explicitement arrêté (mis en mode veille, mode basse consommation, etc.), mais notez que même les modes veille ou les défauts irrécupérables ne garantissent généralement pas que plus de code ne va être exécuté. Vous pouvez vous réveiller des modes veille (c'est ainsi qu'ils sont normalement utilisés), et même un processeur verrouillé peut toujours exécuter un gestionnaire NMI (c'est le cas pour Cortex-M). Un chien de garde fonctionnera également, et vous ne pourrez peut-être pas le désactiver sur certains microcontrôleurs une fois qu'il est activé. Les détails varient considérablement d'une architecture à l'autre.
Dans le cas d'un firmware écrit dans un langage tel que C ou C ++, ce qui se passe si main () se termine est déterminé par le code de démarrage. Par exemple, voici la partie pertinente du code de démarrage de la bibliothèque périphérique standard STM32 (pour une chaîne d'outils GNU, les commentaires sont les miens):
Ce code entrera dans une boucle infinie lors du retour de main (), bien que de manière non évidente (
bl main
chargelr
avec l'adresse de l'instruction suivante qui est en fait un saut vers lui-même). Aucune tentative n'est faite pour arrêter le processeur ou le faire passer en mode basse consommation, etc. Si vous avez un besoin légitime de tout cela dans votre application, vous devrez le faire vous-même.Notez que comme spécifié dans ARMv7-M ARM A2.3.1, le registre de liaison est défini sur 0xFFFFFFFF lors de la réinitialisation, et une branche à cette adresse déclenchera une erreur. Les concepteurs de Cortex-M ont donc décidé de traiter un retour du gestionnaire de réinitialisation comme anormal, et il est difficile de discuter avec eux.
En parlant d'un besoin légitime d'arrêter le CPU après la fin du firmware, il est difficile d'imaginer celui qui ne serait pas mieux servi par une mise hors tension de votre appareil. (Si vous désactivez votre CPU "pour de bon", la seule chose qui peut être faite à votre appareil est un cycle d'alimentation ou une réinitialisation matérielle externe.) Vous pouvez désactiver le signal ENABLE pour votre convertisseur DC / DC ou couper l'alimentation en d'une autre manière, comme le fait un PC ATX.
la source
loop: b loop
. Je me demande s'ils voulaient vraiment faire un retour mais ont oublié d'enregistrerlr
.Lorsque vous posez des questions sur
return
, vous pensez trop haut niveau. Le code C est traduit en code machine. Donc, si vous pensez plutôt au processeur qui extrait aveuglément des instructions de la mémoire et les exécute, il n'a aucune idée de laquelle est la "finale"return
. Ainsi, les processeurs n'ont pas de fin inhérente, mais à la place, c'est au programmeur de gérer le cas final. Comme Leon le souligne dans sa réponse, les compilateurs ont programmé un comportement par défaut, mais souvent le programmeur peut vouloir sa propre séquence d'arrêt (j'ai fait diverses choses comme entrer dans un mode basse consommation et s'arrêter, ou attendre qu'un câble USB soit branché dans puis redémarrer).De nombreux microprocesseurs ont des instructions d'arrêt, ce qui arrête le processeur sans affecter les périphériques. D'autres processeurs peuvent compter sur "l'arrêt" en sautant simplement à la même adresse à plusieurs reprises. Il existe plusieurs options, mais cela dépend du programmeur car le processeur continuera simplement à lire les instructions de meory, même si cette mémoire n'était pas destinée à être des instructions.
la source
Le problème n'est pas embarqué (un système embarqué peut exécuter Linux ou même Windows) mais autonome ou bare-metal: le programme d'application (compilé) est la seule chose qui s'exécute sur l'ordinateur (Peu importe s'il s'agit d'un microcontrôleur ou microprocesseur).
Pour la plupart des langues, la langue ne définit pas ce qui se passe lorsque le «principal» se termine et qu'il n'y a pas de système d'exploitation sur lequel revenir. Pour C, cela dépend de ce qui se trouve dans le fichier de démarrage (souvent crt0.s). Dans la plupart des cas, l'utilisateur peut (ou même doit) fournir le code de démarrage, donc la réponse finale est: tout ce que vous écrivez est le code de démarrage, ou ce qui se trouve dans le code de démarrage que vous spécifiez.
En pratique, il existe 3 approches:
ne prenez aucune mesure spéciale. ce qui se passe lorsque le retour principal n'est pas défini.
passer à 0 ou utiliser tout autre moyen pour redémarrer l'application.
entrez dans une boucle étroite (ou désactivez les interruptions et exécutez une instruction d'arrêt), verrouillant le processeur pour toujours.
Ce qui est approprié dépend de l'application. Une carte de voeux en fourrure et un système de contrôle des freins (pour ne citer que deux systèmes embarqués) devraient probablement redémarrer. L'inconvénient du redémarrage est que le problème peut passer inaperçu.
la source
Je regardais un peu de code ATtiny45 démonté (C ++ compilé par avr-gcc) l'autre jour et ce qu'il fait à la fin du code est de passer à 0x0000. Fondamentalement, faire une réinitialisation / redémarrage.
Si ce dernier saut à 0x0000 est omis par le compilateur / assembleur, tous les octets dans la mémoire du programme sont interprétés comme du code machine `` valide '' et il s'exécute jusqu'à ce que le compteur du programme passe à 0x0000.
Sur AVR, un octet de 00 (valeur par défaut lorsqu'une cellule est vide) est un NOP = aucune opération. Cela fonctionne donc très rapidement, ne faisant rien mais prenant juste un peu de temps.
la source
Le
main
code généralement compilé est ensuite lié au code de démarrage (il peut être intégré dans la chaîne d'outils, fourni par le vendeur de puces, écrit par vous, etc.).Linker place ensuite tous les codes d'application et de démarrage dans des segments de mémoire, donc la réponse à vos questions dépend: 1. du code du démarrage, car il peut par exemple:
bl lr
oub .
), qui sera similaire à "fin de programme", mais les interruptions et les périphériques activés précédemment fonctionneront toujours,main
).ignorez simplement «ce qui sera le prochain» après l'appel aux
main
retours.main
comportement dépendra de votre éditeur de liens (et / ou script de l'éditeur de liens utilisé lors de la liaison).Si d'autres fonctions / codes sont placés après votre,
main
ils seront exécutés avec des valeurs d'arguments invalides / non définies,Si le chien de garde est activé, il réinitialisera éventuellement le MCU malgré toutes les boucles sans fin dans lesquelles vous vous trouvez (bien sûr s'il ne sera pas rechargé).
la source
La meilleure façon d'arrêter un périphérique intégré est d'attendre indéfiniment avec les instructions NOP.
La deuxième façon consiste à fermer l'appareil en utilisant l'appareil lui-même. Si vous pouvez contrôler un relais avec vos instructions, vous pouvez simplement ouvrir le commutateur qui alimente votre appareil intégré et hein votre appareil intégré est parti sans consommation d'énergie.
la source
C'était clairement expliqué dans le manuel. En règle générale, une exception générale est levée par le processeur car il accède à un emplacement de mémoire qui se trouve en dehors du segment de pile. [exception de protection de la mémoire].
Qu'entendiez-vous par système embarqué? Microprocesseur ou microcontrôleur? Dans les deux cas, c'est défini dans le manuel.
Dans le processeur x86, nous éteignons l'ordinateur en envoyant la commande au contrôleur ACIP. Accès au mode de gestion du système. Ce contrôleur est donc une puce d'E / S et vous n'avez pas besoin de l'éteindre manuellement.
Lisez la spécification ACPI pour plus d'informations.
la source