« Very High Speed Integrated Circuit Hardware Description Language/Embarquer un PIC 16F84 » : différence entre les versions

Contenu supprimé Contenu ajouté
m Robot : Remplacement de texte automatisé (-\b(idem(''')?)(?=[\s,.)]|$) +''\1'')
m Robot : Remplacement de texte automatisé (-(<|</)source([ \t>]) +\1syntaxhighlight\2)
Ligne 185 :
== Notre cœur ou processeur softcore ==
Le cœur original CQPIC a été réalisé de manière à être le plus proche du composant PIC® 16F84 original. Voici maintenant une description du cœur sous forme de programme VHDL.
<sourcesyntaxhighlight lang="VHDL">
component piccore
generic (
Ligne 242 :
);
end component;
</syntaxhighlight>
</source>
À noter que contrairement au PIC® 16F84, le composant CQPIC utilise une entrée spécifique "t0cki" pour le timer0 (pour le PIC® c’est le bit b4 T0CKl du '''PORTA'''). Il y a encore bien d'autres différences : comparez au brochage original du PIC® 16F84 décrit [[w:PIC_16F84_de_Microchip#Brochage_du_PIC16F84|dans un autre projet]] qui fait apparaître 18 broches seulement.
 
Ligne 262 :
| contenu =
Pour des raisons de compatibilité le port porta_dir n’est pas accessible de manière normale. L'écriture dans porta_dir se fait par l'instruction :
<sourcesyntaxhighlight lang="C">
// en langage C
TRISA=0xFF; // 1 ⟺ input
</syntaxhighlight>
</source>
tandis qu'en assembleur on écrira :
<pre>
Ligne 283 :
| contenu =
Notre dernière remarque sera pour compléter notre description. Si l’on écrit dans un programme C :
<sourcesyntaxhighlight lang="C">
// en langage C
PORTA = PORTA; // recopie d'un PORT
</syntaxhighlight>
</source>
ceci aura comme signification : porta_out <= porta_in. Physiquement, ce qui est à gauche du signe égal, n’est pas la même chose que ce qui est à droite.
}}
Ligne 296 :
=== La RAM ===
Il existe peu de modèles de mémoire standard dans le monde des [[w:FPGA|FPGA]] et [[w:Application_Specific_Integrated_Circuit|ASIC]]. En fait le type le plus commun de mémoire que l’on peut trouver est ce que la norme [[w:Wishbone_(computer_bus)|WISHBONE]] appelle 'FASM', ou FPGA and ASIC Subset Model. Pour la [[w:Mémoire_vive|RAM]], sa spécificité est qu’il s'agit d'une mémoire à écriture et lecture synchrone. Il est facile de trouver des exemples d'une telle mémoire en VHDL. Nous avons choisi :
<sourcesyntaxhighlight lang="VHDL">
library ieee;
use ieee.std_logic_1164.all;
Ligne 331 :
dataout <= ram(to_integer(unsigned(addr_reg)));
end RTL;
</syntaxhighlight>
</source>
La gestion de la RAM dans un système mono-puce n’est pas un problème aussi simple qu’il n'y parait. Examinons de plus près ce problème et ce qui fait sa difficulté.
Ligne 362 :
=== La ROM ===
C'est là que se situe le programme à exécuter. Puisque tout compilateur ou assembleur génère un fichier hex, il nous est nécessaire de transformer ce fichier hex en fichier VHDL. Ceci est laissé à un programme C décrit un peu plus loin. Commençons à présenter un exemple de ROM.
<sourcesyntaxhighlight lang="VHDL">
-- This file was generated with hex2rom written by Daniel Wallner
library IEEE;
Ligne 406 :
end process;
end;
</syntaxhighlight>
</source>
Cet exemple montre un contenu mais chaque programme donnera une ROM différente. Il est à noter que ce que l’on présente est du VHDL alors que chaque compilateur ou assembleur ne délivre qu'un fichier au format [[w:HEX_(Intel)|HEX]]. Il faudra donc un utilitaire pour transformer le fichier HEX en fichier VHDL car il s'agit d'une opération qui peut se se faire automatiquement. Nous utiliserons un programme en C++ que nous donnons en [[Very High Speed Integrated Circuit Hardware Description Language/Embarquer un PIC 16F84#Annexe 1|annexe 1]] et qui se trouve dans le répertoire "\CQPICStart\ROM" du fichier [http://moutou.pagesperso-orange.fr/ER2/CQPICStart.zip CQPICStart.zip].
 
Ligne 428 :
=== Le premier programme simple en C avec assembleur ===
Le programme présenté montre comment inclure de l'assembleur dans un programme C.
<sourcesyntaxhighlight lang="C">
#include <pic1684.h>
//#include <htc.h> serait-il mieux ?
Ligne 441 :
#endasm
}
</syntaxhighlight>
</source>
Ne prenez pas ce programme à la lettre. Il est donné pour exemple mais fonctionne de manière surprenante.
 
Ligne 448 :
=== Le premier programme simple en C pur ===
Un programme tout simple de test est présenté maintenant : il s'agit tout simplement de recopier le PORTA sur le '''PORTB'''. Remarquons aussi que ce programme fonctionne complètement si l’on a pris soin de prendre la version que j’ai réalisée.
<sourcesyntaxhighlight lang="C">
#include <pic1684.h>
//#include <htc.h> serait-il mieux ?
Ligne 458 :
PORTB = PORTA; // recopie du PORTA dans le PORTB qui allume les LEDs
}
</syntaxhighlight>
</source>
Contrairement au Silicore1657 déjà évoqué (projet de l'année précédente), le cœur CQPIC dispose du mécanisme d'interruption que nous allons détailler maintenant avec un exemple simple.
 
Ligne 483 :
==== Le programme ====
Le programme correspondant est donné maintenant.
<sourcesyntaxhighlight lang="C">
#include <pic1684.h>
void interrupt decalage(void);
Ligne 513 :
T0IF = 0; // acquittement interruption
}
</syntaxhighlight>
</source>
Remarquez le "if (!(nb % 16))" qui réalise la division par 16 dans l'interruption. C'est absolument nécessaire pour notre cœur qui fonctionne à {{Unité|50|{{abréviation|Mhz|mégahertz}}}} pour voir les LEDs allumées se déplacer.
 
Ligne 539 :
 
La modification du cœur CQPIC pour augmenter le nombre de bits du '''PORTA''', m'a amené à lire son code VHDL et je suis tombé sur :
<sourcesyntaxhighlight lang="VHDL">
-- VHDL
for I in 0 to 7 loop
Ligne 548 :
end if;
end loop;
</syntaxhighlight>
</source>
Ce code montre que '''TRISA''' est pris en compte en interne dans le cœur CQPIC. Ceci peut sembler normal, mais n’est pas conforme à la seule expérience que nous avions avec le [[../Système monopuce compatible avec les PIC 16C57/|Silicore1657]] : puisque '''TRISA''' était sorti à l'extérieur il pouvait servir de PORT supplémentaire.
Si vous avez l’idée d’utiliser '''TRISA''' comme PORT supplémentaire ici, vous aurez un fonctionnement étrange d'un programme C :
<sourcesyntaxhighlight lang="C">
//langage C
TRISA = PORTA ;
</syntaxhighlight>
</source>
Physiquement, on relie '''PORTA''' (ra_out) à des interrupteurs et '''TRISA''' (ra_dir) à des [[w:Diode_électroluminescente|LED]]s. Si PORTA est à OxFF (par les interrupteurs extérieurs), tout interrupteur mis à 0 éteindra correctement la LED correspondante (reliée à '''TRISA'''). Mais l'inverse ne marche plus : si ce même interrupteur est remis à 1 on n'allume plus la LED correspondante.
 
Ligne 572 :
Notez que cette solution impose de déclarer '''PORTC''' et '''TRISC''' dans les programmes C. Je déconseille une modification du fichier pic1684.h Faites plutôt comme ceci :
<sourcesyntaxhighlight lang="C">
#include <pic1684.h> // ou #include <hct.h>
volatile unsigned char PORTC @ 0x07;
volatile unsigned char TRISC @ 0x87;
</syntaxhighlight>
</source>
C'est simple, mais cela ne permet pas un accès à des bits individuels (mais nous n'avons pas besoin de cela dans notre projet).
Ligne 594 :
 
Le programme VHDL correspondant au schéma de la page précédente est présenté maintenant. Il comporte deux entrées '''PORTA''' et '''PORTC''' pour réaliser quatre ports de sorties pA, pB, pC, pD.
<sourcesyntaxhighlight lang="VHDL">
-- increase the number of available ports with the new portC and its strobe
-- ver1.10b, 2010/05/22 (Serge Moutou)
Ligne 651 :
end process;
end BehPorts;
</syntaxhighlight>
</source>
Remarquez qu'on a utilisé des "process" au lieu de "components" pour simplifier le programme.
==== Exercice ====
Ligne 657 :
 
{{Solution|contenu=
<sourcesyntaxhighlight lang="VHDL">
-- increase the number of available ports with the new portC and its strobe
-- ver1.10b, 2010/05/22 (Serge Moutou)
Ligne 734 :
end process;
end BehPorts;
</syntaxhighlight>
</source>
}}
Arrivé à ce point, il nous faut certainement donner une image simple de ce que l’on cherche à faire.
Ligne 752 :
=== Le sous-programme "setX" ===
Une version en C pur est montrée ci-dessous :
<sourcesyntaxhighlight lang="C">
void setX(unsigned int x){
TRISA=0x00;TRISC=0x00;
Ligne 760 :
PORTC=x>>8;//poids fort
}
</syntaxhighlight>
</source>
Le contenu de ce programme est complètement déterminé par la partie matérielle.
 
=== Déplacement horizontal en continu de notre balle/rectangle ===
Nous allons présenter maintenant un programme fonctionnel qui déplace sans arrêt le rectangle sur une horizontale.
<sourcesyntaxhighlight lang="C">
#include <pic1684.h>
volatile unsigned char PORTC @ 0x07;
Ligne 806 :
while(TMR0<tempo);
}
</syntaxhighlight>
</source>
Remarquez l’utilisation du timer0 sans interruption pour faire la temporisation.
 
=== Programme complet de gestion simple de la balle ===
Nous présentons maintenant un programme simple de gestion de la balle avec des rebonds :
<sourcesyntaxhighlight lang="C">
#include <pic1684.h>
volatile unsigned char PORTC @ 0x07;
Ligne 856 :
while(TMR0<tempo);
}
</syntaxhighlight>
</source>
 
L'inconvénient de ce programme est le petit nombre des trajectoires gérées, ce qui peut devenir lassant pour un jeu.
Ligne 880 :
|}
Pour pouvoir gérer des rectangles de tailles différentes et de couleur différentes, on complique un peu la partie destinée à dessiner un rectangle en lui donnant une couleur de rectangle une largeur et une hauteur. Voici donc notre nouveau composant :
<sourcesyntaxhighlight lang="VHDL">
COMPONENT rect IS PORT(
row,col,x_rec,y_rec,delta_x,delta_y :in STD_LOGIC_VECTOR(9 DOWNTO 0);
Ligne 886 :
red1,green1,blue1 : out std_logic);
END component;
</syntaxhighlight>
</source>
L'intanciation des rectangles pour la balle et les raquettes se fera alors de la manière suivante :
<sourcesyntaxhighlight lang="VHDL">
balle:rect port map(row=>srow, col=>scol,r ed1=>sred, green1=>sgreen, blue1=>sblue, colorRGB=>"111", delta_x=>"0000001010", delta_y=>"0000001100", x_rec => x_rect, y_rec => y_rect);
raquetteG:rect port map(row=>srow, col=>scol, red1=>sred1, green1=>sgreen1,
Ligne 901 :
green <= sgreen or sgreen1 or sgreen2;
blue <= sblue or sblue1 or sblue2;
</syntaxhighlight>
</source>
Les déclarations des signaux dans ce morceau de programme sont omises.
Voici maintenant le programme C permettant le rebond sur les raquettes. Vous pouvez remarquer que les coordonnées des raquettes sont calculées en fonction des interrupteurs sur le '''PORTB''', mais ne sont pas mises à jour dans le matériel puisque le matériel ne peut pas le faire.
<sourcesyntaxhighlight lang="C">
//#include <pic1684.h> // Programme pour Hitech C dans MPLAB
#include <htc.h> //***** Hitech C *******
Ligne 948 :
}
}
</syntaxhighlight>
</source>
Comme on peut le voir nous avons choisi le '''PORTB''' connecté aux interrupteurs sw0,sw1,sw6 et sw7 de la carte, pour faire descendre et monter les raquettes et sw2 (RB2) pour le départ.
 
Ligne 976 :
{{Solution|contenu=
Le contenu de la gestion des ports est donné dans l'exercice plus haut. Voici le complément :
<sourcesyntaxhighlight lang="VHDL">
-- CQPIC.vhd
-- CQPIC top (PIC16F8 with CPU-core, program ROM and data RAM)
Ligne 1 327 :
--<
end RTL;
</syntaxhighlight>
</source>
 
}}
Ligne 1 335 :
{{Solution|contenu=
Premièrement : modifier le programme pour utiliser setXY au lieu et place de setX et setY :
<sourcesyntaxhighlight lang="c">
//#include <pic1684.h> // Programme pour Hitech C dans MPLAB
#include <htc.h>
Ligne 1 401 :
while(TMR0<tempo);
}
</syntaxhighlight>
</source>
 
Pour l’[[w:Algorithme_de_tracé_de_segment_de_Bresenham|algorithme de tracé de segment de Bresenham]], le programme le plus compact trouvé [http://rosettacode.org/wiki/Bitmap/Bresenham's_line_algorithm sur internet] est :
<sourcesyntaxhighlight lang="c">
//********* http://rosettacode.org/wiki/Bitmap/Bresenham's_line_algorithm
void line(int x0, int y0, int x1, int y1) {
Ligne 1 418 :
}
}
</syntaxhighlight>
</source>
La première chose que fait l'algorithme est de calculer dx et dy. En ce qui nous concerne, nous ne ferons pas ce calcul puisque nous gérerons directement ce dx et ce dy. Entre parenthèse, cela nous évite de calculer des points d'intersections de notre trajectoire avec les bords de l'écran.
 
En remarquant que x0 est notre posX, y0 est notre posY, sx est notre deltaX et donc sy notre delatY, il vient :
 
<sourcesyntaxhighlight lang="c">
#include <pic1684.h> // Programme pour Hitech C dans MPLAB
volatile unsigned char PORTC @ 0x07;
Ligne 1 478 :
 
//************* voir ci-dessus pour setXY et wait
</syntaxhighlight>
</source>
 
Il ne reste plus qu’à faire varier deltaY entre 15 et 5 par exemple à l'aide des rebonds sur les raquettes.
Ligne 1 484 :
Certains se demandent peut-être ce qu’il y a de [[w:Algorithme_de_tracé_de_segment_de_Bresenham|Bresenham]] là-dedans. Je vous rappelle que l'algorithme original permet de calculer les points d'une droite sans multiplication et sans division, c’est ce que l’on fait ici. Ce qui caractérise cet algorithme c’est que la pente de la droite tracée est dy/dx, c'est-à-dire un [[w:Nombre_rationnel|nombre rationnel]], c’est ce que l’on a encore une fois.
Changez la ligne
<sourcesyntaxhighlight lang="c">
// int err = (dx>dy ? dx : -dy)/2, e2; montre comment calculer err
int dx=10,dy=10,err=-5,e2; //Pour Bresenham
</syntaxhighlight>
</source>
en
<sourcesyntaxhighlight lang="c">
// int err = (dx>dy ? dx : -dy)/2, e2; montre comment calculer err
int dx=10,dy=5,err=+5,e2; //Pour Bresenham
</syntaxhighlight>
</source>
ou encore en
<sourcesyntaxhighlight lang="c">
// int err = (dx>dy ? dx : -dy)/2, e2; montre comment calculer err
int dx=10,dy=15,err=-7,e2; //Pour Bresenham
</syntaxhighlight>
</source>
pour voir les différentes pentes du déplacement de la balle.
 
Ligne 1 508 :
* si le déplacement de la raquette et de la balle (suivant y) sont en sens contraires on diminue dy en ne dépassant jamais 5
 
<sourcesyntaxhighlight lang="c">
#include <pic1684.h> // Programme pour Hitech C dans MPLAB
volatile unsigned char PORTC @ 0x07;
Ligne 1 588 :
}
}
</syntaxhighlight>
</source>
 
Pour information l’ensemble des resources mémoire de ce programme est donné maintenant :