Retrouvez cet article dans : Linux Magazine 84
1. Ode à l’AVR
Pour les lecteurs ayant raté le hors-série 23, voici un petit résumé de ce qu’est un microcontrôleur AVR. Un microcontrôleur est un processeur couplé à de la mémoire (Flash de préférence) et à un ensemble de fonctionnalités intégrées (convertisseurs, timers, sources d’interruption interne et externes, etc.). Pour utiliser le microcontrôleur, il suffit de créer un code et de le télécharger dans le composant. Dès la mise sous tension (ou après un reset), le microcontrôleur exécute le code embarqué. Il existe des centaines de microcontrôleurs produits par différents fabricants parmi lesquels Microchip, SGS Thomson, Intel ou encore Atmel. Ce dernier propose une vaste gamme appelée AVR qui est directement concurrente de la gamme proposée par Microchip sous le nom de PIC. AVR et PIC sont souvent mis dans le même panier, car ils font l’objet d’une attention toute particulière de la presse et des sites spécialisés en électronique. En effet, AVR comme PIC disposent d’une large logithèque, sont peu onéreux et relativement faciles à programmer, par rapport, par exemple, aux dérivés de 68HC11/12. La popularité des deux gammes, PIC et AVR, permet à l’utilisateur GNU/Linux de disposer d’un certain nombre d’outils de développement, contrairement aux autres microcontrôleurs du marché, pour lesquels il n’existe souvent que des solutions Windows. Les différents modèles d’une gamme se distinguent en fonction de plusieurs caractéristiques :- La taille de mémoire Flash utilisable allant du simple ko à 256 ko. Il faut préciser ici que cette valeur est relative, car certains microcontrôleurs se programment en mots de 16 bits et d’autres de 12 bits. Le nombre d’instructions téléchargeables dans la mémoire est donc variable selon le modèle et le fabricant.
- Le nombre d’entrées/sorties, de 3 à près d’une centaine.
- La puissance en fréquence d’horloge ou en MIPS.
- Le nombre de convertisseurs analogique/digital.
- Le nombre de registres de travail et/ou le volume de mémoire vive (RAM).
- Les fonctionnalités courantes (timer, watchdog, PWM, etc.).
- Les fonctionnalités spécifiques (USB, USB On-The-Go (OTG), wireless, i2c, etc.).
- Le format (PDIP, SOIC, TQFP, PLCC, etc.).
- Le prix.
- C’est un avis tout personnel, mais l’AVR semble se distinguer très clairement des PIC et autres concurrents :
- Une partie de la gamme AVR accepte du code développé avec GCC (ATmega par exemple) en raison de l’important volume de mémoire Flash. Comme l’article du hors-série le présentait, il est parfaitement possible d’écrire du code C efficace pour un microcontrôleur AVR et profiter d’une bibliothèque C spécialisée. Les petits modèles d’AVR se programmeront en assembleur. C’est l’objet du présent article.
- La programmation du microcontrôleur AVR est dite " ICSP " ou " in situ ". Le microcontrôleur est connecté classiquement, comme pour sa mise en œuvre définitive et on greffe une connectique spécifique pour le programmer sans avoir recours à un montage spécial (un programmeur). La liaison AVR/PC se fera généralement via un port parallèle (il existe également des adaptateurs série). Les PIC nécessitent souvent un programmeur comme le montage JDM (voir GLMF 73, juin 2005) via un port série RS232 en voie de disparition sur les configurations actuelles et posant un certain nombre de problèmes d’alimentation. Dans les deux cas, AVR comme PIC, les logiciels permettant le chargement du code dans la mémoire du microcontrôleur existent sous GNU/Linux.
- L’assembleur utilisé pour les AVR est plus abordable pour le débutant. Certes, ce langage reste ce qu’il est, mais les PIC ajoutent à la complexité en travaillant avec deux banques (16F628 par exemple) avec lesquelles il faut jongler. Le jeu d’instructions de l’AVR est plus riche et, même si cela ne semble pas être un élément important pour les spécialistes, on dispose d’une plus grande liberté dans le développement.

Fig. 1 : Schémas de connexion de l’adaptateur ICSP sur port parallèle. Ce montage est sans doute le plus simple qui soit, mais n’offre aucune protection.
2. ATtiny15L
L’ATtiny15L est au cœur du présent article. Pour le décrire, commençons par l’aspect le plus bassement matérialiste : le prix. Un ATtiny15L, acheté auprès d’un détaillant électronique (GoTronic, Selectronic, Conrad, etc.), vous coûtera un peu plus de 3 euros. En prenant en compte les composants nécessaires à la fabrication de l’adaptateur ICSP et quelques composants de base pour l’expérimentation (résistances, LED, condensateurs, etc.), vous pouvez compter un budget entre 15 et 30 euros pour des heures de plaisir. Notez également que des kits de développement et des programmeurs Atmel existent sous les désignations STK200, STK300 ou STK500. Ces kits sont compatibles avec l’application de programmation pour GNU/Linux décrite ci-après. Si le prix d’un achat neuf calme vos ardeurs (environs 150 euros) peut-être aurez-vous la chance d’en trouver d’occasion sur les sites d’enchères en ligne. Néanmoins, la solution consistant à fabriquer son propre adaptateur ICSP est bien plus économique (quelques euros). Venons-en aux caractéristiques de l’ATtiny15L dont le seul point faible, à mon goût, est le manque d’entrées/sorties, ce qui est normal vue sa taille. Ceci est toutefois largement compensé par la richesse des fonctionnalités :- 1 ko de mémoire Flash. Voilà qui est largement suffisant pour les applications envisageables avec ce type de composant. Notez que la prochaine génération d’ATtiny disposera de bien plus de mémoire Flash pour un format (PDIP 8) identique.
- Oscillateur interne de 1.6 Mhz. Il y a quelques années, il était nécessaire d’utiliser un quartz ou un circuit RC en guise d’horloge pour le microcontrôleur. L’ATtiny15L comme bien d’autres est en mesure de se passer de ce type de chose en utilisant son propre oscillateur interne calibré. Plus simplement, cela signifie l’économie de deux broches sur le composant et une mise en œuvre bien plus simple.
- 32 registres de 8 bits. Il s’agit, grossièrement, de la mémoire vive du système ou, si vous voulez, de vos variables.
- 64 octets d’EEPROM. Contrairement aux registres qui sont dans un état indéterminé après la mise sous tension, l’EEPROM conserve les données stockées lorsque le composant n’est plus sous tension. Nous avons donc la mémoire Flash pour le programme et les données statiques, les registres pour les variables et l’EEPROM pour le stockage. Une partie de la configuration du microcontrôleur est également stockée dans l’EEPROM.
- 6 entrées/sorties utilisables selon configuration. Il faut pondérer cette caractéristique, car sur les 6 E/S disponibles, une est utilisée, par défaut, par le reset externe. Il est possible de " récupérer " cette sortie, mais la programmation ICSP basse tension n’est alors plus possible. Sur les 5 E/S restantes, il faut également prendre en considération les multiples fonctions de chaque broche. Ainsi, par exemple, la broche 7, nommée PB2, est une E/S binaire, mais peut également être configurée comme source d’interruption externe ou entrée analogique. Notez également que 4 des 6 E/S sont utilisées pour la programmation ICSP. C’est à ce prix qu’il est possible de " bourrer " tant de fonctionnalités dans un composant de 8 broches.
- 2 timers. Un timer peut être vu comme une tâche de fond (attention, c’est une simple illustration, un AVR n’est pas un système multitâche). Une fois configuré dans ce sens, un timer va déclencher périodiquement une interruption. Une interruption, comme son nom l’indique, est un évènement qui va interrompre le fonctionnement du programme. Le programmeur aura pris soin de créer un morceau de code spécifique qui sera alors exécuté. Ceci fait, le fonctionnement normal du code reprendra. Notez au passage que le microcontrôleur ne peut pas ne rien faire. Tout comme avec une application graphique, il faut une boucle principale.
- Un convertisseur analogique/digital (ADC) multiplexé en 4 canaux. Le monde ne se compose pas de 0 et de 1. Pour que le microcontrôleur puisse travailler avec des données analogiques, il faut les convertir en valeurs numériques. L’ATtiny15L intègre un convertisseur 10-bit utilisable de différentes manières (relative ou absolue).
- Une sortie PWM rapide (Pulse Width Modulation ou modulation de largeur d’impulsion) à 150 kHz. Nous y reviendrons plus en détail dans un prochain article.
- Différentes fonctionnalités intéressantes, comme la mise en sommeil (sleep mode) avec un réveil sur changement d’état d’une des broches, le contrôle de la qualité d’alimentation (Brown-out Detection Circuit), le chien de garde (Watchdog) programmable pour assurer la disponibilité du système et le reset automatique en cas de problème, etc.
3. Programmation
Au risque de me paraphraser (article dans le HS23), voici de brèves explications sur la méthode de programmation des composants AVR et l’ICSP. Le schéma page 91 présente la connexion et la composition de l’adaptateur ICSP sur port parallèle d’un PC. Comme vous pouvez le constater, il est très simple, mais des adaptateurs plus complexes reposant par exemple sur le driver de ligne 74HC244 sont documentés sur le Web et sont également supportés par les logiciels de programmation AVR existant sous GNU/Linux. L’adaptateur décrit ici présente l’avantage de " tenir " dans un le cache plastique d’un connecteur parallèle, mais n’offre pas toutes les protections peut-être souhaitées (inversion de connecteurs, court-circuit, etc.).
L’ATtiny15L en situation. Notez le fil vert reliant le reset avec Vcc. Dans sa configuration par défaut, la broche 1 (PB5) n’est pas utilisable et doit être reliée au Vcc ou à un circuit avec un bouton poussoir et une résistance de rappel au Vcc. En mettant la broche 1 à la masse, on fait alors un reset du microcontrôleur.
Remarquez que les adaptateurs ICSP, quels qu’ils soient, sont utilisables avec toute la gamme AVR 8-bit d’Atmel. Il faudra simplement prendre garde à bien repérer les broches MOSI (Master Out Slave In), MISO (Master In Slave Out), RST (reset) et SCK (Serial ClocK) pour chaque microcontrôleur de la gamme.
Côté logiciel, j’ai opté pour uisp, un programme d’Uros Platise maintenu actuellement par Marek Michalkiewicz (http://www.nongnu.org/uisp/index.html). Ce logiciel en ligne de commande supporte bon nombre d’adaptateurs, dont celui décrit dans cet article (sous la désignation dapa pour " Direct AVR Parallel Access ").
La programmation, une fois l’adaptateur connecté à l’AVR, se fera très simplement, en trois étapes. Tout d’abord, il convient d’effacer la mémoire Flash du microcontrôleur :
uisp -dlpt=/dev/parport0 --erase -dprog=dapaOn charge ensuite le programme :
uisp -dlpt=/dev/parport0 --upload if=prog.hex \ -dprog=dapa -dno-poll -vEnfin, l’étape qui n’est pas strictement nécessaire mais fortement recommandée, la vérification :
uisp -dlpt=/dev/parport0 --verify if=prog.hex \ -dprog=dapa -dno-poll -vBien entendu, l’utilisateur doit avoir les permissions adéquates (rw) sur l’entrée dans
avr-as: C’est l’assembleur GNU livré avec avr-gcc. Je ne recommanderai pas cette solution sauf si vous avez l’habitude de l’utiliser sur une autre plate-forme. La syntaxe de l’assembleur n’est pas la même que la solution mise à disposition par Atmel (AVR Studio) et l’adaptation de code trouvé sur le Web sera difficile.avra: Voici l’une des solutions packagées dans Debian. L’assembleur est mature, mais nécessitera l’utilisation de fichiers d’en-tête personnalisés ou repris du kit de développement Atmel. Ceci n’est pas un point critique, car ces fichiers se limitent à décrire une correspondance entre des adresses et des mots clefs qu’on trouvera dans le datasheet (documentation) du composant.gavrasm: Un autre assembleur très performant et également compatible avec la syntaxe de l’assembleur Atmel.gavrasmséduit par le fait qu’il apporte des informations complémentaires lors de l’assemblage du code comme celles qu’on a l’habitude de trouver avec un compilateur C (avertissement des variables/registres définis mais non utilisés, etc.). On notera toutefois quegavrasmintègre " en dur " les correspondances habituellement déclarées dans les fichiers d’en-tête. Ceci peut sembler très pratique, mais souvent déroutant et surtout très inhabituel.
4. Et si on codait ?
L’assembleur donne souvent une double image à la fois attirante et rebutante. Assembleur est souvent synonyme de performances, mais également de complexité. Ce n’est qu’en passant au-delà des préjugés qu’on se rend finalement compte qu’il n’en est rien. Il vous faudra simplement oublier vos habitudes de développeur C, Perl ou Python et les avantages mis à disposition par ces langages de haut niveau. Nous allons commencer par un classique du genre, j’ai nommé l’équivalent du " hello world ", la fameuse LED qui clignote :.device attiny15
; pour avra uniquement
.include "attiny15IO.asm"
.org 0x0000
rjmp RESET
.org 0x0009
RESET:
sbi DDRB,PB4
LOOP:
sbi PORTB,PB4
cbi PORTB,PB4
rjmp LOOP
Le fichier .equ PORTB = 0x18 .equ DDRB = 0x17 .equ PB4 = 4 .equ PB3 = 3 .equ PB2 = 2 .equ PB1 = 1 .equ PB0 = 0Avant toutes choses, précisons différents points :
- L’assembleur n’est pas sensible à la casse. Néanmoins, il est courant de laisser les instructions en minuscule et les constantes en majuscule.
- Les directives débutant par un point sont destinées à l’assembleur lui-même. Elles permettent de préciser des éléments importants pour l’assemblage comme, par exemple, le microcontrôleur cible (
.device). - Les commentaires sont précédés d’un point-virgule. L’assembleur ignorera tout ce qui se trouve entre ce symbole et la fin de la ligne.
5. Base de programmation ASM
A ce stade, je vais considérer que vous avez assimilé les quelques éléments déjà donnés. Nous allons donc accélérer la cadence et prendre quelques raccourcis. Lorsque je parle de pause dans l’exécution du code, il ne s’agit en fait que de l’exécution d’instructions ne servant à rien. Il existe une instruction spécifique permettant d’obtenir ce résultat :delai:
clr t1
hop:
dec t1
brne hop
dec temp
brne hop
ret
En tout début de code, nous assignons des noms à certains registres :
.def t1 = r1 .def temp = r16Il ne s’agit pas de constantes définies avec la directive
r16Ãr29supportent toutes les instructions de manipulation sur les registres. Je vous fais grâce de la liste, mais sachez que ces registres supportent les instructionssbci,subi,cpi, andi,orietldipermettant d’utiliser des valeurs immédiates. Une valeur immédiate est explicitement donnée dans le code. Ainsi,ldi temp,0x42placera la valeur0x42dans le registretemp. Ceci ne fonctionnera que sitempest un registre entrer16etr31.r1Ãr15s’utilisent comme les registres précédents, mais ne supportent pas les manipulations avec des valeurs immédiates. Si vous voulez placer0x42dans le registre r1 par exemple, vous devrez faireldi temp,0x42, puismov r1,temp. Ces registres limités seront donc principalement utilisés pour des compteurs et d’autres opérations où le code n’initialise pas directement le contenu des registres.r30etr31peuvent être utilisés comme des registres classiques. Ils seront cependant réservés pour un mode d’adressage spécifique. Ces deux registres forment un pointeur de 16 bits (le pointeur Z) qui adresse la mémoire Flash. Une fois ces deux registres initialisés, on utilisera l’instructionlpm(Load Program Memory) qui chargera alors l’octet pointé dansr0. Ce type de manipulations permet de stocker dans la mémoire Flash, non plus des instructions, mais des données via la directive.dbde l’assembleur. On placera à cet effet une étiquette permettant de calculer l’adresse à pointer.
delai:clr t1, nous commençons par mettre le registret1à zéro.hop:dec t1, nous décrémentons ensuite le registre de 1. Initialisé précédemment Ã0, celui-ci passe Ã0xFF. A ce stade, il faut parler du principe des drapeau (flags). Certaines opérations " lèvent " des drapeaux en fonction de leur résultat. Ici, le drapeau qui nous intéresse est Z pour Zéro. Celui-ci est activé lorsque le résultat d’une opération donne0.brne hopest une instruction de branchement conditionnel : Branch if Not Equal. Ce n’est pas très explicite, mais un saut est effectué si le drapeauZn’est pas levé suite à la dernière opération (Not Equal, car dans une comparaison, lorsqu’il y a égalité, la différence est zéro). Ainsi, après chaque décrémentation, si le registret1n’est pas zéro, nous sautons Ãhop:. C’est une boucle conditionnée.dec temp, décrémentetemp. Si nous arrivons là , c’est quet1est Ãzéro.tempsera initialisé dans le code avant l’appel à la sous-routine.brne hopest notre dernier branchement conditionnel qui utilise la précédente opération, celle qui décrémentetemp. Cette condition ne sera testée qu’après chaque tour du registret1. Nous avons deux boucles conditionnées imbriquées. La valeur placée danstempdétermine le nombre de " tours " de boucle utilisantt1.retest l’instruction de retour permettant de terminer l’appel à la sous-routine. L’adresse de l’appel a été placée sur la pile. Cette pile supporte trois niveaux d’appels aux sous-routines, pas plus.
LOOP:
sbi PORTB,PB4
ldi temp,0x15
rcall delai
cbi PORTB,PB4
ldi temp,0x7F
rcall delai
rjmp LOOP
Dès le chargement du code dans l’AVR, on voit immédiatement le changement. Cette fois, le clignotement de la LED est bien visible (voir photo, non ça ne clignote pas dans le magazine). Ceci nous a permis de faire connaissance avec la notion de sous-routines, de registres et de sauts conditionnels. A ce stade, vous avez une excellente base de travail en assembleur AVR.
6. Conclusion temporaire
Arrêtons là pour cette fois. Il reste beaucoup à dire sur le développement en assembleur sur ATtiny15L et nous y reviendrons dans un prochain article où il sera question d’interruptions, de timer, de PWM et de stockage des données dans la mémoire Flash. En attendant, je vous conseille de vous équiper, de faire ces premiers essais et surtout de parcourir le datasheet téléchargeable sur le site du fabricant (http://www.atmel.com). Liens- La page ATtiny15L sur le site Atmel : http://www.atmel.com/dyn/products/product_card.asp?part_id=2033
- Un site incontournable par et pour les utilisateurs d’AVR : http://www.avrfreaks.net/
- Le programmeur AVR de C. Tavernier : http://www.tavernier-c.com/programmateur_atmel.htm
- La documentation wikibooks sur l’AVR : http://en.wikibooks.org/wiki/Atmel_AVR
- L’article de Guido sur la programmation AVR en C : http://tldp.org/linuxfocus/Francais/November2004/article352.shtml
Retrouvez cet article dans : Linux Magazine 84





Donnez votre avis
Vous devez avoir ouvert une session pour écrire un commentaire.