Very High Speed Integrated Circuit Hardware Description Language/Exercices/Autres projets pour ATMEL ATMega8
|
|
|||
| Exercice no5 | |||
| Leçon : Very High Speed Integrated Circuit Hardware Description Language | |||
|---|---|---|---|
|
|
|||
Nous avons l'intention de mettre dans ce chapitre une série de projets permettant de faire évoluer et de mettre en œuvre le coreATMega8.
Sommaire |
[modifier] Projet pour l'année universitaire 2011/2012
Étant satisfait avec le coreATMega8, nous avons décidé de poursuivre l'utilisation de ce système monopuce, et de l'utiliser pour réaliser un autre projet. La carte cible sera plus la même, elle sera réalisée autour d'un spartan3 200. Étant donné que les corrections du jeu de Pong ont été complètement publiées dans un autre chapitre, il nous faut changer de sujet. Il s'agit d'un jeu un peu similaire au jeu de Pong, à savoir un Casse-briques.
[modifier] Version de l'ATMega8
L'écriture du chapitre Programmer in Situ et déboguer nous a obligé à faire évoluer le cœur embarqué coreATMega8.
|
Remarque |
|
La gestion d'interruptions et l'implantation de l'instruction SPM ne sont pas nécessaires pour le projet « casse briques » de cette année, mais le simple fait de vouloir utiliser data2mem (décrit lui aussi dans Programmer in Situ et déboguer) nous oblige à utiliser la dernière version de notre processeur ! Cette version n'est pas disponible chez Opencores pour le moment mais nous la mettons à disposition dans le répertoire /AVRComplet16_S4_S4/25MHzAVR/ de notre ATMega8_pong_VGA.zip. C'est la version la plus à jour, version dans laquelle nous avons vérifié les interruptions RS232 et l'instruction SPM. |
[modifier] Cahier des charges
Une seule raquette est mobile verticalement. L'autre est présente mais son déplacement est lié à celui de la balle. Donc le rebond sur cette raquette se fait toujours.
Nous présentons ci-dessus l'écran VGA pour le casse-brique dans l'hypothèse où le déplacement de la raquette liée à la balle est fait par le processeur. Si l'on compare au jeu de Pong du chapitre sur l'ATMega8, il faut 8 bits supplémentaire pour gérer ce nouveau jeu.
[modifier] Travail à réaliser
Trois phases distinctes sont à réaliser, un projet tuteuré sur environ 12 heures qui se solde par un rapport, la réalisation de la partie matérielle à partir de l'existant (c'est-à-dire le projet de pong précédent), puis le développement de la partie logicielle.
[modifier] Projet tuteuré
Réaliser un schéma fonctionnel complet de la partie matérielle. Nous aimerions un schéma réalisé sous OpenOffice pour pouvoir le publier ici. Calculer le nombre de PORTs nécessaires pour interfacer votre écran VGA et votre processeur. A ce stade, il vous faut choisir si la liaison entre la balle et la raquette se fait à l'aide du matériel où à l'aide du logiciel.
Apprentissage du GNU C pour l'AVR. Pour cela vous partirez du répertoire /AVRComplet16_S4_S4 du fichier ATMega8_pong_VGA.zip qui contient une version améliorée du processeur, capable de gérer les interruptions et surtout capable d'exécuter une instruction qui écrit en programme mémoire. Cela permet de réaliser un bootloader ce qui facilite grandement le développement. Nous nous contenterons d'utiliser « data2mem » pour cette année car nous n'avons pas réussi jusqu'à présent à faire fonctionner notre bootloader.
La partie matérielle gère les quatre afficheurs sept segments et les LEDs à travers des PORTs :
- PORTB pour l'affichage des 7 segments
- PORTC pour les 8 LEDs
- PORTD pour la sélection des digits d'affichages
Écrire des programmes C réalisant des chenillards un compteur sur deux digits.
[modifier] Corrections
Voici un programme C réalisant un chenillard :
#include "avr/io.h" #undef F_CPU #define F_CPU 25000000UL #include "util/delay.h" main(void) { // La gestion de DDRB et DDRC est inutile pour ce cœur // DDRB = 0xFF; // 8 sorties pour B retiré car non implanté (voir ci-dessus) // DDRC = 0x00; // 8 entrees pour C retiré car non implanté uint8_t i=0; while(1) { i++; i &= 0x07; PORTC = 1 << i; _delay_ms(1000); } }
[modifier] Partie matérielle
Le chapitre Interface VGA et PS/2 ou le répertoire /CorrProjet2010 du fichier ATMega8_pong_VGA.zip contiennent une correction de la partie VGA du jeu de Pong (fichier VGA_top.vhd et ses composants) Modifier ce fichier pour remplacer l'affichage du score inutile par deux rangées de 8 briques au milieu de l'écran. Il serait bon de changer la place de l'affichage des scores (plus au milieu). Pour mettre au point cette partie on travaillera sans processeur. Une fois que tout est au point on crée l'interface entre cette partie et le processeur.
Pour aider les étudiants, nous proposons les choix technologiques suivants reliant les PORTs aux signaux de commande VGA :
- choix technologiques
-
E/S module VGA E/S AVR x_rect<9:8> PORTD<1:0> x_rect<7:0> DDRD<7:0> y_rect<9:8> PORTB<1:0> y_rect<7:0> DDRB<7:0> y_raqG<7:0> PORTC<7:0> y_raqD<7:0> DDRC<7:0> ligne1<7:0> PORTA<7:0> ligne2<7:0> DDRA<7:0> scoreG<7:0> EEDR<7:0>
Le registre EEDR est normalement réservé aux données de l'EEPROM. Comme nous n'avons pas d'EEPROM dans notre cœur embarqué nous l'utilisons pour ajouter 8 bits de sorties supplémentaires. « ligne1 » et « ligne2 » gèrent le 1er mur1 et le 2eme mur de l'image ci-dessus.
C'est une caractéristique de ce cœur, cette facilité à transformer des registres en PORTs. Nous rappelons que ceci est fait avec le code VHDL :
-- ceci est dans un fichier io2.vhd qui remplace io.vhd original -- IO write process -- iowr: process(I_CLK) begin if (rising_edge(I_CLK)) then if (I_CLR = '1') then L_RX_INT_ENABLED <= '0'; L_TX_INT_ENABLED <= '0'; elsif (I_WE_IO = '1') then case I_ADR_IO is when X"31" => Balle_xLow <= I_DIN; --DDRD when X"32" => Balle_xHigh <= I_DIN; --PORTD when X"37" => Balle_yLow <= I_DIN; --DDRB when X"38" => Balle_yHigh <= I_DIN; --PORTB when X"34" => raqD_y <= I_DIN; --DDRC when X"35" => raqG_y <= I_DIN; --PORTC when X"3B" => s_ligne1 <= I_DIN; -- PORTA when X"3A" => s_ligne2 <= I_DIN; -- DDRA when X"3D" => s_scoreg <= I_DIN; -- EEDR : EEPROM Data Register when X"40" => -- handled by uart when X"41" => -- handled by uart when X"43" => L_RX_INT_ENABLED <= I_DIN(0); L_TX_INT_ENABLED <= I_DIN(1); when others => end case; end if; end if; end process;
Et voici de manière schématique ce qu'il faut faire pour interfacer notre écran VGA au processeur :
Conventions de la figure
Les signes + devant des entrées ou sorties veulent dire que l'on a ajouté ces entrées ou sorties dans les entités correspondantes. On a dessiné seulement trois composants dans cette figure, mais il en existe beaucoup d'autres.
- Le composant VGATop est inclu dans le fichier io.vhd qui est renommé io2.vhd pour l'occasion.
- La connexion à l'intérieur de io2.vhd se fait avec le process vhdl qui est montré plus haut dans cette section.
[modifier] Solution
Exercice3 question 3 du chapitre Interfaces VGA et PS2 contient une correction de la partie gestion de l'écran VGA.
|
Remarque |
|
Le répertoire /CorrProjet2011 du fichier ATMega8_pong_VGA.zip contient une correction complète du projet 2011/2012. |
[modifier] Partie logicielle
Programmer l'ensemble avec plusieurs niveaux de jeu :
- un premier niveau avec une rangée de briques pour lequel n'importe quel rebond sur une brique éteint cette brique
- un deuxième niveau avec une rangée de brique avec une sur deux d'allumée pour lequel n'importe quel rebond sur une brique éteint cette brique
- un troisième niveau semblable au premier niveau avec une rangée de briques mais pour lequel seule une balle provenant de votre raquette pourra éteindre une brique
- un quatrième niveau semblable au deuxième niveau avec une rangée de briques une sur deux allumée mais pour lequel seule une balle provenant de votre raquette éteindra une brique
- un cinquième de niveaux avec deux rangées de briques.
Les étudiants ont toute latitude pour accélérer les balles et trouver un algorithme de calcul des scores.
Le changement de pente pour la balle pourra se faire de manière aléatoire par la raquette qui suit la balle.
Attachez-vous à comprendre comment le C gère les briques : comment vous savez où sont les briques ? C'est fait ici grâce aux deux tableaux tabmur1 et tabmur2 qui contiennent toutes les informations de position que vous avez dans votre partie matérielle.
// gestion d'un casse brique dans un FPGA = VGA+ATMega8 // Ce programme tient dans environ 2ko sur 8 ko dispo // Il manque cependant de jouabilité !!!! #include <avr/io.h> #include "util/delay.h" #undef F_CPU #define F_CPU 25000000UL /* Port A */ //#define PINA _SFR_IO8(0x19) // Les ports ci-dessous n'existent pas dans l'ATMega8 de la vraie vie mais nous les avons ajouté dans notre coeur // d'où leur présence ici : ne pas modifier les fichiers d'entête ! #define DDRA _SFR_IO8(0x1A) #define PORTA _SFR_IO8(0x1B) //****************************************************************************************************************************** // constants definitions (see VHDL files) //****************************************************************************************************************************** // Constantes liées au matériel (voir dans VHDL) // Mes étudiants, par exemple, ont mis les deux murs plus à gauche ce qui change ces constantes //************** wall 1 #define GX1 420 #define GY 0 #define GDX 20 #define GDY 422 //************** wall 2 #define GX2 440 //****************************************************************************************************************************** // data type definitions and the correspionding arrays //****************************************************************************************************************************** //L'utilisation pratique des tableaux ci-dessous nous a montré qu'il est possible de retirer le champ xdeb pour économiser de la place mémoire struct s_brique { uint16_t xdeb,ydeb,xfin,yfin; } tabmur1[8]={{GX1-10,GY,GX1+GDX,(GDY-GY)/8},{GX1-10,(GDY-GY)/8 -12,GX1+GDX,2*(GDY-GY)/8},{GX1-10,2*(GDY-GY)/8 -12,GX1+GDX,3*(GDY-GY)/8}, {GX1-10,3*(GDY-GY)/8 -12,GX1+GDX,4*(GDY-GY)/8},{GX1-10,4*(GDY-GY)/8 -12,GX1+GDX,5*(GDY-GY)/8},{GX1-10,5*(GDY-GY)/8 -12,GX1+GDX,6*(GDY-GY)/8}, {GX1-10,6*(GDY-GY)/8 -12,GX1+GDX,7*(GDY-GY)/8},{GX1-10,7*(GDY-GY)/8 -12,GX1+GDX,(GDY-GY)}}, tabmur2[8]={{GX2-10,GY,GX2+GDX,(GDY-GY)/8},{GX2-10,(GDY-GY)/8 -12,GX2+GDX,2*(GDY-GY)/8},{GX2-10,2*(GDY-GY)/8 -12,GX2+GDX,3*(GDY-GY)/8}, {GX2-10,3*(GDY-GY)/8 -12,GX2+GDX,4*(GDY-GY)/8},{GX2-10,4*(GDY-GY)/8 -12,GX2+GDX,5*(GDY-GY)/8},{GX2-10,5*(GDY-GY)/8 -12,GX2+GDX,6*(GDY-GY)/8}, {GX2-10,6*(GDY-GY)/8 -12,GX2+GDX,7*(GDY-GY)/8},{GX2-10,7*(GDY-GY)/8 -12,GX2+GDX,(GDY-GY)}}; //****************************************************************************************************************************** // functions prototypes //****************************************************************************************************************************** void setXY(uint16_t x,unsigned int y); void My_delay(unsigned int delay); void bounceOffTheWall(unsigned int posX,unsigned int posY,unsigned char level,unsigned char levelMin, struct s_brique tableauData[],signed char *deltaX,signed char *deltaY,unsigned char *mur); unsigned char PseudoAleat(uint16_t Lim); //****************************************************************************************************************************** // main //****************************************************************************************************************************** int main (void) { unsigned int posRaqu_16; unsigned int posX,posY,tempo=250; // change to 200 to increase speed unsigned char raqD_y=0,raqG_y=0,dizG=0,level=1,line1=0,line2=0,random=0; signed char deltaX=1,deltaY=1,delta_raqG_y=1; // int err = (dx>dy ? dx : -dy)/2, e2; montre comment calculer err int dx=10,dy=5,err=5,e2; //Pour Bresenham line1 = 0xFF; // level 1 PORTA = line1; //update the wall number 1 DDRA = 0x00; // update the wall number 2 while(1) { EEDR = level; // two digits level // starting position posX=320; posY=200; setXY(posX,posY); deltaX=-1; //attente du départ et recherche graine du gene pseudoaléatoire while (bit_is_clear(PINB,PINB0))random = PseudoAleat(12); while (posX>30 && (line1 || line2)) { //equation booléenne pas facile à trouver posRaqu_16=raqD_y<<1; if (posX>=574) { // le rebond est automatique //Ne pas remettre le test ci-dessous semble poser problème de temps en temps if (deltaX>0) deltaX= -deltaX; // rebond sur raquette droite // changement de pente aléatoire dy = PseudoAleat(12); } posRaqu_16=raqG_y<<1; //rebond sur raquette gauche ? if ((posX<=32) && (posY<posRaqu_16+58) && (posY+10>posRaqu_16) && (deltaX<0)) { deltaX= -deltaX; // rebond sur raquette gauche if (delta_raqG_y) { // delta_raqG_y!=0 on change la pente if ((delta_raqG_y >0 && deltaY >0) || (delta_raqG_y <0 && deltaY <0)) { dy+=5; if (dy > 15) dy=15; // ne peut dépasser 15 } else { dy-=5; if (dy < 5) dy=5; // ne peut dépasser 5 } } } // rebond sur mur du bas if ((posY>=417) && (deltaY>0)) deltaY= -deltaY; // rebond sur haut de l'écran if ((posY<=10) && (deltaY<0)) deltaY= -deltaY; //*********** calcul du rebond sur mur1 bounceOffTheWall(posX,posY,level,3,tabmur1,&deltaX,&deltaY,&line1); //*********** calcul du rebond sur mur2 bounceOffTheWall(posX,posY,level,6,tabmur2,&deltaX,&deltaY,&line2); //*********** Début de Brensenham e2 = err; if (e2 >-dx) { err -= dy; posX += deltaX; } if (e2 < dy) { err += dx; posY += deltaY; } setXY(posX,posY); //*********** fin de Bresenham // gestion des raquettes 2bits PORTB/raquette delta_raqG_y=0; if (bit_is_set(PINB,PINB6)) if (raqG_y<182) delta_raqG_y=1; if (bit_is_set(PINB,PINB7)) if (raqG_y>0) delta_raqG_y=-1; raqG_y = raqG_y + delta_raqG_y; PORTC=raqG_y; raqD_y = posY>>1; if (raqD_y>182) raqD_y=182; DDRC=raqD_y; // you want to see the walls : PORTA = line1; //update the wall number 1 DDRA = line2; //update the wall number 2 My_delay(tempo); } // end of while (posX>30&& (line1 || line2)) : fin des niveaux // managing levels in BCD if (posX>30) {// remove for easier checks level++; // remove the comment below if you want speed increases with level // tempo -=20; // managing level with 2 digits if ((level & 0X0F) > 9) { dizG++; level = dizG <<4; } // end if if (dizG > 9) {dizG=0;level=0;} } // end if if (level== 3) line1 = 0xFF; // mur 1 if (level == 2||level== 4) line1 = 0xAA; if (level >= 5) { line2 = 0xFF; // ligne2 line1 = 0xFF; // ligne1 } //********************************************************* // Rien de particulier n'est fait à partir du niveau 7 !!!! // On pourrait frapper plusieurs coups pour éteindre une brique // avec changement de couleurs... Voir futur projet 2012/2013 //********************************************************* // updating walls PORTA = line1; //update the wall number 1 DDRA = line2; //update the wall number 2 } //end while(1) } //end main //****************************************************************************************************************************** // function setXY() // purpose: put the ball with x and y coordinates // arguments: // corresponding x and y coordinates // return: // note: //****************************************************************************************************************************** void setXY(uint16_t x,unsigned int y){ DDRD=x; //least significant byte PORTD=x>>8;//most significant byte DDRB=y; //least significant byte PORTB=y>>8;//most significant byte } //****************************************************************************************************************************** // function PseudoAleat() // purpose: simple random generator // arguments: // corresponding modulo = nb different values :12 for us // return: // note: //****************************************************************************************************************************** unsigned char PseudoAleat(uint16_t Lim){ static uint16_t Y = 1; Y = (Y * 32719 + 3) % 32749; return ((Y % Lim) + 4); // offset de 4 } //****************************************************************************************************************************** // function My_delay() // purpose: time consuming function to waste time // arguments: // corresponding delay // return: // note: //****************************************************************************************************************************** void My_delay(unsigned int delay){ int i; for(i=0;i<delay;i++) _delay_ms(1); } //****************************************************************************************************************************** // function bounceOffTheWall() // purpose: to bounce off the wall if necessary // arguments: // corresponding coordinates of the ball : posX and posY // level : the current level of the game // levelMin : from this level on, only a left bounce can destroy a break // tableauData : data array of the corresponding wall under investigation // current and calculated coordinates differences : *delatX,*deltaY // current and calculated bits for the breaks : mur (wall in English) // return: // note: //****************************************************************************************************************************** void bounceOffTheWall(unsigned int posX,unsigned int posY,unsigned char level,unsigned char levelMin, struct s_brique tableauData[],signed char *deltaX,signed char *deltaY,unsigned char *mur) { //levelMin = 3 pour premier mur, = 6 pour deuxieme mur unsigned char i; // compteur de boucle //tableauData[0].xdeb=GX1-10 if (posX==tableauData[0].xdeb && level > 0 && *mur != 0) // rebond avec effacement for(i=0;i<8;i++) if (posY>=tableauData[i].ydeb && posY <= tableauData[i].yfin && (*mur & 1<<i) && *deltaX >0) { *deltaX = -*deltaX; // rebond *mur &= ~(1<<i); // on éteint la brique } if (posX==tableauData[0].xfin && level > 0) // rebond parfois sans effacement for(i=0;i<8;i++) if (posY>=tableauData[i].ydeb && posY <= tableauData[i].yfin && (*mur & 1<<i) && *deltaX <0) { *deltaX = -*deltaX; // rebond if (level < levelMin) *mur &= ~(1<<i); // on efface la brique } if (posX > (tableauData[0].xdeb) && posX < (tableauData[0].xfin) && level > 0) { // possibilité de rebond vertical sur brique if( *deltaY > 0) { // rebond par le haut for(i=1;i<8;i++) //pas brique du haut if (posY == tableauData[i].ydeb && (*mur & 1<<i) ) { //tab[i].ydeb contient déjà le -12 *deltaY = -*deltaY; // rebond if (level < levelMin) *mur &= ~(1<<i); // on efface la brique } } else //autrement change de signe sans arret // rebond par le bas for(i=0;i<7;i++) //pas brique du bas if (posY == tableauData[i].yfin && (*mur & 1<<i) ) { *deltaY = -*deltaY; // rebond if (level < levelMin) *mur &= ~(1<<i); // on efface la brique } } }
- Cette version gère correctement 7 niveaux de jeux : après le septième niveau tout est comme au septième.
- pour le niveau 2 et 4 on est parti du principe qu'il était plus difficile de "descendre" 4 briques que 8 ce qui est faux ! a revoir donc !
- Ce programme tient dans un peu plus de 2ko : comme nous disposons de 8 ko, nous voyons qu'il est possible de l'améliorer nettement.
- Ce programme manque de jouabilité : quand vous avez une brique à "descendre" vous pouvez certes modifier la pente du rebond mais comme la raquette droite le fait de manière aléatoire, cela rend difficile la visée. Il faudrait peut être remettre en cause le rebond aléatoire sur la raquette de droite !!!
- On ne gère par contre aucun score : ce sera certainement réalisé l'année prochaine avec un affichage en mode caractères.
[modifier] Conclusion
Ce travail a été donné à deux étudiants pour 60 heures de projet. La partie matérielle a été réalisée en 30 heures, comme prévu à l'origine. Nous rappelons qu'il s'agissait de partir de la partie matérielle du jeu de Pong et de la modifier pour le casse briques.
La partie logicielle qu'ils ont développé gérait :
- les rebonds sur les deux raquettes
- les rebonds sur les deux murs quand la balle venait de la gauche ou de la droite avec destruction de la brique correspondante.
Aucun niveau n'était géré.
Les rebonds hauts et bas sur les briques n'ont pas été gérés.
Il manquait probablement une trentaine d'heures pour aboutir à la correction donnée dans ce chapitre, qui est celle de l'enseignant tuteur.
Du point de vue programmation, ce casse briques est devenu un peu complexe pour des étudiants de niveau L2.
[modifier] Projet casse-briques (suite) pour 2012/2013
Cette section utilise les RAM spécifiques des F.P.G.A. de chez Xilinx. Il est donc pas inutile d'en rappeler la terminologie (déjà évoquée dans le chapitre Interfaces VGA et PS/2).
Terminologie Xilinx
On appellera dans la suite :
- RAMB4 un RAM/ROM de 4 kbits
- RAMB16 un RAM/ROM de 16 kbits
- RAMB16_S18 une RAMB16 avec 18 bits de données (2 ko) : 16 bits et deux bits de parité non utilisés pour nos besoins.
- RAMB16_S18_S9 une RAMB16 avec deux PORTs indépendants 18 bit de données (16 kbits) pour la partie reliée au processeur et 9 bits pour la partie reliée au FPGA.
Nous allons améliorer la partie matérielle du projet précédent de trois manières :
- affichage en mode texte dans la partie basse : score sur 4 digits et level sur deux digits.
- interfaçage au cœur AVR pour pouvoir mettre à jour ce score et ce level.
Faute de temps, nous ne voulons pas laisser les étudiants réaliser une partie matérielle trop importante : sur les 60 heures de projet, nous ne voulons en aucun cas dépasser les 30 heures de conception matérielle. Nous allons ainsi leur donner la gestion VGA toute faite. Il faudra donc réaliser l'interface avec 4 PORTs de l'AVR pour pouvoir écrire dans la mémoire et pouvoir ainsi changer les valeurs numériques.
[modifier] Peut-on gagner de la mémoire RAM ?
Nous avons déjà eu l'occasion de présenter les diverses modifications que nous avons réalisé sur la mémoire programme pour pouvoir utiliser data2mem (voir le le chapitre correspondant). Cette année il nous faut réaliser un travail un peu identique sur la mémoire RAM.
La mémoire RAM de l'ATMega8 a une taille de 1 ko (celui qui est vendu par ATMEL). Dans le cœur original de chez OpenCore cette RAM est réalisée à l'aide de quatre RAMB4_S4_S4 (possédant deux PORTs de 4 bits soit 4ko en tout). En clair nous avons plus de mémoire RAM que prévu : c'est bien. Mais est-ce que le compilateur C est capable de l'utiliser ?
D'un autre côté quel gaspillage ! Le F.P.G.A. spartan 3 utilisé ne possède que des RAMB16 mais chaque bloc de RAMB4 prend en fait un bloc de RAMB16. En clair on gaspille 16 ko pour en faire 4 ko !!! Le problème c'est que la ROM programme plus la RAM ainsi réalisée utilisent toutes les RAMB16 du spartan3 !!! Or il nous faut réaliser une ROM de caractères pour afficher notre texte.
Si l'on prend en compte les programmes déjà réalisés, on peut s'apercevoir qu'ils ne sont pas très consommateurs de RAM : ainsi l'idée consistant à remplacer 4 RAMB4 par une RAMB16 de 2ko ne pénalisera certainement pas nos programmes. Cela libère ainsi 3 RAMB16 : une sera entièrement utilisée par notre ROM de caractères, une autre sera utilisée pour les briques et le texte à afficher. Il nous en reste une pour faire évoluer cet ensemble.
Cette modification a déjà été réalisée dans la correction du projet précédent (celui de 2011/2012 voir le répertoire /CorrProjet2011 du fichier ATMega8_pong_VGA.zip si vous utilisez le fichier vgaTopCassebrique2.vhd en lieu et place de vgaTopCassebrique.vhd)
[modifier] Travail à réaliser
Comme d'habitude ce travail se décompose en une partie matérielle et une partie logicielle.
[modifier] Partie matérielle
La connexion de PORTs pour l'ATMega8 a déjà été évoqué dans le projet précédent. On rappelle donc que le projet 2011 a réalisé la connexion du module VGA de la manière suivante :
Nous allons présenter maintenant ce qu'il va vous falloir réaliser.
Comparez les deux figures avant de commencer quoi que ce soit. Comme d'habitude les (+) désignent des entrées ou sorties à ajouter et les (-) la même chose mais à retirer. Nous avons retirés tous les + de l'année dernière car tout est déjà prêt cette année.
- choix technologiques
-
E/S module VGA E/S AVR x_rect<9:8> PORTD<1:0> x_rect<7:0> DDRD<7:0> y_rect<9:8> PORTB<1:0> y_rect<7:0> DDRB<7:0> y_raqG<7:0> PORTC<7:0> y_raqD<7:0> DDRC<7:0> ligne1<7:0> PORTA<7:0> ligne2<7:0> DDRA<7:0> AddrL<7:0> TWAR<7:0> AddrH<7:0> TWDR<7:0> Data<7:0> ADCL<7:0> CommandBus<7:0> ADCH<7:0>
Nous avons donc choisi les tout premiers registres non utilisés. Ceci est réalisé dans le fichier io2.vhd avec :
-- IO write process
--
iowr: process(I_CLK)
begin
if (rising_edge(I_CLK)) then
if (I_CLR = '1') then
L_RX_INT_ENABLED <= '0';
L_TX_INT_ENABLED <= '0';
elsif (I_WE_IO = '1') then
case I_ADR_IO is
when X"22" => AddrL <= I_DIN; --TWAR
when X"23" => AddrH <= I_DIN; --TWDR
when X"24" => Data <= I_DIN; --ADCL
when X"25" => CommandBus <= I_DIN; --ADCH
when X"31" => Balle_xLow <= I_DIN; --DDRD
when X"32" => Balle_xHigh <= I_DIN; --PORTD
when X"37" => Balle_yLow <= I_DIN; --DDRB
when X"38" => Balle_yHigh <= I_DIN; --PORTB
when X"34" => raqD_y <= I_DIN; --DDRC
when X"35" => raqG_y <= I_DIN; --PORTC
when X"3B" => s_ligne1 <= I_DIN; -- PORTA
when X"3A" => s_ligne2 <= I_DIN; -- DDRA
-- when X"3D" => s_scoreg <= I_DIN; -- EEDR : EEPROM Data Register
when X"40" => -- handled by uart
when X"41" => -- handled by uart
when X"43" => L_RX_INT_ENABLED <= I_DIN(0);
L_TX_INT_ENABLED <= I_DIN(1);
when others =>
end case;
end if;
end if;
end process;
Voila en quatre points le travail à réaliser en VHDL :
- Éventuellement, modifier le fichier vgaTopCasseBrique2.vhd pour ramener le contenu de la mémoire RAMB16_S9, qui contient le texte à afficher, en adresse 0.
- Ajouter quatre PORTs de sortie au cœur ATMega8 dans le fichier io2.vhd. Trois PORTs peuvent suffire car nous n'aurons jamais à écrire au-delà de 256 octets (8 bits d'adresse).
- Ajouter un PORT à la RAMB16_S9 en la transformant en RAMB16_S9_S9 dans le fichier vgaTopCasseBrique.vhd
- Connecter les trois ou quatre PORTs de l'ATMega8 au PORT ajouté de la RAMB16_S9_S9.
[modifier] Partie logicielle
En commençant par réaliser une balle qui rebondit correctement sur les raquettes, vous pourrez améliorer votre programme petit à petit pour que votre balle soit capable de rebondir sur des briques en les détruisant. Affiner ensuite vos rebonds sur les briques en particulier avec les rebonds sur les faces horizontales des briques.... Gérer ensuite l'affichage du "level" et pour finir celui du "score" à votre convenance.
[modifier] Projet pacman pour 2012/2013
La partie gestion d'écran pour pacman est en cours de développement, mais nous n'avons pas encore décidé avec quel processeur nous allons la piloter. Pour le moment vous pouvez lire :
- pacman dans wikipédia qui vous rappelle les règles et la terminologie associée.
- qu'appelle-t-on un sprite dans un jeu vidéo ?
- Construction de la gestion d'écran correspondant dans ce livre.
- le site pacman chez opencores semble intéressant. Il s'agit d'un pacman complet, sans processeur et en verilog.