vendredi 29 novembre 2013

surprise et perplexité.

J'étais en train d'écrire une routine de division en assembleur sur PIC32MX lorsque j'ai réalisé que le core MIPS M4K n'a pas de registre d'état. Ça fait des mois que je travaille avec des PIC32MX et jusque là je n'avais pas porté attention à ce fait. En réalité c'est le seul processeur que je connais qui n'en possède pas et j'en ai vu pas mal ces 40 dernières années. Comme cette routine de division utilise un décalage vers la gauche sur 2 mots de 32 bits j'étais un peut perplexe. En effet habituellement lorsqu'on fait un décalage à gauche ou à droite sur plusieurs mots on utilise une instruction qui récupère le bit qui sort dans le carry bit et de là on le récupère pour le faire entrer dans le mot suivant. C'est du moins comme ça que ça se passe sur la majorité des micro-processeurs. J'ai donc du adapter ma routine en vérifiant l'état du bit avant de faire le décalage et faire un branchement conditionnel en fonction de l'état de ce bit. La routine nécessite donc plus d'instructions que sur un processeur ARM par exemple qui laisse le dernier bit sorti dans carry bit du registre d'état.

C'est encore une preuve que les habitudes nous rendent aveugle. Ce n'est pas que je n'avais pas étudier le modèle de programmation du core M4K mais je prenais pour acquis que tout processeur à un registre d'état ce qui fait que cette absence n'était pas passé au niveau conscient puisqu'il n'avais pas été requis dans ma programmation jusque là.

présentation des PIC24

Dans cette article je fais une brève présentation des micro-contrôleurs PIC24 de Microchip.

Architecture

Comme les autres PIC les PIC24 sont basés sur une architecture Harvard mais là s'arrête la ressemblance. Il s'agit de micro-contrôleurs 16 bits avec 16 registres généraux. Ils possèdent un multiplicateur en hardware ainsi qu'un support à la division.

Structure interne

Le compteur ordinal a 23 bits. Les instructions son encodées sur 24 bits et le compteur peut adresser 4Mi. Notez cependant que le bit le plus faible du compteur ordinal est toujours à zéro, les adresses impaires ne peuvent-être accédées. La mémoire est organisé en mots de 24 bits mais l'alignement du compteur ordinal se fait comme s'il s'agissait de 2 mots de 16 bits. Donc dans les faits le compteur ordinal est incrémenté de 2 à chaque instruction. Il n'y a pas d'octets perdus cependant car l'octet le plus lourd (bits 24-32) n'est pas implémenté en mémoire. Cette arrangement est pour rendre comptable l'adressage avec la mémoire RAM qui elle est organisée en mots de 16 bits.

Les registres généraux sont nommés W0 à W15. W15 sert de pointeur de pile, celle-ci étant en mémoire RAM. IL y a un registre SPLIM qui détermine la taille de la pile. S'il y a débordement de la pile l'exception 3 stack error est déclenchée. Notez la présence du registre RCOUNT, c'est un compteur de boucle qui fonctionne avec l'instruction assembleur REPEAT. Cette instruction utilisée avec les instructions DIV.SD, DIV.SW, DIV.UD et DIV.UW permet de faire une division en seulement 19 cycles machine. Les boucles REPEAT sont limitées à une seule instruction, celle qui suis le REPEAT. Mais comme l'instruction MOV encode la source et la destination par indirection via registre auto-incrémenté, une seule instruction permet de copier un bloc de mémoire d'un endroit à un autre ou vers un SFR de périphérique.

Contrairement à la plupart des MCU à registres comme les AVR, MIPS ou MSP430, les PIC24 peuvent utiliser une donnée en mémoire RAM comme argument d'une opération ALU, dans ce cas W0 alias WREG est utilisé comme autre argument. Le résultat peut-être enregistré dans WREG ou la variable en RAM. Ce type d'instruction même s'il exige une lecture et possiblement une écriture dans la RAM s'exécute en un seul cycle. Comme pour les PIC32MX les instructions à 3 arguments sont aussi possible comme ADD Wb,Ws,Wd qui additionne le contenu de Wb avec Ws et met le résultat dans Wd.

Interruptions

Les interruptions multi-niveaux sont supportées. Il y a 2 tables de vecteurs d'interruptions contenant chacune 126 entrée. Les 8 premières entrées sont réservés aux exceptions (trap). Ces tables commencent à l'adresse 0x000004 et se terminent à l'adresse 0x000200. L'interruption 0 est à l'adresse 0x14 pour la table principale et 0x114 pour la table alternative. Chaque table occupe 256 octets incluant les trap et le reset vector. La table alternative sert au débogage. Chaque entrée de table contient une adresse de 24 bits qui est le point d'entrée de l'ISR servant le vecteur correspondant. La priorité d'interruption est par ordre inverse du numéro de vecteur. Le vecteur 0 a la plus haute priorité et le 117 la plus faible.

Modèle de programmation

Programme démo en C

Plusieurs modèles de PIC24 sont disponibles en format PDIP-14, PDIP-20 et PDIP-28. Pour ce démo j'ai choisi un PIC24F16KA101-I/P ainsi qu'une matrice de LED 8x8. La matrice de LEDs est organisée en 8 lignes par 8 colonnes. Les cathodes sont connectées sur les colonnes et les anodes sur les lignes. Le PIC24F16KA101 possède 16Ko de mémoire flash et 1,5Ko de RAM et les périphériques qu'on retrouve le plus souvent sur un MCU, minuteries, convertisseur A/N, UART, I2C. Il fonctionne à une fréquence maximale de 32Mhz. Il peut-être programmé avec un PICKIT 2.

L'environnement de développement est MPLABX avec le compilateur XC16 disponible en version gratuite avec optimisation de code limité comme c'est l'habitude chez Microchip.

Le démo est une implémentation de l'automate cellulaire appelé Jeux de la vie. Le démo joue 3 configurations en séquence. Il passe à la configuration suivante après 16 générations. C'est la variable max_gen qui détermine le nombre de générations calculées pour chaque configuration initiale.

schématique

La grille de LED est multiplexé 1 LED à la fois. Le rapport cyclique de chaque LED est donc de 1/64 on obtient néanmoins une intensité d'affichage satisfaisante. Pour ne pas interrompre le multiplexeur d'affichage le calcul de la génération suivante est intercalé dans le multiplexeur par appel de la fonction next_gen(). Une seule cellule est recalculée par appel. Il y a 2 tableaux contenant l'état de l'univers, lifea et lifeb. Tandis qu'un tableau est affiché le calcul de la génération suivante est enregistré dans l'autre. La variable grid détermine quel est le tableau à afficher. Le tableau est commuté à tous les 100 cycles du multiplexeur d'affichage (variable k dans display_grid()). Ce délais donne un peu plus 0,5 seconde entre chaque commutation.

Pour la Configuration bits settings j'ai procédé comme je le fais avec les PIC32MX. C'est à dire que j'utilise le menu Window - PIC memory views - configuration bits. Après avoir configuré les bits dans cette grille j'utilise le bouton generate source code to Output et ensuite un copier-coller vers mon fichier source.

Pour ce démo le MCU fonctionne à 8Mhz sur l'oscillateur interne mais cette fréquence peut-être augmentée à 32Mhz grâce au PLL inclus dans le MCU.

Code source du démo

Vidéo du démo

Conclusion

Dans un prochain article je vais présenter un démo en assembleur.

dimanche 24 novembre 2013

moteur pas à pas

Dans cette article j'explique comment contrôler un moteur pas à pas . Pour ce démo j'ai utilisé un MSP430 launchpad et un C.I. L293D pour piloter le moteur. Comme moteur j'ai utilisé le mécanisme de transport de la tête de lecture d'un graveur de CD. On retrouve aussi le même type de mécanisme dans les lecteurs de disquettes.

schématique

Le moteur a 2 bobines et comme illustré ci-haut. Il s'agit d'un moteur bipolaire il y a donc 4 connections au moteur. Sur les moteurs unipolaire il y a en 6.

Description

En fait le programme pour contrôler un moteur pas à pas est simple. On a besoin d'un pont H pour chaque bobine et c'est le L293D qui contient 4 demi-pont H qui est utilisé dans ce but. Lorsqu'on alimente une bobine le rotor s'aligne sur le champ magnétique créé par la bobine. Si on alimente les 2 bobines en même temps le champ magnétique résultant est entre les 2 bobines et le rotor s'aligne donc entre celle-ci. Donc pour déplacé le rotor on déplace le champ magnétique du stator en alimentant alternativement les bobines.

Il y a plusieurs façon d'alimenter un moteur pas à pas mais celle qui donne le plus petit angle de rotation à chaque pas est la suivante:

pasa1b1a2b2
1+5v0v0v0v
2+5v+5v0v0v
30v+5v0v0v
40v+5v+5v0v
50v0v+5v0v
60v0v+5v+5v
70v0v0v+5v
8+5v0v0v+5v
Pour faire tourner le moteur en continu dans un direction il suffit de répéter ces 8 pas en boucle et pour le faire tourner dans l'autre sens on les répète à l'envers c'est à dire de 8 à 1. J'ai branché les 4 fils des bobinages sur le même port (PORT1) de sorte qu'il suffit de conserver les valeurs pour chaque pas dans un tableau indicé par la phase. Il faut écrire la valeur correspondant à la phase ou le moteur est rendu dans P1OUT. La valeur de chaque nombre dans le tableau correspond aux étapes de cette table.

Un moteur pas à pas il n'y a pas de rétroaction comme pour le cerveau moteur donc on ne connaît pas la position du moteur. Il faut compter les pas et habituellement on utilise des commutateurs en fin de course pour indiquer que la limite est atteinte. Mais si la charge est trop grande et que le moteur glisse le compteur de pas n'est plus valide il faut voir à ce que la charge ne dépasse pas la capacité du moteur. Il faut aussi tenir compte de l'inertie. Plus la charge est grande plus le moteur va prendre de temps pour s'aligner sur la nouvelle position. Donc le délais de pas doit-être augmenter avec la charge. Comme au départ je ne connaissait pas les caractéristiques du moteur j'ai commencer les tests avec un délais long (50msec), pour le réduire progressivement jusqu'à 1msec. Mais à 1 msec le moteur vibre. A 2msec c'est parfais. Mais si je mettais une charge sur le chariot il faudrait probablement augmenter ce délais.

Pour ce démo j'ai simplement vérifier à quelle vitesse je pouvais déplacer le chariot de tête du graveur en envoyant 200 impulsions dans un sens et ensuite 200 dans l'autre.

déplacement lent, 50msec/pas déplacement rapide 2msec/pas.

Conclusion

Comme on le voie un pilote de moteur pas à pas c'est simple. Il serait facile d'adapter ça en assembleur pour n'importe quel microcontrôleur.