LOCODUINO

Forum de discussion
Dépôt GIT Locoduino
Flux RSS

jeudi 2 décembre 2021

39 visiteurs en ce moment

L’assembleur (9)

Conseils et bonnes pratiques

. Par : Christian

DIFFICULTÉ :

Cette série d’articles vous a fait découvrir les avantages, mais aussi les inconvénients, de l’assembleur. Elle vous a proposé quelques techniques pour programmer vos microcontrôleurs dans ce langage et proposé quelques applications très simples utilisables en modélisme ferroviaire. C’est déjà beaucoup et pourtant cette série n’a été conçue que pour vous faire découvrir le sujet : il y aurait encore beaucoup à dire. Comme vous êtes des experts en Arduino et autres cartes dérivées, c’est à vous maintenant d’augmenter vos connaissances et votre pratique de l’assembleur en continuant votre apprentissage dans des cours, des tutos, des documentations, des vidéos et tout ce que propose internet. Dans ce dernier article, nous allons vous donner quelques conseils pour bien développer en assembleur.

Cette série d’articles avait vocation à s’appliquer à tous les microcontrôleurs de la gamme AVR. Cependant, nous avons insisté un peu plus sur l’ATmega328P qui équipe les cartes Uno et les différentes figures illustrant cette série sont la plupart du temps tirées de la datasheet de ce composant. Si vous voulez programmer d’autres AVR que l’ATmega328P, le principe reste le même : un recours attentif à la datasheet du composant.

Les programmes que nous avons développés dans les précédents articles ont été écrits soit avec Microchip Studio 7, soit avec l’IDE d’Arduino. Ces deux environnements de développement n’utilisent pas la même syntaxe et un copier-coller d’un programme de l’un vers l’autre ne fonctionnera sans doute pas, notamment s’il comporte des directives d’assemblage. Il est donc indispensable de bien connaître les outils que l’on utilise (microcontrôleurs et environnement de développement), et pour cela d’avoir une bonne documentation.

Se documenter

Avant toute séance de conception d’un programme, nous vous conseillons d’ouvrir dans votre espace de travail les quelques PDF dont nous parlons ci-dessous et qui constitueront une documentation précieuse à laquelle vous vous référerez. Tout d’abord, la datasheet du MCU utilisé qui permet de trouver la liste des instructions possibles ainsi que les adresses des registres du microcontrôleur et ses différentes ressources. Cette datasheet doit devenir votre première référence dans votre travail de conception. Elle peut être complétée par un plan du brochage du microcontrôleur comme celui donné par la figure 1, plan qui peut être trouvé sur internet ou sur le site github.

Figure 1
Figure 1
Brochage du microcontrôleur ATmega328 qui équipe les cartes Uno.

Néanmoins, la datasheet ne décrit pas en détails les différentes instructions et les contraintes qui s’appliquent à celles-ci. La seconde documentation à ouvrir est éditée par Microchip (en fait Atmel et date de 2021) et est intitulée AVR Instruction Set Manual. On y trouve comment écrire l’instruction, quelles sont les contraintes sur les registres ou les valeurs immédiates, comment l’instruction est codée, comment elle agit sur les flags du registre d’état SREG, combien de mots elle utilise en mémoire Flash et combien de cycles horloge sont nécessaires à son exécution.

En fonction de l’environnement de développement intégré que vous utiliserez (IDE d’Arduino ou Studio 7), vous devrez également avoir sous la main la documentation de l’assembleur, soit gnu-as pour l’IDE soit AVRASM2 pour Studio 7. Vous avez vu en effet que les directives d’assemblage ne sont pas les mêmes mais il y a aussi bien d’autres chapitres fort utiles à découvrir dans ces documentations.

Studio 7 étant un environnement de développement extrêmement puissant, il est nécessaire d’apprendre à le maîtriser et pour cela, nous vous conseillons aussi de télécharger le guide de l’utilisateur disponible sur le site de Microchip où on peut également trouver de nombreuses vidéos de prise en main de l’outil.

Une dernière documentation que nous vous conseillons au moins de lire une fois est une note d’application, disponible sur le site de Microchip, expliquant comment mélanger du code en C avec du code en assembleur et donnant un exemple pratique pour comprendre.

Voici les différentes adresses où trouver ces documentations :

Datasheet du MCU utilisé à télécharger sur https://www.microchip.com/doclisting/TechDoc.aspx?type=datasheet

AVR Instruction Set Manual : https://ww1.microchip.com/downloads/en/DeviceDoc/AVR-InstructionSet-Manual-DS40002198.pdf

AVR Assembler – Microchip – 2017 (décrit l’assembler AVRASM2 utilisé par Studio 7) :
https://ww1.microchip.com/downloads/en/devicedoc/40001917a.pdf

Using as – The GNU Assembler – Free Software Foundation Inc – 2018 (décrit l’assembler GNU-AS) :
https://doc.ecoscentric.com/gnutools/doc/as.pdf

Atmel Studio User Guide – Atmel – 2016 (guide de l’utilisateur de Studio 7) :
https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42167-Atmel-Studio_User%20Guide.pdf

Application note – Atmel AT1886 : Mixing assembly and C with AVRGCC – Atmel – 2012 :
https://ww1.microchip.com/downloads/en/Appnotes/doc42055.pdf

Écrire du code

Écrire du code n’a rien de compliqué ; il suffit de suivre la syntaxe de l’instruction. Studio 7 ou bien l’IDE vous permet d’écrire en minuscule ou en majuscule, ce que vous préférez. Par contre, il est important que le code soit présenté en quatre colonnes, une pour les étiquettes, une pour les mnémoniques, une pour les opérandes et une pour le commentaire de ligne. Studio 7 ainsi que l’IDE permettent de mettre l’étiquette sur une ligne à part ; si vous le faites, il reste quand même trois colonnes pour chaque ligne d’instruction. L’alignement des colonnes peut être fait avec des caractères de tabulation mais ceux-ci sont parfois mal interprétés d’un environnement de développement à un autre, et il est préférable d’utiliser des caractères « espace ».

Les programmes d’assemblage permettent souvent de mettre plusieurs instructions par ligne mais cette méthode n’est pas recommandée. Pour la lisibilité et la compréhension du programme, ne mettez qu’une seule instruction par ligne et derrière le commentaire de ligne.

L’assembleur étant moins facile à comprendre qu’un langage évolué comme le C/C++, il est important de commenter énormément, quasiment chaque ligne de programme. Bien évidemment, ces commentaires doivent être judicieux et ne pas seulement reprendre l’instruction. Par exemple :

DEC R18     ; on décrémente le registre R18

Ce commentaire ne sert à rien : l’instruction dit la même chose ! Par contre :

DEC R18     ; un motif de moins restant à faire

Ce commentaire permet de comprendre que R18 contient le nombre de motifs qu’il reste à traiter. Vous verrez que c’est tout un art de trouver le bon commentaire, celui qui ne décrit que ce qui est utile pour comprendre comment fonctionne le programme.

Le choix des étiquettes est également important ; leur nom doit permettre de se repérer dans ce que fait le programme. Pour les sous-programmes, l’étiquette doit permettre de comprendre à quoi sert ce dernier. Par exemple, l’étiquette LCD_INIT permet tout de suite de comprendre que le sous-programme initialise un écran LCD. Deux étiquettes ne doivent pas porter le même nom : de toute façon, cela déboucherait sur une erreur qui stopperait la compilation du programme.

Si vous faites évoluer votre projet, et que vous modifiez votre programme, assurez vous que les commentaires et les étiquettes collent toujours au nouvel usage.

Enfin, les datasheets des microcontrôleurs AVR comportent de nombreux exemples de programmes écrits d’une part en C, d’autre part en assembleur. Vous pouvez vous inspirer de ces derniers pour écrire vos propres programmes.

Contrôle du microcontrôleur

Il existe au sein d’un microcontrôleur des registres spéciaux qui définissent le mode de fonctionnement du MCU et d’autres qui permettent de connaître son état. Nous allons en dire quelques mots mais seule une étude approfondie de la datasheet vous familiarisera avec ces registres.

Le cœur d’un microcontrôleur, c’est l’ALU (Arithmetic Logic Unit) qui effectue des opérations divisées en trois catégories : arithmétique, logique et bit-fonctions. Toutes les opérations de l’ALU mettent à jour un registre de 8 bits appelé registre d’état (Status Register ou encore SREG) dont nous avons déjà parlé dans l’article N°2. La figure 2 montre la structure de SREG dont les bits nous renseignent sur le résultat de l’opération qui vient d’être effectuée ; il suffit alors de surveiller ces bits pour agir en conséquence. Par exemple, les bits 0 à 3 (encore appelés Flag) nous indiquent si une opération a donné lieu à une retenue ( C  : Carry Flag est alors mis à 1), ou bien donne un résultat nul ( Z  : Zero Flag est mis à 1) ou bien négatif ( N  : Negative Flag est mis à 1) ou bien s’il y a dépassement de capacité (Overflow) en arithmétique de complément à 2 ( V  : Two’s Complement Overflow Flag). Le bit 4 ( S  : Sign Bit) est toujours un ou exclusif entre les bits N et V , le bit 5 ( H  : Half Carry) indique une demi-retenue dans certaines opérations arithmétiques [1] et est très utile en arithmétique BCD (Binary-Coded Decimal), enfin le bit 6 ( T  : Bit Copy Storage) est un bit source ou destination pour des instructions de copie de bits comme BLD ou BST (Bit Load ou Bit Store). Le bit 7 ( I  : Global Interrupt Bit) joue un rôle particulier car c’est lui qui autorise ( I = 1) ou non ( I = 0) les interruptions en général. Notons que chacun de ces bits peuvent être lus ou écrits et qu’ils sont initialisés à 0. Comme on le voit, SREG donne beaucoup de renseignements sur ce que réalise l’ALU. SREG n’est pas automatiquement sauvegardé lorsqu’on exécute une routine d’interruption ni restauré à la fin ; il faut donc le faire éventuellement dans le programme.

Figure 2
Figure 2
Le registre d’état SREG (Source Microchip).

Un autre registre d’état est le registre MCUSR (MCU Status Register) qui permet d’identifier la source d’un RESET qui peut avoir quatre causes : Power-on (reset quand l’alimentation du MCU tombe sous un certain seuil), External reset (quand un niveau bas est présent sur la broche de RESET), Watchdog reset (quand le timer WDT atteint sa période programmée) et enfin Brown-out reset (quand l’alimentation du MCU tombe au-dessous du seuil de Brown-out et que le détecteur Brown-out est autorisé, un RESET interne à lieu (voir par exemple le paragraphe 10.5 de la datasheet du ATmega328P)). La figure 3 montre la structure du MCUSR.

Figure 3
Figure 3
Le registre MCUSR (MCU Status Register) (Source Microchip).

Parallèlement aux registres d’état, on trouve des registres de contrôle, comme le MCUCR (MCU Control Register) montré par la figure 4. Les deux premiers bits sont importants, le bit 0 ou IVCE (Interrupt Vector Change Enable) et le bit 1 ou IVSEL (Interrupt Vector Select). Si IVSEL vaut 0, alors les vecteurs d’interruptions sont placés au début de la mémoire Flash, si IVSEL vaut 1, ils sont placés au début de la section Boot Loader de la mémoire Flash. Bien évidemment, les microcontrôleurs sans boot loader (ATtiny par exemple) n’ont pas cette possibilité et leur registre MCUCR a une autre structure qu’il faut connaître si on veut les programmer. Pour éviter des changements non intentionnels de la table des vecteurs d’interruption, il y a une procédure spéciale pour écrire IVSEL qui se fait avec l’aide du bit IVCE qui doit être positionné à 1 pour autoriser un changement d’ IVSEL . Référez-vous à la datasheet du composant où il y a même un exemple en assembleur pour cette procédure. Les autres bits de MCUCR concernent le mode Pull-up des ports d’entrée-sortie ( PUD ) et le mode Sleep du MCU ( BODS et BODSE ).

Figure 4
Figure 4
Le registre de contrôle du MCU ATmega328P (Source Microchip).

Chaque ressource du microcontrôleur dispose de ses propres registres de contrôle et il serait trop long de les décrire tous ici. Nous renvoyons donc le lecteur à la datasheet du composant utilisé.

Programme minimum en assembleur

Comme on vient de l’expliquer, la table des vecteurs d’interruption (et du vecteur RESET) est soit au début de la mémoire Flash, soit au début de la section Boot Loader dans la mémoire Flash : ceci dépend de la valeur du bit IVSEL , mais également du bit Boot Reset Fuse encore appelé BOOTRST . La figure 5 montre les quatre possibilités pour placer le vecteur RESET et les vecteurs d’interruption en fonction des valeurs de BOOTRST et IVSEL .

Figure 5
Figure 5
Placement des vecteurs de RESET et d’interruption (Source Microchip).

Sur un AVR sans Boot Loader, le vecteur RESET doit être positionné à l’adresse 0x0000 de la mémoire Flash et les vecteurs d’interruption juste après, comme le montre la figure 6 pour l’ATtiny25/45/85.

Figure 6
Figure 6
Placement des vecteurs RESET et interruption sur ATtiny25/45/85 (Source Microchip).

Quel que soit le modèle de MCU AVR, cette table doit figurer quelque part (et on n’a pas toujours le choix de la position) sinon le programme plantera dès la mise en route. Nous allons donc décrire ici en quoi consiste un programme minimum en assembleur.

Tout d’abord, quelques lignes de commentaires permettent de définir ce que fait le programme et dans quelles conditions : cible microcontrôleur, fréquence horloge, numéro de version et date, auteur, etc. N’ayez pas peur d’en mettre trop, vous serez bien content de retrouver vos marques si vous reprenez votre programme après plusieurs semaines d’interruption.

  1. ;*****************************************************************************
  2. ; COMPOSANT : ATMEL AVR 8 Bits (RISC) - ATMega328P Quartz = 16 MHz
  3. ; PROGRAMME : Chenillard_asm_Uno.asm
  4. ; VERSION : V 1.00
  5. ; DATE : 07/12/2020
  6. ; DERNIERE MAJ. : 06/02/2021
  7. ; DESCRIPTION : Chenillard sur sorties 2 à 7 carte Uno
  8. ; AUTEUR : Christian

Vous pouvez ensuite mettre quelques directives d’assemblage pour définir le type de microcontrôleur utilisé et pour inclure un fichier de définition qui permet de définir des registres ou des ports, etc. Dans l’article N°8, nous avons vu que Studio 7 connaît les noms de registre, alors qu’avec l’IDE, il fallait donner les adresses, ce qui a impliqué une réécriture du programme mais cela aurait pu être fait avec un fichier de définition.

  1. ;*****************************************************************************
  2. ; DIRECTIVES D'ASSEMBLAGE
  3. ;*****************************************************************************
  4. .INCLUDE "m32def.inc" ; Fichier de définition du microcontrôleur

Vous pouvez ensuite faire des commentaires pour décrire les ports d’entrées-sorties utilisés, ainsi que les registres R0 à R31 utilisés avec l’usage qu’il en est fait. Ceci vous facilitera le travail si vous voulez ultérieurement modifier votre programme (ou si un ami veut le comprendre).

  1. ;*****************************************************************************
  2. ; PORTS D'ENTREES/SORTIES
  3. ;*****************************************************************************
  4. ; PD0 et PD1 libres pour Rx et Tx
  5. ; PD2 à PD7 Utilisés et reliés à LED par anode
  6. ; Port PB0 à PB5 Libre
  7. ; Port PC0 à PC5 Libre
  8.  
  9. ;*****************************************************************************
  10. ; DEFINITIONS DE REGISTRES
  11. ;*****************************************************************************
  12. ; r5 utilisé pour instruction LSL
  13. ; r8, r9 et r16 utilisés pour temporisation
  14. ; r17 utilisé pour initialisé PORT D
  15. ; r26 à r31 Réservé pour registre X, Y, Z (sans objet ici)

Vous pouvez ensuite décrire les variables et mettre les directives d’assemblage pour gérer la SRAM ou la Flash comme nous l’avons fait dans l’article N°8.

  1. ;*****************************************************************************
  2. ; ORGANISATION RAM
  3. ;*****************************************************************************
  4. .DSEG
  5. .ORG $100 ; début de la mémoire disponible pour l’utilisateur sur ATmega328P
  6. ; sans objet dans le programme Chenillard.

Les vecteurs RESET et interruptions sont à définir en tout début du programme proprement dit. Nous vous conseillons de le faire même si vous n’utilisez pas d’interruptions (ce que nous n’avons pas fait dans nos exemples pour ne pas trop surcharger la leçon de l’article, et c’est la raison pour laquelle on en parle ici). Voici un exemple pour les vecteurs de RESET et d’interruptions d’un ATmega328P :

  1. .CSEG
  2. .ORG $0000 ; Positionnement en début de mémoire Flash (0x0000)
  3. JMP RESET ; RESET handler
  4. JMP EXT_INT0 ; IRQ0 handler
  5. JMP EXT_INT1 ; IRQ1 handler
  6. JMP PCINT0 ; PCINT0 Handler
  7. JMP PCINT1 ; PCINT1 Handler
  8. JMP PCINT2 ; PCINT2 Handler
  9. JMP WDT ; Watchdog Timer Handler
  10. JMP TIM2_COMPA ; Timer2 Compare A Handler
  11. JMP TIM2_COMPB ; Timer2 Compare B Handler
  12. JMP TIM2_OVF ; Timer2 Overflow Handler
  13. JMP TIM1_CAPT ; Timer1 Capture Handler
  14. JMP TIM1_COMPA ; Timer1 Compare A Handler
  15. JMP TIM1_COMPB ; Timer1 Compare B Handler
  16. JMP TIM1_OVF ; Timer1 Overflow Handler
  17. JMP TIM0_COMPA ; Timer0 Compare A Handler
  18. JMP TIM0_COMPB ; Timer0 Compare B Handler
  19. JMP TIM0_OVF ; Timer0 Overflow Handler
  20. JMP SPI_STC ; SPI Transfer Complete Handler
  21. JMP USART_RXC ; USART, RX Complete Handler
  22. JMP USART_UDRE ; USART, UDR Empty Handler
  23. JMP USART_TXC ; USART, TX Complete Handler
  24. JMP ADC ; ADC Conversion Complete Handler
  25. JMP EE_RDY ; EEPROM Ready Handler
  26. JMP ANA_COMP ; Analog Comparator Handler
  27. JMP TWI ; 2-wire Serial Interface Handler
  28. JMP SPM_RDY ; Store Program Memory Ready Handler
  29. . . .

Comme vous le voyez, chaque vecteur d’interruption est une instruction JMP (ou RJMP) vers une étiquette où seront définies les routines d’interruption.

  1. RESET : ; ici commence le programme
  2. . . .

Si on n’utilise pas certaines interruptions, la routine d’interruption associée doit être écrite de la façon suivante (exemple pour EXT_INT0) :

  1. EXT_INT0 : nop ; ne rien faire (instruction facultative)
  2. reti ; retour d’interruption (il faut utiliser reti et non ret)
  3. . . .

Comme on le voit, en cas de RESET, le programme fera un saut vers l’étiquette RESET : donc là où commence le programme en fait. Le nom de l’étiquette peut être choisi différemment, par exemple debut: ou bien debut_PRGM:

Enfin, le début de programme est l’occasion d’initialiser la pile ; la procédure est décrite dans la datasheet (en rouge, les adresses de type word de la mémoire programme) :

  1. 0x0033 RESET: ldi r16, high(RAMEND) ; ici commence le programme
  2. 0x0034 out SPH, r16 ; SP en haut de SRAM
  3. 0x0035 ldi r16, low(RAMEND)
  4. 0x0036 out SPL, r16
  5. 0x0037 sei ; autorise interruptions si utilisées
  6. 0x0038 <instr> xxx
  7. . . .

Tout ce travail correspond à un programme minimum ; il ne reste plus qu’à le compléter pour développer l’application. Le paragraphe suivant explique comment s’organiser.

Travail de conception

Tout travail d’écriture d’un programme informatique doit commencer par une longue réflexion avant de commencer à coder. Ceci est vrai quel que soit le langage utilisé, mais ceci devient un impératif incontournable avec l’assembleur. Ce travail de réflexion se fait sur le papier avec un crayon et une gomme. Voici quelques étapes que vous aurez à suivre.

Les objectifs
Tout d’abord, il est nécessaire de bien cerner les objectifs de votre programme, ce qu’il doit finir par faire. Aucun programme sophistiqué n’est développé en une seule fois ; le mieux est de définir des phases d’élaboration en ajoutant à chaque phase réussie un objectif supplémentaire pour la phase suivante. Voyez par exemple comment a été conçu le programme gérant un passage à niveau décrit dans l’article Passage à niveau géré par Arduino (1).

Les contraintes
Une fois les objectifs définis, il faut lister les contraintes du projet : doit-on lire des capteurs, existe-t-il une contrainte temporelle à respecter, comment présenter les résultats ? Face à certaines contraintes, la solution est-elle de faire appel à de l’électronique supplémentaire ou bien d’adopter une solution logicielle ?

Les ressources internes ou externes
Voyons maintenant les ressources en commençant par celles du microcontrôleur : de quoi disposons-nous ? Par exemple, si nous avons besoin de communiquer par CAN, faisons-nous appel à une carte dédiée ou bien changeons-nous de microcontrôleur ? Certaines ressources internes seront utilisées et nécessiteront un recours à la datasheet pour comprendre leur fonctionnement. Quels registres internes sont utilisés par ces ressources ? Existe-t-il des bibliothèques pour gérer ces ressources, et si oui sont-elles adaptées ? Chaque fois que c’est possible, il ne faut pas hésiter à utiliser le travail des autres s’il est bien en Open Source.

Les variables (d’entrée, de sortie et intermédiaires)
À la fin de ce premier travail qui va déjà vous prendre du temps, vous aurez une idée de comment procéder. Ce qui suit va donc concerner la partie logicielle du projet : comment allez-vous faire ? Une des premières choses à faire est de définir toutes les variables qui concernent le projet : variables d’entrées (à traiter) et variables de sorties (à présenter) et bien sûr variables intermédiaires. En entrée, cela dépend des capteurs utilisés et en sortie, cela dépend du mode de présentation : une simple LED, un afficheur 7 segments, un écran LCD, un écran tactile couleur, etc. En fonction du type de variable, combien d’octets sont nécessaires pour la stocker et à quelle adresse allez-vous stocker ces octets ?

Les registres à usage général
Pour manipuler ces octets, vous aurez besoin des registres à usage général. Le mieux est de définir à l’avance le rôle de chaque registre. Les registres R16 à R31 sont utilisables avec n’importe quelle instruction, alors que ce n’est pas le cas pour les registres R0 à R15. Les registres R26 à R31 peuvent être utilisés pour stocker des adresses ; ils deviennent X, Y ou Z-Register. Pour les microcontrôleurs qui ont une mémoire dépassant 64 KB (ATmega2560 par exemple, qui équipe les cartes Mega), il devient nécessaire d’étendre ces registres avec un autre registre appelé RAMP. Enfin, si votre projet est construit sur une cohabitation entre du C et de l’assembleur, il est nécessaire de se rappeler comment les registres sont utilisés par le compilateur pour passer les arguments (voir l’article L’assembleur (6)). La figure 7 résume l’utilisation des registres dans un programme qui mélange C et assembleur.

Figure 7
Figure 7
Utilisation des registres entre C et assembleur (Source Microchip).

Avec tout cela, on comprend que les registres ne s’utilisent pas n’importe comment et il convient d’en tenir compte dans le travail de conception. Spécialiser un registre dans un seul type de tâche est un bon principe mais si votre programme est complexe, les 32 registres ne suffiront peut-être pas. Il est alors nécessaire de prévoir des sauvegardes de leur contenu dans la pile afin de pouvoir utiliser les registres avec d’autres données. Cela demande de la rigueur dans les ordres PUSH et POP afin de ne pas corrompre la pile ; pour faire simple, il faut autant de POP qu’on a mis de PUSH.

Les autres registres
RAMPX, RAMPY, RAMPZ : concaténés avec X-, Y- ou Z-Register, ils permettent d’adresser l’ensemble de l’espace mémoire de données pour un MCU qui dispose de plus de 64 KB d’espace données, et de récupérer les données constantes dans l’ensemble de la mémoire Flash pour un MCU qui dispose de plus de 64 KB d’espace programme.

RAMPD : concaténé avec Z-Register, il permet d’adresser l’ensemble de l’espace mémoire de données pour un MCU qui dispose de plus de 64 KB.

EIND : concaténé avec Z-Register, il permet des sauts et appels indirects dans la totalité de l’espace programme pour un MCU qui dispose de plus de 64 K-words (128 KB) d’espace programme.

STACK : pile (espace de la SRAM) pour stocker les adresses retour et les registres poussés. À ne pas confondre avec SP qui est le registre Stack Pointer qui pointe vers la pile.

Les instructions
Le choix des instructions n’est pas non plus anodin et il convient de trouver dans le jeu d’instructions celle qui convient le mieux à la tâche élémentaire à réaliser. Utiliser RCALL au lieu de CALL permet de gagner du temps d’exécution et de la place mémoire, mais ce n’est pas toujours possible. L’ALU met à jour le registre d’état SREG et sa surveillance permet d’éviter d’avoir à faire des comparaisons de données, ce qui donne un code plus efficace. Dans le choix des instructions, il est nécessaire de bien comprendre comment l’instruction agit, quelles sont les contraintes (par exemple sur ses arguments (registres, constantes littérales), ou bien le codage et la taille en mémoire, la durée d’exécution, etc.) et seul le recours à la documentation peut vous y aider.

Sous-programmes et interruptions
Prévoyez une programmation la plus structurée possible en écrivant des fonctions ou des sous-programmes. Listez les interruptions dont vous aurez besoin afin d’écrire les routines et de prévoir les vecteurs d’interruption et surtout pensez à sauvegarder les registres si nécessaire. Le bit I de SREG permet d’autoriser ou non les interruptions, mais cela n’empêche pas qu’il faut aussi les autoriser dans d’autres registres (selon la source d’interruption) et qu’il faut aussi savoir utiliser les registres de masques dans certains cas (voir par exemple l’article Les Timers (I) ou suivants qui parlent un peu de la notion de masque).

Si votre travail de conception a été bien mené sans rien oublier, le travail d’écriture des lignes de code coule de source.

Initialement, cette série d’articles devait se contenter de faire découvrir l’assembleur et de le présenter comme une technique possible pour programmer nos cartes à base de microcontrôleurs. Au fur et à mesure que l’on rédigeait les articles, il nous a paru nécessaire de donner des exemples concrets de programmes et puisque Locoduino est spécialisé en modélisme ferroviaire, de faire en sorte que ces exemples soient utiles pour ce hobby. Le but initial a non seulement été respecté mais aussi dépassé. Évidemment, après ces neuf articles, une petite partie seulement du sujet a été abordée, mais nous restons persuadés que l’essentiel a été dit pour vous permettre de vous y mettre vous aussi. Programmer en assembleur demande beaucoup de travail mais apporte en contrepartie la joie de découvrir l’intimité du microcontrôleur et de comprendre comment les ingénieurs ont conçu ce petit condensé de technologie. Alors n’hésitez pas et bon développement !

[1 H est mis à 1 lors de certaines opérations arithmétiques qui génèrent une retenue du quartet de poids faible d’un mot de 8 bits vers le quartet de poids fort.

Réagissez à « L’assembleur (9) »

Qui êtes-vous ?
Votre message

Pour créer des paragraphes, laissez simplement des lignes vides.

Lien hypertexte

(Si votre message se réfère à un article publié sur le Web, ou à une page fournissant plus d’informations, vous pouvez indiquer ci-après le titre de la page et son adresse.)

Rubrique « Programmation »

Comment gérer le temps dans un programme ?

La programmation, qu’est ce que c’est

Types, constantes et variables

Installation de l’IDE Arduino

Répéter des instructions : les boucles

Les interruptions (1)

Instructions conditionnelles : le if … else

Instructions conditionnelles : le switch … case

Comment concevoir rationnellement votre système

Comment gérer l’aléatoire ?

Calculer avec l’Arduino (1)

Calculer avec l’Arduino (2)

La compilation d’un projet Arduino

Les structures

Systèmes de numération

Les fonctions

Trois façons de déclarer des constantes

Transcription d’un programme simple en programmation objet

Ces tableaux qui peuvent nous simplifier le développement Arduino

Les chaînes de caractères

Trucs, astuces et choses à ne pas faire !

Processing pour nos trains

Arduino : toute première fois !

Démarrer en Processing (1)

TCOs en Processing (1)

TCOs en Processing (2)

Comment réussir son projet Arduino

Passage à niveau géré par Arduino (1)

Passage à niveau géré par Arduino (2)

Passage à niveau géré par Arduino (3)

Passage à niveau géré par Arduino (4)

Passage à niveau géré par Arduino (5)

Du sketch à l’exécutable

Programmer vos Arduino avec un fichier hexadécimal

Le monde des objets (1)

Le monde des objets (2)

Le monde des objets (3)

Le monde des objets (4)

Les pointeurs (1)

Les pointeurs (2)

Les Timers (I)

Les Timers (II)

Les Timers (III)

Les Timers (IV)

Les Timers (V)

Bien utiliser l’IDE d’Arduino (1)

Bien utiliser l’IDE d’Arduino (2)

Piloter son Arduino avec son navigateur web et Node.js (1)

Piloter son Arduino avec son navigateur web et Node.js (2)

Piloter son Arduino avec son navigateur web et Node.js (3)

Piloter son Arduino avec son navigateur web et Node.js (4)

Les derniers articles

L’assembleur (9)


Christian

L’assembleur (8)


Christian

L’assembleur (7)


Christian

L’assembleur (6)


Christian

L’assembleur (5)


Christian

L’assembleur (4)


Christian

L’assembleur (3)


Christian

L’assembleur (2)


Christian

L’assembleur (1)


Christian

Programmer vos Arduino avec un fichier hexadécimal


Christian

Les articles les plus lus

Les Timers (I)

Les interruptions (1)

Instructions conditionnelles : le if … else

Ces tableaux qui peuvent nous simplifier le développement Arduino

Comment gérer le temps dans un programme ?

Les Timers (II)

Répéter des instructions : les boucles

Bien utiliser l’IDE d’Arduino (1)

Calculer avec l’Arduino (1)

Piloter son Arduino avec son navigateur web et Node.js (1)