Quantcast
Channel: PICatout
Viewing all 192 articles
Browse latest View live

Du nouveau chez Microchip

$
0
0

Finalement ils sont . La rumeur circulais depuis plusieurs mois à propos de ces PIC32MZ. Il s'agit des nouveaux MCU 32 bits avec un nouveau core, le MIPS MicroAptiv, plus performant que le M4K des PIC32MX. Il peuvent fonctionner jusqu'à 200Mhz, avoir 2Mo de Flash et 512Ko de RAM. C'est suffisant pour faire tourner un système GNU/Linux ou BSD unix. La frontière entre MCU et SoC devient de plus en plus floue. Je m'attendais à ce qu'ils soient multicore mais mes attentes sont déçues. Évidemment le prix est à l'avenant, le modèle le plus économique vaut 13,94CAN$ (PIC32MZ1024ECG064-I/PT) actuellement chez Digikey.ca

Il existe 2 starter kit au coût de 172CAN$. À ce prix je passe.


Autre découverte que j'ai faite aujourd’hui en furetant sur Microchip.com le PIC16F527. Je ne sais pas si c'est un petit nouveau ou un MCU qui avait échappé à mon attention jusque là mais le datasheet est daté du 2013-12-13.

Ce qu'il a de spécial est ceci, il est de la famille des baseline mais la pile des retours à 4 niveaux au lieu de 2 et il supporte les interruptions avec sauvegarde automatique des registres W, STATUS, BSR et FSR. Mais sa plus grande particularité est qu'il contient 2 amplificateurs opérationnels.

Certains préfèrent les PIC

Y a t-il un autre manufacturier qui a une offre de produit aussi varié que Microchip en terme de MCU? Peut-être TI mais surement pas Atmel. Et à ma connaissance c'est le seul qui offre des MCU 32 bits en format DIP-14, DIP-20 et DIP-28. Si ce n'était de la popularité des carte Arduinos, je ne crois pas que les AVR auraient connue autant de succès. Voilà pourquoi ce blog s'appelle PICatout.


project PICvision

$
0
0

Il y a quelques semaines je suis tombé sur le projet Hackvision. Il s'agit d'une console de jeux rétro très économique et que chacun peut fabriquer chez lui sans avoir à utiliser de technologie de montage en surface. C'est donc à la porté de tous. Elle peut aussi être achetée toute assemblée chez Robotshop. Cette console est conçu pour se brancher sur un téléviseur avec une entrée composite NTSC ou PAL. Il s'agit d'un signal monochrome.

Le AtMega328P-PU utilisé ne possède que 2Ko de RAM donc la résolution vidéo est limitée à 136x96 pixels. En voyant ça j'ai décidé de faire une console semblable mais en utilisant un MCU PIC. Mais il n'y a pas de raison de se limiter à un MCU 8 bits. Microchip offre des MCU 16 bits et 32 bits en format PDIP-28. J'ai hésité entre utiliser un PIC24F et un PIC32MX. Puisqu'en fin d'année 2013 j'ai écris quelques articles de présentation des PIC24 j'ai finalement opté pour un PIC24FJ64GA002-i/p.

Il s'agit d'un projet open source sous licence GNU GPLv3 pour le code source et Creative Commons CC BY-SA pour les autres documents . Tous les fichiers sont disponibles sur https://github.com/Picatout/PICvision

Comparaison entre Hackvision et PICvision

Comparaison des microcontrôleurs:

paramètreAtMeag328PPIC24FJ64GA002
disponible en format PDIP-28ouioui
mémoire flash32Ko64Ko
mémoire RAM2Ko8Ko
temps de cycle cpu minimum50nsec62,5nsec
minuteries2 x 8 bits, 1 x 16 bits3 x 16 bits
périphériques OC (PWM)65
périphériques SPI12
périphériques I2C12
prix unitaire (digikey.ca)3,87CAN$4,40CAN$

comparaison des consoles:

paramètreHackvisionPICvision
assemblagefacile sur carte de prototypagefacile sur carte de prototypage
résolution136x96216x216
sortie vidéocomposite NTSC/PALcomposite NTSC/PAL
sortie audiomonophonique, tonalités, et DAC PWMmonophonique, tonalités, bruit blanc, DAC PWM
contrôleursboutons sur carte
optionnel: 2 gamepads NES/SNES
optionnel: nunchuck
connecteurs pour 2 gamepads SNES
optionnel Nunchuck sur breakout I2C.
interfaces libre en breakout1 x I2C peut-être utilisé pour un Nunchuck1 x I2C peut-être utilisé pour un Nunchuck
1 x SPI peut-être utilisé pour carte SD

schématique

Le schéma électronique est simple et le montage sur carte à bandes peut-être réalisé en quelques heures. Dessiné sur KiCAD les fichiers sont disponibles sur le github. Voici un aperçu du schéma et du plan de montage sur carte à bandes VECTOR electronics modèle 8022. Il s'agit d'une carte de 3" x 3,5" (7,6cm x 8,9cm).

Le MCU fonctionne sous une tension de 3,3 volt et c'est le régulateur LDO µA78M33 qui abaisse le voltage d'entrée à ce niveau.

Le microcontrôleur fonctionne à sa vitesse maximale de 32Mhz. Le crystal est à 8Mhz mais cette fréquence est multipliée par 4 par le PLL interne du MCU. Les PIC24 ont un cycle système de la moitié de la fréquence de l'oscillateur donc ici on a 16Mhz ou 62,5nsec par cycle machine.

Le signal vidéo composite est constitué d'un signal de synchronisation dont la sortie est sur la broche 16 et d'un signal contenant la composante vidéo proprement dite sur la broche 14. Un cavalier sur la broche 23, connecteur P4, permet de sélectionner entre les formats NTSC et PAL. La présence du cavalier est détectée au démarrage il doit donc être installé avant la mise sous tension. Notez qu'en ce qui concerne le signal vidéo monochrome composite PAL et SECAM sont identiques. La sortie vidéo est sur connecteur RCA phono. En Europe il faudrait probablement utiliser un connecteur SCART.

En ce qui concerne les contrôleurs SNES les broches sont communes aux 2 contrôleurs sauf la broche data. Pour le contrôleur 1 l'entrée data est sur la broche 2 du MCU et pour le contrôleur 2 sur la broche 3 du MCU. Les connecteurs P5 et P6 font le pont entre les connecteurs SNES et la carte.

Il y a 2 broches de sortie pour l'audio. La broche 21 appelée NOISE sur le schéma est une sortie bruit blanc produite avec le générateur pseudo-hasard. La broche 17 permet soit de sortir des ondes carrées, soit d'utiliser un périphérique output compare comme convertisseur numérique/analogique par PWM. Les résistances R6 et R7 et les condensateurs C7 et C11 forme un filtre passe-bas qui coupe les fréquences au dessus de 7Khz. La sortie audio est faite sur un connecteur RCA phono.

Les résistances R3 et R5, le condensateur C4 et la bouton momentané SW2 forme le circuit de réinitialisation du microcontrôleur.

P1 est le connecteur pour brancher le programmeur du Pickit2 utilisé pour la programmation du MCU.

P2 est un connecteur breakout pour le périphérique SPI2 du MCU. Cette interface n'est pas utilisée dans cette version de PICvision. Elle pourrait servir pour interfacer une carte SD.

P3 est un connecteur breakout pour le périphérique I2C2 du MCU. Cette interface n'est pas utilisée dans cette version de PICvision mais pourrait servir pour brancher un contrôleur Nintendo Nunchuck.

Plan de montage

J'ai photographié la carte Vector electronics modèle 8022 et j'ai éditer la photo dans paint pour faire mon plan de montage. Le résultat est le suivant.


Légende:
  • Trait noir indique une coupure dans la bande.
  • trait gris pâle indique la position d'un composant ou d'un pont entre 2 bandes.
  • trait rouge indique les ponts joignant les segments de bande vdd (3,3volts).

Liste matériel

test TVout

J'ai créé un programme test pour l'unité TVout.c Il s'agit d'une anneau qui rebondi sur les bords de l'écran. Pour le développement j'utilise un petit moniteur LCD de 5 pouces qui accepte les signaux composite NTSC et PAL.

Dans le prochain article je vais détailler le montage sur la carte de prototypage.

PICvision, montage de la carte

$
0
0

J'ai complété le montage sur carte à bande Vector modèle 8022. La carte est de dimension 3,5" x 3" soit 8,9cm x 7,6cm. J'ai effectué le montage à partir du plan suivant mais avec quelques modifications en cours de route.

J'ai commencé par couper les bandes en me fiant au plan initial. La méthode la plus efficace que j'ai trouvé pour couper les bandes est d'utiliser une mèche (foret) 3/16" (4,8mm) que je fais tourner entre mes doigts.

J'ai indiqué un endroit où la coupure de la bande est entre 2 trous et non sur un trou. J'ai aussi indiqué où j'avais oublié de couper une bande.

Ensuite les connecteurs et les fils:

C'est un travail qui demande beaucoup d'attention car lorsqu'on tourne la carte il faut tenir compte que gauche et droite sont inversés.

Les gros connecteurs c'est à dire celui de l'alimentation et les phono RCA demande un travail spécial pour leur installation. Le connecteur d'alimentation viens avec 2 languettes d'environ 3mm de largeur et distante de 200mil. J'ai simplement percé entre 2 trous pour faire une fente de largeur suffisante pour les accommoder.

Pour les connecteurs phonos je n'ai pas essayé d'entrer les languettes dans les trous. j'ai plutôt soudé de fils de grosseur 24AWG que j'ai pu entré dans les trous.

J'ai ajouter 2 remarques sur cette photo. En bas à gauche j'avais un pont entre deux bandes qu'il a fallu que j'enlève après coup. J'avais aussi oublié d'installer le pont entre les broches 15 et 18 du MCU, indiqué en blanc sur la photo.

Le montage complété sans le MCU:

Il y a 3 condensateurs CMS soudés sous la carte.

Pour bien voir il faut cliquer sur les photos pour les agrandir. Les photos sont aussi dans le dépôt github dossier KiCAD.

Vérification avant d'installer le microcontrôleur

Il est quasiment inévitable de faire quelques erreurs au montage c'est pourquoi la première chose à faire avant d'installer le microtontrôleur est de brancher l'alimentation et de vérifier si vdd est bien sur les broches où il doit-être et de même pour vss. A la première mise sous tension la LED d'alimentation n'a pas allumée! Après vérification au voltmètre j'ai constaté que le 3,3 volt était présent à la sortie du régulateur mais sur l'anode de D1 j'avais zéro volt. J'ai vérifié le montage et constaté que j'avais mis un pont où il ne fallait pas, voir la 3ième photo à ce sujet en bas à gauche.

J'ai vérifié toutes les tensions sur les broches des connecteurs et du MCU. Sur le MCU ça n'allais pas sur la broche 7. Je devais mesurer 3,3volt à cause de R2 mais j'obtenais zéro. Vérification faite, il y avait un pont d'étain accidentel entre les broches 7 et 8. Le problème a été réglé rapidement avec le fer à souder.

Autre surprise 6 volt sur la broche 16 du MCU. C'est le voltage à l'entré du régulateur de tension! J'avais oublié de faire une coupure sur une bande tel qu'indiqué sur la deuxième photo en bas.

Après ces corrections tout avait l'air en ordre. J'ai donc installé le MCU et branché la carte sur le moniteur. Whoops! pas de vidéo! Vérification de la sortie vidéo à l'oscilloscope. le signal de synchronisation était présent mais pas le vidéo. J'ai donc vérifié sur la broche 14 du MCU, aucun vidéo. J'ai vérifié sur la broche 15 et le signal video delayétait présent mais pas sur la broche 18. J'avais oublié d'installer le pont entre les 2 broches. Correction faites tout est maintenant fonctionnel.

Voilà donc la console de jeux PICvision avec 1 seul contrôleur de branché. Il ne lui manque qu'un boitier.

Premier jeux

Le logiciel de base n'est pas complété mais je voulais me faire une idée de quoi ça aurait l'air j'ai donc écris un jeux de serpent (centipede). Une variante du jeux traditionnel. Il s'agit d'un jeux en mode texte les graphiques et sons sont encore très rudimentaires. Au bruit que fait le serpent en se déplaçant on pourrait penser que c'est un train à vapeur et que la souris est un morceau de charbon. Dans ma variante le serpent ne fais pas que grandir il raccourci. A chaque souris qu'il mange il gagne 20 calories et rallonge d'un segment. Mais comme tout être vivant il brûle aussi des calories. Lorsqu'il a brulé 20 calories il perd un segment et lorsqu'il arrive à zéro il meurt de faim. Le serpent peut aussi mourir s'il frappe un mur ou s'il se mort la queue. Les calories et la durée de vie du serpent sont inscris en haut de l'écran. Le but du jeux étant de survivre le plus longtemps possible.

Maintenant que la partie matérielle du projet est complétée, dans les prochains articles je vais aborder le logiciel.

PICvision, module TVout

$
0
0

Le module TVout est celui qui génère le signal vidéo composite. Contrairement au module TVout du projet HackVision il est entièrement écris en 'C'. Ceci est rendu possible grâce à l'utilisation judicieuse d'un périphérique SPI pour sérialiser les bits vidéo. De plus comme le périphérique SPI du PIC24FJ64GA002 a une mémoire tampon de 8 octets le temps passé dans l'interruption qui génère les pixels vidéo est d'autant raccourci. En effet une fois que les 8 derniers octets de la ligne vidéo sont dans la mémoire tampon SPI on peut sortir de l'interruption et laisser le périphérique faire le travail. Les concepteurs de HackVision auraient put utiliser le périphérique SPI du AtMega328 pour la même utilisation mais il ne l'on pas fait. Cependant la mémoire tampon SPI du AtMega328 n'est que de un octet. Néanmoins en utilisant le SPI comme je l'ai fait ils auraient pu écrire leur TVout entièrement 'C' et réduire le nombre de cycles machine utilisés pour le vidéo.

Comme le code source est disponible sur le dépôt Github je ne vais reproduire ici que la partie du code étudié, soit les 2 interruptions. La première est celle qui contrôle le signal de synchronisation. La deuxième est celle qui envoie le contenu de video_buffer au périphérique SPI. Il est important que ces 2 interruptions soient le plus brèves possible étant données qu'elles se répètent plus de 15,000 fois par secondes, moins on y passe de temps plus il en reste pour le programme principal où est exécuté la logique du jeux.

Interruption _VSYNC_ISR

_VSYNC_ISR est la routine de service d'interruption qui contrôle le signal de synchronisation vidéo. Dans ce but un périphérique Output compare est utilisé en mode PWM. Il s'agit simplement de générer un signal à 15735 hertz pour le NTSC et 15625 hertz pour le PAL. Ce signal est de niveau 1 sauf pour l'impulsion de synchronisation horizontale qui elle est à zéro. Le signal sur la broche 16 du MCU a donc la forme suivante:

Cependant au début de chaque cadre (frame) le signal est inversé sur les 3 premières lignes vidéo pour assuré la synchronisation verticale:
la variable frame_line_cntr sert a compter les lignes et à partir du numéro de ligne on décide quand il faut activer et désactiver l'interruption qui envoie les pixels vidéo et quand il faut générer la synchronisation verticale. En mode progressif il y a 262 ligne en NTSC et 312 en PAL par cadre. Il faut donc faire des case différent pour le NTSC et le PAL.

Interruption _VIDEO_OUT_ISR

Cette routine de service d'interruption est celle qui prend le contenu du video_buffer et via le périphérique SPI sérialise les octets vers la sortie sur la broche 14 du MCU. Il s'agit d'une interruption de type Change Notification, c'est à dire qui est déclenchée chaque fois que le niveau change sur la broche 18. Entre la fin de l'impulsion de synchronisation horizontale et le début de l'envoie des pixels vidéo il y a un délais. On pourrait attendre à l'intérieur de l'interruption _VSYNC_ISR que ce délais soit écoulé et envoyer les pixels à partir de cette interruption. Ce serait du gaspillage de cycles machine. On utilise donc un deuxième périphérique Output compare qui lui aussi génère un signal semblable au premier sauf que l'impulsion de synchronisation est plus large. Elle débute 1µsec avant l'impulsion horizontal sync mais est 2 fois plus longue.

Cette impulsion est envoyée sur l'entrée digitale broche 18 du MCU et chaque fois qu'il y a un changement d'état l'interruption _VIDEO_OUT_ISR est déclenchée. Mais la transition qui nous intéresse est la montante. C'est pourquoi au début de _VIDEO_OUT_ISR on vérifie si la broche 18 est à 1

if (PIXDLY_INP){
Si c'est le cas on commence à envoyer les pixels du video_buffer en tenant compte du frame_line_cntr. Chaque ligne du video_buffer correspond à 1 ligne horizontale à l'écran.

Ces routines sont simples, en fait le plus gros du code de ce module est dans la définition des constantes et l'initialisation des périphériques.

Interface application

L'interface application (API) de ce module ne contient que 3 fonctions.


void video_init();
void wait_n_frame(unsigned n);
void blank_out();
La première fonction se passe de commentaire. wait_n_frame() est utilisée pour faire une pause dans le programme. Cette pause est en multiple de cadre. En mode NTSC un cadre dure 16,67msec. et en PAL 20msec.

blank_out() accepte 2 valeurs VIDEO_OFF et VIDEO_ON et sert exactement à ça. Cette fonction active et désactive la sortie des pixels vidéo mais sans désactiver le signal de synchronisation. On peut l'utiliser pour faire clignoter le contenu de l'écran au complet. exemple.


// clignotement de l'écran 5 fois par seconde
int delay;
if (video_mode==NTSC_MODE) delay=6;else delay=5;
while(1){
blank_out(VIDEO_OFF);
wait_n_frame(delay);
blank_out(VIDEO_ON);
wait_n_frame(delay);
}

PICvision, module snes-paddle

$
0
0

Les contrôleurs SNES sont intéressant pour 2 raisons, ils sont économiques et facile à trouver et deuxièmement ils sont simple à interfacer.

Le connecteur SNES a 7 broches mais n'en utilise que 5.

  1. Vdd, positif de l'alimention, fonctionne aussi bien à 5volt qu'à 3,3volt
  2. clock, sert à lire le contrôleur, bit par bit.
  3. latch, lit l'état des boutons et met le résultat dans le registre à décalage
  4. data, sortie des bits de lecture.
  5. pas de connection
  6. pas de connection
  7. gnd, 0 volt de l'alimentation.
La broche 1 est à l'extrémitée plate du connecteur.

schématiquement l'électronique du contrôleur ressemble à ceci:

Le contrôleur a 12 boutons et pour faire la lecture de ces boutons on procède comme suit.

  1. Envoie d'une impulsion sur la ligne LATCH
  2. Lecture du premier bit (bouton B) sur la ligne DATA
  3. Répéter 15 fois
    1. Envoie d'une impulsion sur la ligne CLOCK
    2. Lecture du bit sur la ligne DATA
Les lignes CLOCK et LATCH sont des sorties digitales sur le MCU et sont gardée à zéro volt. L'impulsion LATCH mets cette ligne à Vdd pour 250nsec. Cette impulsion a pour effet de lire l'état des boutons dans le registre à décalage. On obtient un instantané de l'état des boutons dans le registre après cette impulsion. Un bouton enfoncé correspond à 1 bit à zéro. Le bit du bouton B est disponible dès le latch. Il y a 12 boutons met le registre a 16 bits. Les 4 derniers bits sont toujours à 1. Après avoir lu le bit du bouton B on envoie 15 impulsions sur la ligne CLOCK pour lire les 15 bits restants. les bits sont décalés vers la sortie à la transition montante de l'impulsion clock.

snes-paddle.c

C'est très simple comme code. Il n'y a qu'une fonction dans l'interface application:


unsigned read_paddle(int paddleId)
paddleId identifie le contrôleur dont on veut faire la lecture PADDLE1 ou PADDLE2. read_paddle() utilise les fonctions latch() qui envoie l'impulsion sur la ligne LATCH et la fonction bit_shift() qui envoie l'impulsion sur la ligne CLOCK pour décaler vers la sortie DATA le bit suivant.

Les 2 contrôleurs sont lus en même temps puisque les lignes CLOCK et LATCH sont communes aux 2 contrôleurs. La ligne DATA du PADDLE1 est lue sur l'entrée digitale RA0 et la ligne PADDLE2 est lue sur l'entrée digitale RA1. Les variables p1 et p2 contiennent le résultat de la lecture respectivement pour chacun des contrôleurs. La valeur de l'argument paddleId détermine laquelle de p1 ou p2 la fonction retourne. Le masque 0xfff est appliqué pour ne retourner que les 12 premiers bits. La valeur des bits est inversée de sorte qu'un bouton enfoncé a son bit à 1. Les constantes pour sélectionner les différents bits dans l'entier sont définis dans le fichier snes-paddle.h. En fait j'ai emprunté ces définitions au projet hackvision.

Pour plus d'information sur les contrôleurs NES et SNES vous pouvez lire le document NES-controller-Hydra-Ch6All-v1.0.pdf en anglais qui se trouve dans le répertoire docs du dépôt github.

PICvision, module HardwareProfile

$
0
0

Le profil matériel (hardware profile) est utilisé pour 2 raisons. La première est pour faciliter les modifications logicielles en cas de changement du schéma électronique et la deuxième pour rendre le projet plus facile à adapter à une autre plateforme.

Entre le premier schéma que j'ai dessiné et la version finale il y a eu des modifications au niveau de l'affectation des périphériques au broches du MCU. Par exemple au départ les lignes DATA1 et DATA2 des contrôleurs SNES étaient sur RB14 et RB15 et par la suite ont été transférés sur RA0, RA1. En créant les définitions suivantes dans le fichier HardwareProfile.h


// SNES paddles i/o
#define PADDLES_DATA_PORT PORTA
#define P_PDL1_DAT LATAbits.LATA0 // paddle 1 data input
#define P_PDL1_DAT_TRIS TRISAbits.TRISA0 // paddle 1 TRIS bit
#define P_PDL1_ANDIS AD1PCFGbits.PCFG0 // disable ANx disable bit
#define P_PDL2_DAT LATAbits.LATA1 // paddle 2 data input
#define P_PDL2_ANDIS AD1PCFGbits.PCFG1 // paddle 2 ANx disable bit
#define P_PDL2_DAT_TRIS TRISAbits.TRISA1 // paddle 2 TRIS bit
#define P_PDL_CLK LATBbits.LATB0 // paddles clock output signal
#define P_PDL_CLK_TRIS TRISBbits.TRISB0 // paddles clock TRIS bit
#define P_PDL_LATCH LATBbits.LATB1 // paddles data latch output signal
#define P_PDL_LATCH_TRIS TRISBbits.TRISB1 // paddles latch TRIS bit
Je n'ai eu qu'à modifier ces définitions sans chercher ailleurs pour que la modification s'applique partout dans le projet. Ce concept de profil matériel s'avère utile dans tous les projets le moindrement complexes. De plus on peut choisir des noms plus significatifs dans le cadre du projet.

La raison pour laquelle j'ai modifié le schéma électronique initial est justement pour faciliter l'adaptation du projet à un autre microcontrôleur. Actuellement je pourrais enlever le PIC24FJ64GA002 de la carte et le remplacer par un PIC32MX150F128B sans avoir à modifier quoi que ce soit au montage électronique. Tout ce que j'aurais à faire est de modifier le hardwareProfile et faire quelques adaptation au niveau du code. Bref avec seulement quelques heures de programmation j'aurais un PICvision fonctionnant avec un MCU 32 bits avec 32Ko de RAM plutôt qu'un MCU 16 bits avec 8Ko de RAM.

Le principe du profile matériel est simple on substitue des symboles par d'autres:


#define PADDLES_DATA_PORT PORTA
Ainsi chaque fois que dans le code je veux lire les lignes DATA des contrôleurs SNES j'utilise le symbole PADDLES_DATA_PORT au lieu de PORTA et si mon montage est modifié et que c'est sur PORTB plutôt que PORTA je n'ai qu'à changer la définition:

#define PADDLES_DATA_PORT PORTB
Tout ce qui est spécifique à la configuration matériel est centralisé dans HardwareProfile.h et HardwareProfile.c sauf les bits de configurations du MCU, qui eux doivent-être dans le fichier qui contient la fonction main(). Il semble que le pré-processeur s'attend à trouver ces directives dans le fichier principal.

conclusion

La modularisation d'un projet facilite sa gestion, les modifications et l'adaptation à d'autres plateformes. Centraliser les informations spécifique à la plateforme matérielle dans un seul fichier ou groupe de fichiers est un aspect important de la modularisation.

PICvision, nouveau démo

$
0
0

Je continue à travailler sur PICvision. Dernièrement j'ai créé un splash screen, un système de menus et j'ai refais le jeux serpent en mode graphique plutôt que caractère voici un vidéo du jeux en action.

Actuellement la mémoire flash n'est utilisé qu'à 24% mais la mémoire RAM à 87%. Il y a donc de la place pour ajouter de nouveaux jeux. J'ai peur cependant de manquer de mémoire RAM avant d'avoir tout utilisé la mémoire programme.

lien github

introduction au LPC810 (ARM M0+)

$
0
0

Je prends une pause du projet PICvision pour présenter le seul microcontrôleur 32 bits disponible en format PDIP-8. Le MCU LPC810 fabriqué par NXP est en effet basé sur le core ARM M0+. Pour l'avoir en format PDIP-8 il faut commander le modèle LPC810M021FN8. NXP est le seul manufacturier à offrir des MCU ARM en format PDIP et il n'y a que 2 modèles disponibles, l'autre étant le LPC1114FN28 disponible en format PDIP-28 large (600mil.).

Caractéristiques du LPC810

paramètrevaleur
coeurARM Cortex M0+
architectureVon Neumann
Freq. CPU30Mhz max.
mémoire flash4Ko
mémoire RAM1Ko
USART2
I2C1
SPI1
comparateur1
multirate timer4 canaux
systick counteroui, 24 bits
GPIO6
multiplicationhardware 32 bits, 1 cycle
boot loader en ROMoui
alimentation1,8 à 3,6 volt

Environnement de développement

NXP mais à notre disposition une version gratuite de LPCXpresso. Cet IDE est basé sur Eclipse et est disponible pour Linux, Windows et OSX. Il faut cependant créer un compte utilisateur sur le site lpcware.com pour obtenir la clé d'enregistrement.

Une fois le logiciel installé l'enregistrement se fait à partir de l'IDE dans le menu HELP - Activate - Create serial number and register...

Une fois le numéro de série créé et la clé d'activation obtenue, il faut alors aller dans HELP - Activate - Enter activation code...

La version gratuite permet de créer des programmes jusqu'à 256Ko. Il y a deux autres logiciels à télécharger. Le premier est flash magic disponible gratuitement pour windows et OSX. Flash magic permet de programmer le MCU en se servant du boot loader en ROM qui est inclus dans le MCU lors de sa fabrication. A moins que vous n'ayez un programmeur compatible supportant SWD ou JTAG vous ne pourrez pas programmer le LPC810 à partir de l'IDE. Par défaut le compilateur génère un fichier .AXF qui n'est pas supporté par flash magic. Il faut donc pour chaque projet spécifié qu'on veut un fichier .HEX.

Pour générer un fichier HEX il faut dans l'explorateur de projet, cliquer avec le bouton droit sur le nom du projet et dans le menu choisir propeties. dans C/C++ setting onglet build steps, post-build steps command:cliquez sur le bouton edit....

dans l'éditeur ajoutez la ligne suivante:

arm-none-eabi-objcopy -O ihex "${BuildArtifactFileName}"
"${BuildArtifactFileBaseName}.hex"
Une fois cette configuration accomplie, lors de la compilation du projet un fichier .HEX sera généré.

Premier projet

Pour ce premier projet on va en importer un de Github et le modifier. Allez à https://github.com/microbuilder/LPC810_CodeBase et à droite de la page cliquez sur le dernier bouton nommé Download ZIP. Une fois téléchargé il faut maintenant l'importer dans l'explorateur de projet de LPCXpresso.

En dessous de l'explorateur de projet il y a une autre fenêtre avec plusieurs onglets. Dans Quick start panel cliquez sur import project(s). Dans le fenêtre d'importation cliquez le premier bouton browse... et allez chercher le fichier .ZIP que vous venez de télécharger. Cliquez maintenant sur le bouton Finish. Une fois le projet importé il devrait apparaitre dans l'explorateur de projet sous le nom LPC810_CodeBase.

Déployez l'arborescence de ce projet et le dossier srcà l'intérieur de celui-ci. Ouvrez le fichier main.c dans l'éditeur en double-cliquant dessus.

J'ai modifié le projet pour remplacer la LED simple par une une LED RGB dont les anodes sont connectées comme suis:

  • PIO0_1 (broche 5) ANODE ROUGE
  • PIO0_2 (broche 4) ANODE BLEU
  • PIO0_3 (broche 3) ANODE VERTE
  • V-   CATHODE COMMUNE
vue montage dans Boardview:
photo du montage:
On y aperçois la petite alimentation Sparkfun 3,3/5 Volt, ainsi que adaptateur de niveaux de tension RS-232 vers TTL.

Voici le fichier main.c tel que je l'ai modifié.

Ce projet est déjà configuré pour générer un fichier .HEX il ne reste donc qu'à le compiler. Dans la barre d'outils il y a un marteau avec une petite flèche à droite qui pointe vers le bas. Cliquez sur la flèche et ensuite sur Release (Release build).

S'il n'y a pas d'erreur de compilation il devrait y avoir un fichier LPC810_CodeBase.hex dans le dossier release du projet. Dernière étape flasher ce fichier dans le LPC810.

Flash magic

Vous avez installé flash magic maintenant ouvrez le. Mais d'abord pour faire entrer le MCU en mode boot loader il faut l'éteindre et ensuite mettre PIO0_1 (broche 5) à zéro volt (voir photo, j'utilise le cavalier bleu à cet effet). On réalimente le MCU. Maintenant dans flash magic, il faut sélectionner le port sériel sur lequel est branché le MCU, indiquez la vitesse de transmission et mettre le clock à 12Mhz. Comme illustré ci-bas (le no de port ne sera pas nécessairement le même sur votre ordinateur.
Pour la programmation le LPC810 reçoit sur la broche 8 et transmet sur la broche 2.

Utilisez le bouton browse pour aller chercher le fichier LPC810_CodeBase.hex dans votre dossier de travail LPCXpresso. Lorque c'est fait on clique sur le bouton start. Si tout va bien le message Finished va apparaître après quelques secondes dans la barre d'état. On éteint l'alimentation du MCU, on enlève le cavalier sur la broche 5 de Vss et on réallume. La LED RGB allume ses 3 couleurs en alternance à intervale de 0,5 seconde.

Documents à télécharger

LPC8xM datasheet
LPC81x user manual


LPC810, partie 2

$
0
0

Dans cet article j'explique le diagramme bloc des microcontrôleurs LPC81x. Mais d'abord un mot au sujet de la compagnie ARM

ARM est une compagnie d’ingénierie et ne fabrique pas de circuit intégrés. Ils conçoivent des CPU et vendent des licences au fabricants de microprocesseurs. Il y a 3 familles de produits ARM: Cortex-A, Cortex-R et Cortex-M. Le A de Cortex-A signifie application. Cette famille de processeur est celle qu'on retrouve dans les téléphones, les tablettes et les laptops. Ce sont des CPU d'usage général. le R dans Cortex-R signifie Real time. Ces CPU sont utilisés dans les microprocesseurs pour les applications temps réel. Finalement la famille qui nous intéresse ici Cortex-M, M pour microcontrôleur. Inutile de dire où on les retrouve. Il y a 5 groupes de Cortex-M, M0, M0+, M1, M3 et M4. Les M0 sont les plus économiques et les M4 les plus performants. Les M0, M0+, M1 et M3 on une architecture Von Neumann mais les M3 et M4 ont une architecture Harvard. Les M4 possèdent en plus des fonctionnalités pour le traitement numérique de signale (DSP).

Donc comme je le disais ARM vends des licences et de nombreux fabricants de circuit intégrés en possèdent. Dans le domaine des microcontrôleurs il y a de nombreuses compagnies en possession de licences Cortext-M, Texas Instruments, Atmel, NPX, FreeScale pour n'en nommer que quelques unes.

Anatomie d'un LPC81xM

Il y a 3 MCU dans ce groupe LPC810, LPC811 et LPC812. Ils partagent le même datasheet et le diagramme bloc suivant est extrait de ce document.

Le bloc marqué en gras ARM Cortex-M0+ correspond au CPU licencié par la compagnie ARM. Tout le reste est conçu par les ingénieurs de NXP. Cette licence viens avec une option hardware multiplier. Comme lorsqu'on achète une automobile il faut payer un extra pour les options. NXP a donc acheté cette option puisque les LPC81xM possèdent ce composant.

Les bus

  • private bus Il n'est pas identifié sur ce diagramme mais ce bus est interne au bloc CPU et relie le core au contrôleur d'interruption NVIC aussi interne au coeur et aux modules optionnels vendus avec le coeur Cortex-M+.
  • fast GPIO et pin interrupts/pattern match, ces 2 modules ne font pas partie du coeur mais y sont reliés directement par un bus dédié.
  • AHBAdvanced High performance bus est le bus primaire qui relie les blocs mémoire, le module CRC et le module SCT au coeur.
  • APBAdvanced Peripherals bus est relié au bus AHB et relie les périphériques moins prioritaires en terme de délais d'accès.

Les périphériques

  • USARTxUniversal Synchronous Asynchronous Receiver Transmitter, Le diagramme en montre 3 mais le LPC810 ne possède que le USART0. Ce module sert pour les communication RS-232 et RS-422. Peut communiquer sur de longue distance.
  • SPIxSerial Peripheral interface bus, le diagramme en montre 2 mais le LPC810 ne possède que le SPI0. Utilisé en autre pour accès au carte mémoire et autre mémoire en circuit intégré mais aussi pour des affichages LCD. Communication courte distance (boitier).
  • I2CInter Integrated Circuit bus, communication sérielle entre circuit intégrés sur une même carte ou carte voisines. Sert aussi pour les sondes de température ou autre. Communication courte distance (boitier).
  • XTAL est le module oscillateur pour l'utilisation d'un crystal. N'est pas disponible sur le LPC810.
  • SYSCON est le module de configuration du MCU, configuration de la source de l'oscillateur système, du PLL, et autres paramètres de fonctionnement du MCU.
  • Comparator, c'est le module compartateur analogique.
  • IRC C'est l'oscillateur interne de 12Mhz. C'est cet oscillateur qui est sélectionné par défaut comme horloge système.
  • WDOsc C'est l'oscillateur du Watch dog timer, ça fréquence est programmable entre 9,4Khz et 2,3Mhz.
  • BODBrown Out Detector, ce circuit détecte les chutes de tension et génère une interruption si l'alimentation descend sous un certain niveau.
  • PORPower On Reset, ce circuit maintient le CPU en RESET lors de la mise sous tension le temps qui cette dernière est atteint un niveau suffisant.
  • Clock generation, Power Control, system functions, ce bloc contient les circuit qui contrôlent les signaux d'horloges, la gestion de l'alimentation et d'autres fonctions système.
  • always on power domain, comme les MPC81xM possèdent un gestionnaire de consommation qui permet de réduire la consommation électrique à différent niveaux. En mode deep power-down le seul bloc qui reste alimenté est celui-ci. Ce bloc contient le PMUPower Management Unit qui gère les différent niveaux, sleep, deep-sleep, power-down et deep power-down. Le Self Wake-up Timer est une minuterie qui sort le MCU du mode deep power down après un interval de temps pré-programmé.
  • Multi-rate timer est une minuterie qui peut déclencher des interruptions régulières. Cette minuterie possède 4 canaux. C'est à dire que 4 interruptions régulières peuvent-être programmées avec une fréquence différente.
  • IOCON, contrôle des Entrées/Sortie numérique. Configure les broches pour différent modes de fonctionnement: Direction, pullup/pulldown, Open-colletor, glich filter, analog mode.
  • WWDTWindowed Watchdog Timer, minuterie chien de garde avec intervalle fenêtrée.
  • CRCCyclic Redondancy Check, ce module sert à vérifier l'intégrité d'un bloc de donnée reçu ou transmis en émettant une somme de contrôle.
  • SCTState Configuration Timer, Minuterie utilisée pour la génération de signaux PWM ou comme compteur d'événements externe ou simplement comme compteur d'intervalle.
  • Pins interrupts/pattern match, configuration des interruptions sur changement d'état des broches ou interruption sur expression booléenne.
  • High speed GPIO, le branchement direct des broches en mode numérique au coeur permet l'écriture ou la lecture en 1 seul Tcy.
  • TEST/DEBUG INTERFACE il s'agit d'une interface JTAG pour les test d'usine boundary check et SWDSingle Wire Debug pour la programmation et le débogage du MCU.
  • FLASH mémoire programme permanente de 4Ko sur le LPC810.
  • RAM mémoire de données de 1Ko sur le LPC810.
  • ROM mémoire permanente en lecture seule de 8Ko contenant le boot loader avec ISP ainsi que des interfaces I2C, USART, IAP et des profiles d'alimentation.
  • switch matrix, permet d'établir les connections entre les périphériques et les broches. Si certains périphériques ne peuvent être connectés qu'à une broche prédéfinie par contre d'autres peuvent l'être à n'importe quel GPIO libre. Par exemple le RESET ne peut-être relié qu'à la broche PIO0_5 (broche 1 sur le LPC810). les signaux USART0_RX, USART0_TX peuvent l'être à n'importe quel GPIO libre, par exemple si le RESET est désactivé USART_TX0 peut-être assigné à GPIO0_5. Ces assignations se font par les registres PINASSIGNx (il y en a 9).

LPC810, partie 3, création d'un projet

$
0
0

Dans la première partie nous avons compiler un projet téléchargé de github après l'avoir modifié légèrement. Dans cette partie je montre comment créer un nouveau projet. Actuellement la fenêtre project explorer devrait contenir les projets contenu dans LPCXpresso Sample Code Bundle for the LPC8xx. Si ce n'est pas le cas il faut télécharger et importer (comme expliquer dans la partie 1) le fichier zip dans project explorer. Au final la fenêtre devrait ressemblée à ceci:

Pour créer un nouveau projet on peut passé par File - new - project ou cliquez sur new project dans la fenêtre Quickstart panel.

Étape 1, type de projet:

Étape 2, nom du projet: on va l'appellé rgb_blinky
Étape 3, sélection du microcontrôleur: LPC810
Étape 4, sélection de la librairie: on laisse ça tel quel et on clique sur next
Étape 5, sélection de la librairie DSP: on en utilise aucune, on laisse à none et on clique next
Étape 6, débogage: on n'a pas de débogueur donc on décoche enable definition of buffer array for MTB et on met le champ number of byte to reserve for the MTBà zéro. next
Étape 7, other options: on peut décoché enable CRP in target image et faire finish

Maintenant notre projet rgb_blinky apparaît dans project explorer. On le sélectionne et en cliquant sur son nom avec le bouton droit de la souris on choisi properties tout en bas du menu surgissant. Dans c/c++ build on sélectionne l'onglet build steps on modifie le champ command du groupe post-build steps en ajoutant au texte existant la ligne suivante:


arm-none-eabi-objcopy -v -O ihex "${BuildArtifactFileName}"
"${BuildArtifactFileBaseName}.hex"
Car on veut obtenir un fichier rgb_blinky.hex pour utilisation dans flash magic.

Personnellement j'aime bien avoir un listing assembleur, donc avant de fermer les propriétés on va aller dans c/c++ build - Setting onglet Tool settings, dossier miscellaneous et on va ajouter à la fin du champ other flags


-Wa,-a,-ad="$*.lst"

On peut maintenant travailler sur le code source. Dans le dossier src de notre projet on double clique sur main.c pour l'ouvrir dans l'éditeur. On a déjà un squelette de l'application voici mon code finalisé.

Le compilateur me donne encore une erreur:


../src/main.c:18:30: fatal error: lpc8xx_clkconfig.h:
No such file or directory
#include "lpc8xx_clkconfig.h"
J'ai oublié quelque chose dans la configuration:

lpc800_driver_lib n'était pas coché dans Project reference. Deuxième tentative même erreur. Il manque encore quelque chose dans la configuration des propriétés. S'il ne trouve pas le fichier d'entête c'est qu'il ne connait pas le chemin on va donc ajouter ce chemin dans C/C++ general - Path and symbols onglet includes. On sélectionne GNU C et on clique le bouton add...
Cette librairie dans est dans le dossier workspace donc on coche is a workspace path et on donne le chemin relatif. Dans la même fenêtre dans l'onglet library paths on clique sur add...
Et finalement dans l'onglet libraries on ajoute lpc800_driver_lib
Compilation! Cette fois ça marche. Ne reste plus qu'à flasher rgb_blinky.hex tel qu'expliqué en partie 1.

LPC810, partie 4, programmation

$
0
0

Les 3 premiers articles présentaient l'environnement et le LPC810. Dans cette partie je vais discuter de la programmation en analysant l'exemple de la partie 3.

Après avoir créer le projet rgb_blinky dans la partie 3 on avait 4 fichiers dans le dossier src

  • cr_startup_lpc8xx.c, ce fichier contient le code d'initialisation du MCU et est généré automatiquement. Normalement il n'est pas nécessaire de modifier son contenu.
  • crp.c, Si on a sélectionné l'option "Enable Code Read Protect" dans les options du projets ce fichier contient le code de protection. Normalement on ne touche pas à ce fichier.
  • mtb.c, correspond à la fenêtre d'options Micro Trace Buffer lors de la création du projet. On n'a pas à toucher à ce fichier.
  • main.c, c'est le fichier principal de notre application, celui sur lequel on travaille.

Le squelette de l'application

Si on ouvre main.c dans l'éditeur on voit qu'il y a 2 fichiers d'entête inclus dans le squelette de l'application.

LPC8xx.h contient toutes les définitions nécessaire pour accéder les modules internes du MCU. On va y revenir.

cr_section_macros.h ne contient que des macros qui définissent les sections de mémoire. Ces informations sont utilisées par le compilateur et le linker mais normalement on n'a pas besoin de s'en préoccuper.

On pourrait écrire notre application sans inclure d'autres entête mais ça augmenterais notre charge de travail. C'est pourquoi on a inclus dans notre projet les librairies CMSIS_CORE_LPC8xx et lpc8xx_driver_lib.

CMSIS_CORE_LPC8xx contient le code d'initialisation du MCU ainsi que les fonctions de base qu'on retrouve dans toute application 'C' tel que stdio.h, stdlib.h, string.h, math.h, etc. On inclus donc dans notre projet les entêtes dont on a besoins pour référencer les fonctions de ces modules.

lpc8xx_driver_lib contient les pilotes de périphériques disponibles dans le microcontrôleur. Il faut inclure le(s) fichier(s) d'entête pour les périphériques qu'on utilise dans notre application.

Dans le projet rgb_blinky j'ai inclus les 2 fichiers d'entête suivant:


#include "lpc8xx_gpio.h" // utilisation des entrées/sorties sans périphérique
#include "lpc8xx_mrt.h" // utilisation du multi-rate timer

Si on se réfère à la partie 2 de cette série, où j'explique les modules interne du LPC810 et qu'on regarde le contenu du fichier d'entête LPC8xx.h on constate que pour chaque bloc du schéma on a une structure définie comme typedef. par exemple:

typedef struct
{
union {
__IO uint32_t PINASSIGN[9];
struct {
__IO uint32_t PINASSIGN0;
__IO uint32_t PINASSIGN1;
__IO uint32_t PINASSIGN2;
__IO uint32_t PINASSIGN3;
__IO uint32_t PINASSIGN4;
__IO uint32_t PINASSIGN5;
__IO uint32_t PINASSIGN6;
__IO uint32_t PINASSIGN7;
__IO uint32_t PINASSIGN8;
};
};
__I uint32_t RESERVED0[103];
__IO uint32_t PINENABLE0;
} LPC_SWM_TypeDef;

et plus bas on retrouve une variable de type pointer dont le nom est LPC_SWM. Chaque périphérique utilise un certains nombre de registres SFR et les éléments de la structure correspondent à ces registres. Donc dans le programme on retrouve:


LPC_SWM->PINENABLE0 = PINENABLE0_RESRVD|DIS_ACMP_I1|DIS_ACMP_I2|
DIS_SWCLK|DIS_SWDIO|DIS_XTALIN|DIS_XTALOUT|
DIS_CLKIN|DIS_VDDCMP;
Le registre PINENABLE0 permet d'activer/désactiver certaines fonctions pour libérer les GPIO. Par défaut SWCLK et SWDIO accaparent les broches 3 et 4, donc si on veut utiliser ces broches pour alimenter la LED RGB on doit désactiver ces 2 fonctions.

La fonction delayMs() qui est définie dans lpc8xx_mrt.c utilise le périphérique Multi-rate Timer on doit donc l'activer et le réinitialiser:


LPC_SYSCON->SYSAHBCLKCTRL |= ENABLE_MRT;
LPC_SYSCON->PRESETCTRL |= MRT_RESET;
Les fonctions GPIOinit(), GPIOSetDir() et GPIOSetBitValue() sont définies dans lpc8xx_gpio.c

  • GPIOinit(), initialise les GPIO.
  • GPIOSetDir(), configure une broche entrée ou sortie. Le premier argument est le no de port. Le deuxième est le no de bit et le troisième est 0 pour entrée et 1 pour sortie.
  • GPIOSetBitValue(), fixe la valeur d'un broche en sortie. Le premier argument est le no de port. Le deuxième est le no de bit et le troisième est la valeur de sortie.

Dans la boucle while(1) on contrôle la valeur des sorties en affectant les bits directement dans le registre NOT0 ce registre inverse les bits de sortie dont la valeur est mis à 1 dans le registre. C'est une registre toggle. Il y a aussi un registre SET0 pour mettre les sorties à 1 et un registre CLR0 pour mettre les sorties à 0. Ces registres permettent de modifier simultanément plusieurs sorties.

Conclusion

Dans ce programme exemple on voit donc 2 façons d'utiliser les périphériques. Soit on utilise des fonctions de la librairie lpc800_driver_lib soit on accède directement les SFR à partir des structures définies dans LPC8xx.hIl faut noter que la librairie lpc800_driver_lib est fournie à titre d'exemple et qu'en conséquence est n'est pas très bien documentée et incomplète. Cependant la licence en début de fichier mentionne qu'on a le droit de modifier le code source de cette librairie à condition d'y laisser l'information de licence et de ne l'utiliser que pour des MCU NXP. Il faut considérer cette librairie comme un point de départ qui reste à développer.

LPC810, partie 5, module SCT et PWM

$
0
0

Générer un signal PWM sur un AVR ou un PIC est simple mais pour arriver à le faire sur un LPC810 j'ai du lire et relire avec beaucoup d'attention le chapitre 10 du LPC81x user manual concernant le module SCT (State Configurable Timer). C'est le plus long chapitre du manuel. Ce périphérique utilise 116 registres de configuration. Générer un signal PWM est l'utilisation la plus simple qu'on peut faire de ce périphérique. Si ce périphérique est si complexe c'est qu'en fait il s'agit d'un automate programmable. Notez que les LPC8xx sont limités à 2 états et 6 événements. Dans l'utilisation que j'en fais dans les 2 démos qui suivent il n'y a pas de transition d'état, le SCT demeure dans l'état 0. Néanmoins si vous jetez un coup d’œil à la procédure PWM_init()du premier démo, 30 assignations à divers registres du module SCT sont nécessaires pour générer 3 signaux PWM.

LED RGB contrôlée par PWM 16 bits

Pour ce démo j'ai conservé le montage de la LED RGB tel quel mais chaque anode est contrôlée en intensité par un signal PWM à une fréquence de 183 Hertz. La résolution PWM est de 16 bits par canal. A chaque seconde la fonction rand() est utilisée pour générer 3 nouvelles valeurs pour le rapport cyclique de chaque canal. Il en résulte donc que la LED change de couleur 1 fois par seconde de façon aléatoire.

Comparez la simplicité de la fonction delay_ms() avec la complexité de PWM_init(). Le module MRT (Multi-Rate Timer) est un des plus simple à utiliser.

2ième démo

Dans ce démo j'utilise le module SCT d'un autre autre façon. En utilisant 4 événements le module SCT peut séquencer les 3 couleurs primaires de la LED sans intervention logicielle. Une fois le module SCT paramétré et démarré, le MCU tourne dans une boucle while vide et il n'y a pas non plus de routine d'interruption qui intervient.

Conclusion

Les fabricants de MCU ajoute des modules de plus en plus complexes à leur produit. Ceux-ci demandent plus d'effort d'apprentissage mais une fois maîtrisés ils permettent de libéré l'unité centrale au profit d'autres tâches.

Un Boitier pour PICvision

$
0
0

Quand viens le temps de trouver un boitier pour mes projets j'essaie le plus souvent de faire de la récupération plutôt que d'acheter un boitier préfabriqué. Pour mon projet PICvision j'ai décidé de tenter l'expérience d'en fabriquer un avec du carton ondulé.

Les dimensions extérieures sont de 6-1/4" (159mm) en largeur, 3" (76mm)en hauteur et 4-1/4" (108mm) en profondeur. J'ai découper les panneaux pour chaque face en les doublant en épaisseur et j'ai assemblé le tout avec de la colle chaude. j'ai trouvé à la quincaillerie une équerre en plastique de 1/2" (12,7mm) que j'ai découpé en sections pour protéger les angles de la boite. Les faces extérieures sont recouvertes de papier glacé destiné à l'impression photographique.

Ceci est une solution temporaire, je planifie d'en fabriquer un en bois d'érable ou de chêne rouge.

Il me reste encore du développement logiciel à faire sur ce projet.

Comment fonctionne un décodeur d'instruction

$
0
0

Dans un article précédent j'ai expliqué comment fonctionne l'unitée arithmétique et logique d'un microcontrôleur. Dans cette article j'explique comment fonctionne le décodeur d'instruction. On va prendre pour exemple le coeur PIC baseline.

Voici le cycle d'instruction d'un coeur baseline.

Il faut 4 cycles d'oscillateur pour exécuter une instruction. Ces cycles sont appelés Q1,Q2,Q3,Q4 sur le diagramme ci-haut. Il s'agit d'un automate fini(state machine) qui fait évoluer l'exécution d'une étape à l'autre. Ce qui se passe dans un état Qx donné dépend en partie de l'instruction qui est exécutée mais certaines étapes sont communes à toutes les instructions. Sans connaître l'implémentation réelle du MCU on va essayer de comprendre son fonctionnement. On réalise qu'au démarrage le fetch register ou pileline est vide, il faut donc que le premier cycle d'instruction exécute un NOP. cette instruction a le code 0, donc lors d'une réinitialisation le fetch register doit-être mis à zéro. Au démarrage le compteur ordinal contient la valeur de la dernière adresse flash. Celle-ci contient une instruction MOVLW qui transfert dans W le valeur de calibration du registre OSCCAL. Au deuxième cycle, au début de l'exécution de cette instruction le compteur ordinal retombe à zéro et l'instruction qui est à l'adresse zéro est transférée dans le fetch register.

On va prendre en exemple 2 instructions, GOTO et ADDWF. Commençons par le GOTO. Le code opérationnel de cette instruction est encodée sur les 3 bits les plus significatifs (les instructions sont encodées sur 12 bits) et correspond à 101. Voici comment elle pourrait-être décodée.

Ce schéma est partiel, je n'ai pas dessiner tous les bus et les portes de sélection (tristate gate). C'est en utilisant ces portes de sélection que les informations sont transférées d'un registre à l'autre par les différents signaux Qx. Comme on le voit sur le schéma ci-haut. Les signaux Qx sont décalés dans le temps les uns par rapport aux autres de sortent qu'ils agissent l'un après l'autre. Ce sont eux qui permettent de passer d'une étape à la suivante. Voiçi les étapes pour le GOTO, les étapes 1 à 3 sont communes à toutes les instructions:
  1. Sur la transition Q1 montante on peut transférer le contenu du registre fetch register dans le registre décodeur d'instruction (instructon register). En même temps le contenu du compteur ordinal peut-être transféré vers une des entrée de l'UAL et la valeur 1 sur l'autre entrée.
  2. Sur la transition descendante de Q1 le contenu du bus data de la mémoire programme peut-être transféré dans le fetch register.
  3. Sur la transition montante de Q2 le résultat de l'incrément dans l'UAL est renvoyé dans le compteur ordinal.
  4. Sur Q2 descendant on peut transférer les 9 bits faibles de l'instruction register qui contienne l'adresse de destination du GOTO vers le compteur ordinal.
  5. A cause du changement de valeur du compteur ordinal, le contenu du fetch register n'est plus valide. On doit le remplacer par une instruction NOP de sorte qu'au cycle suivant le fetch register sera rempli avec l'instruction pointée par la nouvelle adresse du compteur ordinal. Voilà pourquoi les instructions de saut prennent 2 Tcy au lieu d'un seul. Cette opération peut-être effectuée pendant les phases Q3 et Q4.

Le compteur ordinal a plus de 8 bits alors que ce passe-t-il lors de l'incrément lorsqu'il y a débordement? A mon avis la façon la plus simple de régler ce problème est en fait d'avoir un UAL qui a autant de bits que le compteur ordinal. Même si l'UAL est plus large que le bus de données ça ne pose pas de problème et pour une petite UAL comme celle-ci le coup supplémentaire est sans doute négligeable.

ADDWF

Voici un schéma partiel d'un décodeur pour cette instruction.

Comme W est utilisé comme opérande on envoie son contenu à une des entrées de l'UAL. Les 5 bits les plus faibles de l'instruction sélectionne l'autre entrée à partir du register file. Ça peut-être une location RAM ou un SFR. S'il le register file a plus que 32 locations, il y a un bank select register qui est utilisé pour adresser les bits les plus forts de l'adresse ou bank. Si la mémoire de PIC baseline est fragmenté en segments c'est justement parce que dans l'instruction il n'y a que 5 bits pour addresser le register file. L'adressage doit donc être complété par le registre BSR (Bank Select Register).

Notez comment le bit d de l'instruction est utilisé pour sélectionner la destination du résultat. Si d vaut zéro c'est la porte qui conduit vers W qui est ouverte. Par contre si d vaut un, c'est la porte qui conduit vers le register file qui est ouverte. Un petit rond à l'entrée de contrôle d'une porte signifie que le signal est inversé (active low).

décodeur ROM

Créer un décodeur pour chaque instruction peut nécessité beaucoup de portes logiques même si les instructions peuvent partager des portes, par exemples les inverseurs sont communs à tous les décodeurs. Il y a une autre façon de procéder, il s'agit d'utiliser un décodeur ROM (Read Only Memory). Les bits data de la ROM sont fabriqués avec un masque métallique plutôt que des portes et ont un faible coût. L'idée est simple à implanter, les bits de l'instruction register qui contiennent le code opérationnel sont utilisés comme adresse d'une mémoire ROM. Les lignes de sortie de donnée de la ROM sont utilisés comme signaux pour contrôler les portes, en plus certaines lignes de données sont retournées vers le bus d'adresse de la ROM ce qui permet de faire évoluer l'automate de manière simple d'une étape à l'autre.

Supposons que le opcode est 5 et que les bits à la sortie du latch sont toujours à zéro au début du cycle d'instruction. À l'adresse 5 de la mémoire ROM on met les bits data aux valeurs qu'on a besoin sur le bus de contrôle et on envoie dans le latch les bits qui combinés avec les bits qui proviennent de l'instruction register vont donner l'adresse en ROM qui contient les valeurs de bits qu'on aura besoin à la prochaine étape du décodage. Ce genre de state machine est fréquemment utilisé, particulièrement dans les FPGA.

PICvision: ajout du jeux 2048


complément à 2

$
0
0

Dans cet article j'explique ce qu'est le complément à 2 (Two's complement) et pourquoi il est utilisé pour représenter les entiers en binaire.

Lorsque nous représentons les nombres en visuel, pour représenter les nombres négatifs nous les précédons simplement du symbole'-' comme dans -35. Mais comment sont-il représentés en mémoire d'ordinateur, c'est à dire en binaire, puisque tout n'est qu'une suite de zéro et un?

Puisqu'un nombre ne peut-être que soit positif, soit négatif un seul bit peut servir à indiquer son signe. On pourrait simplement par exemple réserver le bit le plus significatif pour cette fonction. Supposons des nombres de 8 bits et réservons le bit 7 pour le signe. On aurait alors que 5 serait représenté par 00000101 et -5 par 10000101. Avec 8 bits on pourrait donc représenter tous les entiers entre -127 et 127.

Pour faire les opérations arithmétiques on mettrait simplement de côté le bit de signe et l'opération serait effectuée sur les 7 autres bits. Supposons qu'on voudrait additionner 5 et -9 on s'y prendrais comment? En fait il faudrait soustraire 9-5 et changer le signe du résultat pour obtenir -4. Mais comment concevoir un soustracteur d'entiers avec des portes logique?

C'est ici que le complément à 2 interviens en simplifiant grandement le problème. Pour obtenir ce complément on procède comme suit.

  1. Inverser chaque bit du nombre binaire.
  2. Ajouter 1 au nombre résultant
  3. Le bit de débordement est rejeté
exemple: le complément à 2 de 5 (00000101) est 11111010+1 = 11111011

Le complément à 2 a des propriétés intéressantes par exemple si on recommence l'opération on obtient le nombre original:
11111011 ->00000100+1= 00000101. Tout entier obtenu par complément à 2 est donc considéré comme l'inverse de ce nombre en signe et tout nombre dont le bit le plus fort est 1 est considéré comme la représentation négative de l'entier. Donc pour les entiers de 8 bits les nombre 00000000à 01111111 (0 à 127) sont considérés comme entiers positifs. Si on fait le complément à 2 de ces 128 entiers ont obtient 00000000à 10000001 (0 à -127).

Il y a 2 cas particuliers 0 et -128 en effet si on fait le complément à 2 de 0 on obtient 0 lui-même et celui de -128 11111111 abouti à lui-même aussi. Donc l'étendue (domaine) des entiers binaire en complément à 2 pour 8 bits est de -128à 127. Ainsi avec le système des compléments à 2 les entiers ont toujours un représentant de plus du côté négatif.

Poursuivons notre exploration de ce système pour en percevoir toutes les propriétés intéressantes. Fabriquer un additionneur de nombre binaires avec des portes logiques est simple mais fabriquer un soustracteur serait beaucoup plus complexe. Et les 2 circuits seraient complexes s'il fallait tenir compte du signe des nombres. En effet comme on la vue plus haut additionner un nombre positif et un nombre négatif revient en fait à soustraire en conservant le signe du nombre de plus grande magnitude.

Heureusement la représentation en complément à 2 nous évite ces complications. le fait est que si on veut soustraire un nombre d'un autre il suffit d'additionner son complément à 2. Je veux soustraire 5 de 9. Je produit simplement avec la fonction NOT le complément à 1 de 5 et je lui additionne 1 pour obtenir 11111011 j'additionne ça à 9, 00001001 et j'obtiens 00000100 avec un bit de débordement à 1.

 9 00001001
+
-5 11111011 (en fait le complément à 2 de 5)



  &nbsp00000100C=1

Et si on additionne un entier positif avec un entier négatif on obtient le bon résultat sans avoir à se soucier des signes. Prenons par exemple -3 + 7 = 4

-3 11111101
+
 7 00000111



   00000100C=1

Dans ces 2 exemples C est le bit de débordement (carry bit).

Donc dans les faits les ordinateurs n'effectuent que des additions. Et un bit Cà 1 indique que l'addition a débordée lorqu'on additionne 2 nombres positif. Un bit Cà zéro lors d'une soustraction indique qu'il y a eu emprunt c'est à dire que le nombre soustrait était plus grand que l'autre. Dans le deuxième exemple on a additionner -3à 7 et le bit de débordement est à 1 parce que la magnitude de -3 est plus petite que la magnitude de 7. C'est conforme à ce qu'on aurait obtenu si on avait voulu soustraire 3 de 7. si on avait additionner -9 + 5 on aurait obtenu:

-9 11110111
+
 5 00000101



  &nbsp11111100C=0

Ici le bit C est à zéro conformément au fait que si on soustrait 9 de 5 on doit faire un emprunt. Ce qui n'était pas le cas dans le premier exemple ou c'était 5 qui était soustrait de 9.

Voilà comment le complément à 2 permet de faire des additions et soustractions sur des nombres signés en utilisant simplement un additionneur.

Notez que ce système de complément à la base numérique est valide dans toutes les bases. Vous pouvez le vérifier sur papier avec la base décimale. Dans ce cas il s'agit évidement de trouver le complément à 10. Supposons que nous travaillions avec des nombres de 2 chiffres (0 à 99). Les nombres de 0 à 49 sont considérés comme positifs et les nombres de 50 à 99 comme négatifs. Pour obtenir le complément à 10 on procède comme suis:

  1. soustraire de 9 chaque digit.
  2. additionner 1 au résultat.
  3. jeter le débordement à 100 s'il y lieu.
exemple: 32 donne 9-3=6 et 9-2=7 et donc 67+1 = 68. Essayons 48 - 32 -> 48 + 68 = 116. On jette le digit de débordement on obtient bien 16.

faire moins avec plus

$
0
0

Habituellement dans un soucis d'économie j'essaie d'en faire le plus possible avec le moins possible mais dans cette article je fais moins avec plus :-). En fait je montre comment générer un voltage négatif à partir d'un voltage positif.

Schématique

fonctionnement

Ce circuit utilise 2 périphériques du PIC10F322 soit le PWM1 (Pulse Widh Modulation) et le CWG (Complementary Wave Generator). Le PWM1 est configuré pour générer une onde carré à une fréquence de 62Khz et celle-ci alimente le CWG. La Sortie A du CWG est sur RA0 et la sortie B sur RA1. Le voltage à ces 2 sorties est le suivant:

Le tracé jaune est la sortie RA0 et le bleu la sortie RA1.

Donc lorsque RA0 est à 5 volts le condensateur C4 se charge à travers la diode D3. Lorsque RA0 tombe à zéro volt et que RA1 monte à 5 volts on obtient que le côté positif de C4 se retrouve à zéro volt. Puisque C4 est chargé son électrode négative se retrouve à -5 volts par rapport à Vss. La diode D2 entre en conduction et C4 se décharge dans C3. Mais puisque l'électrode positive de C3 est à +5 volts. La différence de tension entre ses 2 électrodes approche 10 volts. Donc lorsque RA0 va remonter à +5 volts et que RA1 va descendre à 0 volt. L’électrode négative de C3 sera à près de -10 volt par rapport à Vss. La diode D1 va alors entrer en conduction et C3 va libérer sa charge dans C1 et C2. Résultat on obtient un voltage négatif au point de test TP3.

Cependant le courant de la charge est limité par le courant de sortie des broches du MCU. En pratique j'obtiens pour un courant de charge de 6ma un voltage de -5,5 volts à TP3 avec une tension résiduelle à la fréquence du PWM de 15mV. Mais c'est suffisant pour alimenter un convertisseur de niveau RS-232.


Signal résiduel du CWG au point TP3 pour une de charge 6ma

Les diodes sont de type Schottkey plutôt qu'à jonction silicium, c'est plus efficace pour ce montage. Il y a moins de perte de voltage dans les diodes.

Si on a besoin d'une tension mieux filtrée et régularisé on peut utilisé un petit LDO à la sortie.

Il existe des composants disponible sur le marché pour effectuer spécifiquement ce type d'inversion de tension. Par exemple le TC7660 de Microchip.

Code source

Le code source comprend 2 fichiers, pic10f322_m.inc qui contient des macros et plus2minus.asm qui contient le programme principal.

Allumer un néon avec une alimentation de 5 volt

$
0
0

Dans cet article j'explique comment utiliser la surtension générée dans une inductance lorsqu'on coupe subitement le courant qui y circule pour allumer une ampoule néon. Pour faire exception ce projet n'utilise pas de microcontrôleur mais une minuterie 555.

L'ampoule que j'ai utilisée est une A1B. D'après les spécifications du fabriquant elle consomme 300µA lorsqu'elle est en conduction.

circuit

Le transistor 2N5551 est un transistor haute tension capable de supporter une tension de 160 volt à son collecteur lorsqu'il n'y a pas de courant dans la base (Vceo). Pour l'inductance L1 j'ai utiliser une récupéré dans le circuit de démarrage d'un fluo-compact défectueux. J'ignore la valeur de cette inductance mais il est certainement supérieur à 1mH. Cette valeur n'est pas critique mais si elle est trop petite il n'y aura pas suffisamment d'énergie dans le champ magnétique pour allumer le néon. Vous pouvez tester le circuit avec différentes valeurs. Utilisez au moins 1mH.

R3 est utiliser pour limiter le courant et C3 amorti les fluctuations de tensions sur la borne supérieur de L1. R3 et C3 forment ensemble ce qu'on appelle un filtre passe-bas empêchant les fluctuations rapides dans le circuit L1-Q1 de passer dans l'alimentation.

La minuterie 555 est configurée en oscillateur astable avec une fréquence de sortie d'environ 12,5Khz et un rapport cyclique de 50%. La sortie du 555 alimente la base de Q1 à travers R2. Lorsque Q1 conduit le courant passe dans l'inductance L1 qui emmagasine cette énergie dans un champ magnétique. Puisque la sortie du 555 est une onde carrée, à la fin de la phase haute du cycle le transistor Q1 cesse de conduire subitement. Cette coupure brusque du courant traversant L1 a pour effet un effondrement rapide du champ magnétique ce qui génère une surtension oscillante au bornes de L1. Le cycle d'oscillation commence par la phase positive, donc sitôt que la tension sur le collecteur de Q1 dépasse la tension sur le condensateur C4 la diode D2 entre en conduction ce qui permet à l'énergie de L1 de se dissiper dans C4. Lorsque la tension au collecteur de Q1 redescend sous le niveau de C4, D2 cesse de conduire. Mais il y a encore de l'énergie dans L1 donc l'oscillation se poursuit dans le négatif. La diode D1, appelée diode d'amortissement, empêche cette énergie de passer à travers le transistor car lorsque le collecteur de Q1 deviens négatif la jonction base-collecteur devient conductrice mais D1 empêche cette énergie de passer à travers la jonction base-collecteur en la dirigeant vers le v- de l'alimentation.

Voici le voltage au collecteur de Q1. La sonde de l'oscilloscope est en mode 10x donc le voltage de crête est de 56 volts. La tension continue sur C4 est de 55,5 volts environ. Le néon entre en conduction à environ 50 volts.

oscillateur à relaxation

Au départ j'ai ajusté l'alimentation à 5 volts, pour ensuite la réduire progressivement. Vers 2,5 volts le néon commence à clignoter et si je continue à diminuer la tension le clignotement ralenti et finalement il s'éteint complètement.

Lorsque l'inductance n'a plus suffisamment d'énergie pour garder C4 à un niveau de tension suffisant pour garder le néon en conduction il s'éteint. Mais lorsqu'il est éteint il n'y a plus de courant qui y circule donc le condensateur C4 se recharge. Lorsqu'il atteint un niveau suffisant pour faire entrer le néon en conduction, ce dernier décharge C4. Le voltage auquel le néon s'éteint est plus faible que celui auquel il s'allume donc il reste allumer un certain temps avant de s'éteindre à nouveau. C'est ce qu'on appelle un oscillateur à relaxation. Il en résulte une onde triangulaire à la jonction D2-C4. Plus la tension de la l'alimentation est basse plus il faut de temps pour recharger C4 donc la fréquence diminue.

oscillation amortie

J'ai remplacé L1 par une petite inductance de 47µH et j'ai débranché D2 pour visualiser à l'oscilloscope le signal au collecteur de Q1. Voici ce que ça donne.

Le tracé en bleu est le signal à la sortie du 555. Lorsque le signal à la base de Q1 tombe à zéro on voit très bien l'oscillation amortie au collecteur. La tension de crête à crête du premier cycle de l'oscillation est d'environ 13 volts. J'ai modifié l'échelle de temps pour montrer le détail de l'oscillation amortie.

La période est d'environ 440nSec. La formule pour calculer la fréquence d'oscillation d'un circuit accordé est:
F=1/sqrt(2*PI*L*C). Donc pour connaître la valeur de C on a:
C=1/(4*PI^2*L*F^2)
C=1/(4*3,1415^2*47e-6*(1/440e-9)^2
C=1/4*9,8696*47e-6*5,2e12=104pF
104pF serait la capacitance parasite qui fait osciller L1.

Conclusion

Les inductances comme les condensateurs sont des accumulateurs d'énergie. Alors que les condensateurs accumulent l'énergie dans un champ électrique, les inductances l'accumulent dans un champ magnétique. Cependant alors que le champ électrique peut persister dans un condensateur, le champ magnétique lui n'est pas persistant, il s'effondre lorsque l'alimentation est coupée. Mais cette énergie doit se dissiper quelque part. S'il n'y pas de circuit pour la dissiper la tension monte rapidement aux bornes de l'inductance. En théorie cette tension pourrait devenir infinie. En pratique elle est limitée par la capacitance parasite qui existe à l'intérieur de toute inductance. L'inductance forme avec cette capacitance parasite un circuit accordé qui se met à osciller jusqu'à ce que toute l'énergie soit dissipée dans la résistance du bobinage. La tension maximale est atteinte lorsque toute l'énergie du champ magnétique a été transférée dans la capacitance parasite. Dans le circuit ci-haut l'oscillation est amortie très rapidement (1 demi-cycle) car elle est dissipée dans C4 et à travers D1.

LPC810, partie 6, system clock et PLL

$
0
0

Dans ce 6ième article consacré au LPC810 j'explique comment configurer le PLL avec le IRC pour obtenir une fréquence de fonctionnement différente du 12Mhz de l'IRC.

LPC810 peut fonctionner à une fréquence maximale de 30Mhz selon les spécifications. L'oscillateur interne IRC fonctionne à 12Mhz. C'est la fréquence à laquelle le MCU fonctionne par défaut. Cependant en utilisant le PLL et le diviseur du system clock on peut faire fonctionner le MCU à une fréquence supérieure ou inférieure à 12Mhz.

PLL

PLL est l'acronyme anglophone de Phase Lock Loop. Il s'agit d'un circuit qui permet de multiplier une fréquence qu'on injecte à l'entrée par une certaine valeur. Voici le diagramme fonctionnel du PLL inclus dans le LPC810.

FCLKIN est le signal injecté à l'entrée du PLL et qui sera multiplié. Dans le cas du LPC810 il n'y a que 2 possibilités soit soit l'oscillateur IRC soit un signal provenant de la broche CLKIN. sys_osc_clk n'est disponible que sur les LPC811 et LPC812.

Au coeur du PLL il y a un oscillateur contrôlé par courant, le CCO (Current Controlled Oscillator). La fréquence du CCO peut varier entre 156Mhz et 320Mhz. Le bloc PFD (Phase Frequency Detector) compare le signal d'entrée avec le signal de sortie du PLL qui est divisé par les blocs /2P et /M. Si les 2 signaux n'ont pas la même fréquence et phase un signal d'erreur à la sortie du PFD modifie la fréquence du CCO pour diminuer cette erreur.

Donc lorsqu'on utilise le PLL on doit choisir 2 diviseurs le /2*P et le /M. La sortie du CCO est divisée par la valeur 2*P où P peut prendre les valeurs 2,4,8 16. Le diviseur /M peut prendre n'importe quelle valeur entre 1 et 32.

Prenons un exemple, dans lequel on veut faire fonctionner le MCU à sa fréquence maximale en utilisant l'IRC et le PLL. La sortie du PLL FLCKOUT ne peut pas être de 30Mhz car aucune division entière de 30Mhz ne donne 12Mhz. Le plus petit commun multiple entre 12Mhz et 30Mhz est 60Mhz. On va donc programmer le PLL pour obtenir un FCLKOUT de 60Mhz et on va utiliser le diviseur du system clock pour diviser FCLKOUT par 2. Selon les spécifications la fréquence maximale pour FCLKOUT est de 100Mhz.

La fréquence du CCO doit-être maintenue entre 156Mhz et 320Mhz. Donc on doit choisir une valeur de P de sorte que 156<=2*P*60<=320. Si on choisi 2 pour P on a un Fcco=2*P*60=240Mhz on est donc dans l'intervalle.

Maintenant il suffit de choisir la valeur de /M simplement M=60/12=5.

On a donc nos 2 valeurs pour P=2 et /M=5. C'est le registre SYSPLLCTRL qui contient ces 2 diviseurs. les bits 4:0 contiennent MSEL. La valeur de /M=MSEL+1, donc pour 5 on met 4 dans SYSPLLCTRL[4:0]. La valeur PSEL est dans les bits 6:5. les valeurs de P sont:

bits [6:5]P
001
012
104
118

Pour diviser FCLKOUT pour obtenir Fsysclk=30Mhz on utilise le registre SYSAHBCLKDIV. Ce diviseur est compris entre 1 et 255. Dans cet exemple on va y mettre la valeur 2.

code exemple

Lorsqu'on modifie les diviseurs du PLL il faut mettre à zéro et ensuite à 1 le registre SYSPLLCLKUEN (System PLL Clock Update Enable) pour mettre à jour les nouvelles valeurs.

Ensuite on sélectionne le diviseur dans SYSAHBCLKDIV et on sélectionne la sortie du PLL comme source du main clock. Encore une fois il faut faire une séquence 0,1 dans le registre MAINCLKUEN (Main Clock Update Enable) pour compléter la mise à jour.


Liens vers les articles précédents:

  1. Introduction au LPC810 (ARM M0+)
  2. LPC810, partie 2, anatomie
  3. LPC810, création d'un projet
  4. LPC810, partie 4, programmation
  5. LPC810, partie 5, module SCT et PWM

LPC810, partie 7, les interruptions

$
0
0

Dans cet article je discute des interruptions sur les LPC81x. En fait le contrôleur d'interruption fait partie du coeur ARM Cortex M0+, donc son fonctionnement est le même sur tous les MCU qui utilise les CPU M0 et M0+.

Le contrôleur d'interruption

Dans le jargon de la compagnie ARM ce contrôleur s'appelle NVIC pour Nested Vector Interruptupt Controller. Comme son nom l'indique il s'agit d'un contrôleur multi-niveaux utilisant une table de vecteurs. Par multi-niveaux on entend qu'une interruption en cours peut-être interrompue par une autre interruption de priorité supérieure. Il y a 4 niveaux de priorités numérotées de 0 à 3. 0 étant la plus haute et 3 la plus basse.

Lorsqu'on crée un projet utilisant CMSIS_CORE_LPC8xx dans LPCXpresso, on retrouve dans le dossier src du projet un fichier appelé cr_startup_lpc8xx.c et à l'intérieur de celui-ci se trouve la déclaration de toutes les fonctions de gestions d'interruptions.

Comme on le voit il s'agit d'alias pour un gestionnaire par défaut qui contient une boucle while infinie. Donc si dans votre programme vous activez une interruption sans créer un gestionnaire pour celle-ci, lorsque cette interruption sera déclenchée votre programme va bloqué.

Pour créer un gestionnaire d'interruption il suffit de créer une fonction avec le nom du gestionnaire définie dans ce fichier. Par exemple le gestionnaire pour le périphérique MRT (Multi Rate Timer) s'appelle MRT_IRQHandler.

Utilisation d'une interruption

A titre d'exemple on va créer un projet MRT-multi-blink et utiliser le périphérique MRT pour faire clignoter 3 LEDs à des vitesses différentes l'une de l'autre. Ce projet va utiliser une interruption MRT_IRQHandler. Le MRT contient 4 minuteries et chacune d'elle peut-être programmée pour un délais différent. Chaque fois qu'un délais expire l'interruption est déclenchée. Le gestionnaire vérifie qu'elle canal du MRT a déclenché l'interruption et inverse l'état de la LED correspondante.

Créez un nouveau "C project" appelé "MRT-multi-blink" et utilisez la librairie CMSIS_CORE_LPC8xx. Copiez le code source suivant dans le fichier main.c.

Analyse du programme.

Ce programme utilise le signal d'horloge par défaut soit l'IRC sans PLL. Donc le CPU tourne à 12Mhz. Dans la fonction main on commence par désactiver les fonctions fixes ACMP_I1, ACMP_I2, CLKIN, SWCLK et SWDIO. Ces fonctions sont activées/désactivés par des bits dans le registre LPC_SYSCON->PINENABLE0. la macro m_disable_function simplifie cette configuration.

Par défaut les périphériques sur le bus AHB sont désactivés. On doit donc les activés dans le registre LPC_SYSCON->SYSAHBCLKCTRL. Ici on active le clock pour les GPIO et pour le MRT. Se sont les 2 périphériques que ce programme utilise.

À la ligne suivante on met les broches sur lesquelles les LEDs sont branchées en mode sortie en mettant les bits correspondants dans LPC_GPIO_PORT->DIR0à la valeur 1. un bit à 0 dans ce registre correspond à une entrée.

Ensuite on configure les 3 canaux du MRT. Le registre STAT contient un bit indicateur d'interruption. Pour mettre ce bit à zéro il faut écrire un 1 dans le bit (ce n'est pas une erreur, mettre 1 pour réinitialiser). Le registre CTRL contient le bit d'activation/désactivation en position 0. et 2 bits de sélection du mode de fonctionnement en position 2:1. On active le canal en laissant le mode à zéro qui correspond au mode interruption répétitive. Dans ce mode une interruption est déclenchée lorsque le compteur arrive à zéro (le comptage est à rebours). La valeur initiale est rechargée automatiquement et le cycle recommence. On obtient donc une interruption à intervalle régulier.

Le compteur démarre au moment ou on inscris la valeur de l'intervalle désiré dans le registre INTVAL.

On programme ensuite la priorité d'interruption au plus bas niveau avec la fonction NVIC_SetPriority(). Finalement on active cette interruption avec la fonction NVIC_EnableIRQ().

Le gestionnaire d'interruption est très simple. On vérifie quels sont les canneaux qui ont l'indicateur d'interruption à 1 et pour ceux-ci, on inverse l'état de la sortie GPIO associé.

Pour en savoir plus sur l'interface de programmation des interruptions il faut lire le fichier d'entête core_cm0plus.h qui fait parti de la librairie CMSIS_CORE_LPC8xx.


Liens vers les articles précédents:

  1. Introduction au LPC810 (ARM M0+)
  2. LPC810, partie 2, anatomie
  3. LPC810, création d'un projet
  4. LPC810, partie 4, programmation
  5. LPC810, partie 5, module SCT et PWM
  6. LPC810, partie 6, system clock et PLL
Viewing all 192 articles
Browse latest View live