Arduino Bootloader
quelqu'un Peut-il expliquer comment l' Arduino bootloader fonctionne? Je ne cherche pas une réponse de haut niveau ici, j'ai lu le code et j'ai compris l'essentiel.
il y a un tas d'interaction de protocole qui se produit entre L'IDE Arduino et le code du bootloader, aboutissant finalement à un certain nombre d'instructions d'assemblage en ligne qui AUTO-programment le flash avec le programme transmis sur l'interface série.
ce sur quoi je ne suis pas clair est sur ligne 270:
void (*app_start)(void) = 0x0000;
...que je reconnais comme la déclaration, et l'initialisation à NULL, d'un pointeur de fonction. Il y a des appels ultérieurs à app_start dans les endroits où le chargeur d'amorçage est destiné à déléguer à l'exécution du code chargé par l'utilisateur.
sûrement, d'une façon ou d'une autre app_start
besoin d'obtenir une valeur non NULLE à un certain moment pour que cela viennent tous ensemble. Je ne vois pas ça dans le code du bootloader... est-il magiquement lié par le programme qui est chargé par le bootloader? Je suppose que main du bootloader est le point d'entrée dans le logiciel après une réinitialisation de la puce.
enveloppé dans les quelque 70 lignes d'assemblage doit être l'anneau de décodage secret qui dit au programme principal où app_start est vraiment? Ou peut-être est-ce un savoir implicite dont profite L'IDE Arduino? Tout ce que je sais c'est que si quelqu'un ne change pas app_start pour pointer ailleurs que 0, le code bootloader Tournera sur lui-même pour toujours... alors, quelle est le truc?
Modifier
je suis intéressé à essayer de porter le chargeur d'amorçage à un petit AVR qui n'a pas d'espace mémoire séparé pour le code du chargeur d'amorçage. Comme il devient évident pour moi que le code bootloader repose sur certains paramètres de fusibles et le soutien de puce, je suppose que ce qui m'intéresse vraiment de savoir est ce qu'il faut pour porter le chargeur d'amorçage à une puce qui n'a pas ces fusibles et le soutien de matériel (mais a toujours l'auto-programmation la capacité)?
2 réponses
on NULL
L'adresse 0 n'est pas une marque à pointeur nul. Un pointeur null" est quelque chose de plus abstrait: une valeur spéciale applicable fonctions devraient reconnaître comme étant non valide. C dit que la valeur spéciale est 0, et alors que le langue dit déréférencement c'est" comportement non défini", dans le monde simple des microcontrôleurs il a généralement un effet très bien défini.
ATmega Bootloaders
normalement, lors de la réinitialisation, le programme de L'AVR counter (PC) est initialisé à 0, donc le microcontrôleur commence à exécuter le code à l'adresse 0.
cependant, si le fusible de réinitialisation de Boot ("BOOTRST") est activé, le compteur de programme est initialisé à l'adresse d'un bloc à l'extrémité supérieure de la mémoire (où cela dépend de la façon dont les fusibles sont configurés, voir une fiche technique (PDF, 7 MO) pour plus de détails). Le code qui commence là peut faire n'importe quoi-si vous voulez vraiment vous pouvez mettre votre propre programme là si vous utilisez un ICSP (les bootloaders ne peuvent généralement pas se réécrire eux-mêmes).
mais souvent, c'est un programme spécial-a bootloader-qui est capable d' lire les données à partir d'une source externe(souvent via UART, I 2 C, CAN, etc.)réécriture de code de programme (stocké dans la mémoire interne ou externe, selon le micro). Le bootloader recherche généralement un "événement spécial" qui peut littéralement être n'importe quoi, mais pour le développement est le plus commode quelque chose dans le bus de données va extraire le nouveau code. (Pour la production, il pourrait être un niveau logique sur une broche, car il peut être vérifié presque instantanément. Si le bootloader voit l'événement spécial, il peut entrer en mode bootloading, où il reflashera la mémoire du programme, sinon il passe le contrôle au code utilisateur.
a part cela, le but du bootloader fuse et du bloc mémoire supérieur est de permettre l'utilisation d'un bootloader avec aucun modifications à l'original logiciel (tant qu'il ne s'étend pas jusqu'à l'adresse du bootloader). Au lieu de clignoter avec seulement L'hexagone original et les fusibles désirés, on peut clignoter l'hexagone original, bootloader, et les fusibles modifiés, et presto, bootloader ajouté.
de toute façon, dans le cas de l'Arduino, qui, je crois, utilise le protocole de l' STK500, il tente de communiquer sur le UART, et s'il obtient soit pas de réponse dans le heure:
uint32_t count = 0;
while(!(UCSRA & _BV(RXC))) { // loops until a byte received
count++;
if (count > MAX_TIME_COUNT) // 4 seconds or whatever
app_start();
}
ou si des erreurs trop en obtenant une réponse inattendue:
if (++error_count == MAX_ERROR_COUNT)
app_start();
il renvoie le contrôle au programme principal, situé à 0. Dans la source Arduino ci-dessus, ceci est fait en appelant app_start();
, défini comme void (*app_start)(void) = 0x0000;
.
parce qu'il est présenté comme un appel de fonction C, avant que le PC ne passe à 0, Il va pousser la valeur PC courante sur la pile qui contient aussi d'autres variables utilisées dans le bootloader (par exemple count
et error_count
à partir de ci-dessus). Est-ce que cela vole RAM de votre programme? Eh bien, après que le PC est réglé à 0, les opérations qui sont exécutées "violent" de façon flagrante ce qu'une fonction C appropriée (qui finirait par revenir) devrait faire. Entre autres étapes d'initialisation, il réinitialise le pointeur de pile (effaçant ainsi la pile d'appels et toutes les variables locales), récupérant la RAM. Les variables globales / statiques sont initialisées à 0, dont l'adresse peut librement se chevaucher avec ce que le bootloader utilisait parce que le les programmes bootloader et user ont été compilés indépendamment.
les seuls effets durables du bootloader sont les modifications aux registres matériels (périphériques), qu'un bon bootloader ne laissera pas dans un État préjudiciable (allumer les périphériques qui pourraient gaspiller de l'énergie lorsque vous essayez de dormir). C'est généralement une bonne pratique d'initialiser complètement les périphériques que vous utiliserez, donc même si le bootloader a fait quelque chose d'étrange, vous le définirez comme vous le voulez.
ATtiny Bootloaders
sur les ATtinys, comme vous l'avez mentionné, il n'y a pas de luxe de fusibles de bootloader ou de mémoire, donc votre code commencera toujours à l'adresse 0. Vous pourriez être en mesure de mettre votre bootloader dans des pages supérieures de mémoire et de pointer votre vecteur de réinitialisation vers elle, puis chaque fois que vous recevez un nouveau fichier hexadécimal à flash, prenez la commande qui est à l'adresse 0:1, remplacez-la par l'adresse du bootloader, puis stockez l'adresse remplacée ailleurs pour demander une exécution normale. (Si c'est un RJMP
(" relative jump") la valeur de toute évidence besoin d'être recalculé).
Modifier
je suis intéressé à essayer de porter le chargeur d'amorçage à un petit AVR qui n'a pas d'espace mémoire séparé pour le code du chargeur d'amorçage. Comme il devient évident pour moi que le code du chargeur d'amorçage dépend de certains paramètres de fusibles et de la prise en charge de la puce, je suppose que ce qui m'intéresse vraiment c'est de savoir ce qu'il faut pour porter le chargeur d'amorçage sur une puce qui n'a pas ces fusibles et la prise en charge du matériel (mais qui a quand même la capacité d'auto-programmation)?
en Fonction de votre but ultime il peut être plus facile de créer votre propre bootloader plutôt que d'essayer d'en porter un. Vous avez vraiment besoin d'apprendre quelques éléments pour cette partie.
1) uart tx
2) uart rx
3) programmation auto-flash
qui peut être appris séparément puis combiné dans un bootloader. Vous aurez besoin d'une partie que vous pouvez utiliser spi ou n'importe quoi pour écrire le flash, de sorte que si votre bootloader ne fonctionne pas ou n'importe quoi que la partie est venue avec se touche vous pouvez toujours continuer le développement.
que vous portiez ou rouliez le vôtre, vous aurez toujours besoin de comprendre ces trois choses de base en ce qui concerne cette partie.