Very High Speed Integrated Circuit Hardware Description Language/Travail pratique/TPs ATTiny861 avec Altera

Début de la boite de navigation du travail pratique

Nous allons présenter dans ce chapitre une série de 6 TPs réalisés avec une carte Altera DE2-115. Il s'agit de réaliser un compteur de passages d’abord sans processeur puis avec un processeur sans périphérique particulier. On ajoutera ensuite petit à petit des périphériques.

En raison de limitations techniques, la typographie souhaitable du titre, « Travail pratique : TPs ATTiny861 avec Altera
Very High Speed Integrated Circuit Hardware Description Language/Travail pratique/TPs ATTiny861 avec Altera
 », n'a pu être restituée correctement ci-dessus.

Pour information, ces TPs ont été réalisés avec un format de 6 TPs de durée 1h30 et des étudiants de deuxième année de Génie Électrique (2015/2016). Avec ce format, la seule chose qui peut être réalisée est du TP dirigé ! Il faudrait deux ou trois heures par séance pour un fonctionnement plus interactif avec une plus grande autonomie des étudiants. Le sixième TP n'a pas été réalisé mais a été remplacé par le septième qui est une évaluation. L'objectif était de montrer à des étudiants la possibilité d’utiliser des périphériques sophistiqués pour simplifier la programmation. Il a donc été partiellement atteint avec le TP 5.

Pour éviter la création d'un autre chapitre, nous avons complété cette série par une autre série de 6 TPs qui seront réalisés dans les mêmes conditions que la première série. Ces TPs seront numérotés TP1b, TP2b, ... et TP6b et auront pour thème la réalisation partielle d'un réveil sur des afficheurs 7 segments.

Puis... nous avons encore créé une série de 6 TPs avec un thème similaire : le réveil. Sa sortie est par contre réalisée sur l'afficheur LCD de 2x16 caractères. Ils seront numérotés de TP1c à TP6c. Ils ont été réalisés en 2016/2017 par des étudiants de GEII 2ᵉ année.

Introduction modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7. La série d'exercices proposée ici peut certainement être réalisée avec d'autres cartes terasIC, comme la DE-2 et même probablement la DE-1. La seule chose qu’il vous faudra adapter sera le fichier de contraintes. Pour le reste, rien à changer !

Le processeur embarqué qui est utilisé dans ces séries de TPs a été conçu par Andreas Hilvarsson. Il a écrit ce cœur ATTinyx61 et l'a publié chez Opencores.org. Nous l'utiliserons avec une mémoire programme de 8ko, d'où l'appellation ATTiny861 dans ce cours. Il sera programmé en C.

Le compteur de passages est évoqué dans un autre livre : Compteur de passages revu et corrigé. Il sera le fil conducteur de la première série de TPs (TP1 à TP7).

Le réveil sera abordé dans la deuxième série de TPs (TP1b à TP6b) comme dans la troisième série (TP1c à TP6c). La différence entre les deux séries est l'affichage : soit sur des afficheurs sept segments soit sur un afficheur lcd.

Nous allons, dans cette première série de TPs, construire d’abord complètement un compteur de passages sans processeur. Une fois terminé, nous allons utiliser un processeur (embarqué) sans périphérique particulier. Pour terminer cette série, nous allons d’abord déporter le transcodage vers l'extérieur, puis l’ensemble des deux compteurs BCD et des deux transcodeurs. L'objectif de ce travail est donc de bien comprendre les rapports entre le matériel et le logiciel pour des exemples relativement simples.

TP 1 (1h30) modifier

Exercice 1 modifier

On vous demande simplement de réaliser un transcodeur pour afficher tout nombre sur 4 bits (entrée) sur un afficheur 7 segments. Avec notre carte DE2-115, pour allumer un segment il faut mettre un '0' sur la broche correspondante. Une autre caractéristique est l'absence de multiplexage des afficheurs sept segments. Pour information il y en a 8 sur la carte en question et cela nécessite donc 8x7=56 broches de FPGA.

Indication 1 modifier

Vous devez réaliser l'architecture correspondante pour l'entité VHDL suivante :

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- zero pour allumer les LEDs
entity transcod7segs is
    port (  
            I_in4    : in  std_logic_vector(3 downto 0);
				-- Ordre : gfedcba
            Q_7segs  : out std_logic_vector(6 downto 0)
    );
end transcod7segs;

Si le nom des entrées sorties ne vous convient pas, changez-les mais assumez alors ces changements lors des nombreux câblages de ce transcodeur. Tous nos schémas gardent cette convention de noms, à commencer par le fichier de contraintes que nous donnons maintenant.

Indication 2 modifier

Le fichier de contraintes sera :

To,Direction,Location,I/O Bank,VREF Group,I/O Standard,Reserved
Q_7segs[6],Output,PIN_H22,6,B6_N0,2.5 V,
Q_7segs[5],Output,PIN_J22,6,B6_N0,2.5 V,
Q_7segs[4],Output,PIN_L25,6,B6_N1,2.5 V,
Q_7segs[3],Output,PIN_L26,6,B6_N1,2.5 V,
Q_7segs[2],Output,PIN_E17,7,B7_N2,2.5 V,
Q_7segs[1],Output,PIN_F22,7,B7_N0,2.5 V,
Q_7segs[0],Output,PIN_G18,7,B7_N2,2.5 V,

I_in4[3],Input,PIN_AD27,5,B5_N2,2.5 V,
I_in4[2],Input,PIN_AC27,5,B5_N2,2.5 V,
I_in4[1],Input,PIN_AC28,5,B5_N2,2.5 V,
I_in4[0],Input,PIN_AB28,5,B5_N1,2.5 V,

L'enseignant vous expliquera comment trouver ces contraintes avec la documentation de la carte.

Exercice 2 modifier

 
Deux transcodeurs sept segments

Réaliser la même chose avec deux afficheurs. On aura donc maintenant 8 entrées et 14 sorties. On vous demande cette réalisation avec deux composants correspondant à l'exercice 1 (transcodeurs)

Le fichier de contraintes sera :

To,Direction,Location,I/O Bank,VREF Group,I/O Standard,Reserved
Unit7segs[6],Output,PIN_H22,6,B6_N0,2.5 V,
Unit7segs[5],Output,PIN_J22,6,B6_N0,2.5 V,
Unit7segs[4],Output,PIN_L25,6,B6_N1,2.5 V,
Unit7segs[3],Output,PIN_L26,6,B6_N1,2.5 V,
Unit7segs[2],Output,PIN_E17,7,B7_N2,2.5 V,
Unit7segs[1],Output,PIN_F22,7,B7_N0,2.5 V,
Unit7segs[0],Output,PIN_G18,7,B7_N2,2.5 V,
Diz7segs[6],Output,PIN_U24,5,B5_N0,2.5 V,
Diz7segs[5],Output,PIN_U23,5,B5_N1,2.5 V,
Diz7segs[4],Output,PIN_W25,5,B5_N1,2.5 V,
Diz7segs[3],Output,PIN_W22,5,B5_N0,2.5 V,
Diz7segs[2],Output,PIN_W21,5,B5_N1,2.5 V,
Diz7segs[1],Output,PIN_Y22,5,B5_N0,2.5 V,
Diz7segs[0],Output,PIN_M24,6,B6_N2,2.5 V,

sw[7],Input,PIN_AB26,5,B5_N1,2.5 V,
sw[6],Input,PIN_AD26,5,B5_N2,2.5 V,
sw[5],Input,PIN_AC26,5,B5_N2,2.5 V,
sw[4],Input,PIN_AB27,5,B5_N1,2.5 V,
sw[3],Input,PIN_AD27,5,B5_N2,2.5 V,
sw[2],Input,PIN_AC27,5,B5_N2,2.5 V,
sw[1],Input,PIN_AC28,5,B5_N2,2.5 V,
sw[0],Input,PIN_AB28,5,B5_N1,2.5 V,

TP 2 (1h30) modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7.

Exercice 1 modifier

En vous aidant du compteur décompteur décimal présenté ici, on vous demande de compléter le code pour faire un compteur décimal cascadable.

Exercice 2 modifier

 
Test des compteurs BCD cascadés

Le compteur cascadable de l'exercice 1 doit être testé. Pour cela vous devez lui envoyer une horloge lente. Vous allez donc assembler :

  • un compteur destiné à réaliser une horloge lente (division par 2**24)
  • deux compteurs décompteurs décimaux cascadés
  • deux transcodeurs

Le fichier de contraintes sera :

To,Direction,Location,I/O Bank,VREF Group,I/O Standard,Reserved
clk,Input,PIN_Y2,2,B2_N0,3.3-V LVTTL,
Init,Input,PIN_Y23,5,B5_N2,2.5 V,
Unit7segs[6],Output,PIN_H22,6,B6_N0,2.5 V,
Unit7segs[5],Output,PIN_J22,6,B6_N0,2.5 V,
Unit7segs[4],Output,PIN_L25,6,B6_N1,2.5 V,
Unit7segs[3],Output,PIN_L26,6,B6_N1,2.5 V,
Unit7segs[2],Output,PIN_E17,7,B7_N2,2.5 V,
Unit7segs[1],Output,PIN_F22,7,B7_N0,2.5 V,
Unit7segs[0],Output,PIN_G18,7,B7_N2,2.5 V,
Diz7segs[6],Output,PIN_U24,5,B5_N0,2.5 V,
Diz7segs[5],Output,PIN_U23,5,B5_N1,2.5 V,
Diz7segs[4],Output,PIN_W25,5,B5_N1,2.5 V,
Diz7segs[3],Output,PIN_W22,5,B5_N0,2.5 V,
Diz7segs[2],Output,PIN_W21,5,B5_N1,2.5 V,
Diz7segs[1],Output,PIN_Y22,5,B5_N0,2.5 V,
Diz7segs[0],Output,PIN_M24,6,B6_N2,2.5 V,
DownUp,Input,PIN_AC28,5,B5_N2,2.5 V,
en,Input,PIN_AB28,5,B5_N1,2.5 V,

Ce fichier de contraintes correspond à "en" interrupteur complètement à droite, "DownUp" juste à côté et "Init" complètement à gauche.

TP 3 (1h30) modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7.

Le compteur de passages comporte deux entrées capteurs notés CapteurDroit et CapteurGauche qui sont supposés détecter un passage. Pour nous ce sera deux interrupteurs. L'objectif du montage est de compter le nombre de personnes dans une pièce (à une seule entrée) ou de voitures dans un parking (lui aussi à une entrée). On considère donc que lorsqu'on passe devant un capteur puis devant l'autre on entre dans la pièce (ou dans le parking) et lorsque les choses se passent dans l'autre sens on sort. Un séquenceur devra être couplé à un compteur décompteur pour réaliser ce cahier des charges.

Exercice 1 modifier

 
Séquenceur du compteur de passages

Réaliser le séquenceur en complétant le code correspondant trouvé ICI dans un autre livre. Vous allez ensuite assembler :

  • un compteur destiné à réaliser une horloge lente (division par 2**20) : ce sera l'horloge générale
  • un séquenceur
  • deux compteurs décompteurs décimaux cascadés
  • deux transcodeurs

Le fichier de contrainte sera :

To,Direction,Location,I/O Bank,VREF Group,I/O Standard,Reserved
clk_50MHz,Input,PIN_Y2,2,B2_N0,3.3-V LVTTL,
Init,Input,PIN_Y23,5,B5_N2,2.5 V,
Unit7segs[6],Output,PIN_H22,6,B6_N0,2.5 V,
Unit7segs[5],Output,PIN_J22,6,B6_N0,2.5 V,
Unit7segs[4],Output,PIN_L25,6,B6_N1,2.5 V,
Unit7segs[3],Output,PIN_L26,6,B6_N1,2.5 V,
Unit7segs[2],Output,PIN_E17,7,B7_N2,2.5 V,
Unit7segs[1],Output,PIN_F22,7,B7_N0,2.5 V,
Unit7segs[0],Output,PIN_G18,7,B7_N2,2.5 V,
Diz7segs[6],Output,PIN_U24,5,B5_N0,2.5 V,
Diz7segs[5],Output,PIN_U23,5,B5_N1,2.5 V,
Diz7segs[4],Output,PIN_W25,5,B5_N1,2.5 V,
Diz7segs[3],Output,PIN_W22,5,B5_N0,2.5 V,
Diz7segs[2],Output,PIN_W21,5,B5_N1,2.5 V,
Diz7segs[1],Output,PIN_Y22,5,B5_N0,2.5 V,
Diz7segs[0],Output,PIN_M24,6,B6_N2,2.5 V,
CapteurGauche,Input,PIN_AC28,5,B5_N2,2.5 V,
CapteurDroit,Input,PIN_AB28,5,B5_N1,2.5 V,

CapteurDroit est l'interrupteur complètement à droite, CapteurGauche est juste à côté tandis que Init est complètement à gauche.

 
Aperçu général du compteur de passages

Voici en schéma ce que vous devez réaliser.


Exercice 2 modifier

Changer le séquenceur pour laisser la possibilité de réaliser un demi-tour.

TP 4 (1h30) modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7.

 
Aperçu fonctionnel de notre SOC (Tiny861) au départ

Indication : Pour la mise à jour du contenu de la mémoire seulement, sans passer par un temps de recompilation complet de l’application (donc plus ou moins équivalent à data2mem), il faut valider l'option "use smart compilation". Pour y accéder : menu assignements => settings => compilation process settings => puis cocher l'option. Ne pas oublier de faire "apply" avant de quitter la fenêtre !

Vous allez maintenant réaliser vos premiers programmes en C destinés à un processeur dans le FPGA. Le code source complet du processeur vous est donné. Vous allez donc réaliser un projet pour compiler ce processeur. Cette compilation peut être assez longue (près de 10 min) mais la simple mise en RAM/ROM du programme ne prendra que 2 min une fois cette première compilation réalisée.

Voici sous forme schématique l’ensemble du processeur.

Ressources modifier

Andreas Hilvarsson a écrit ce cœur ATTiny861 et l'a publié chez Opencores.org. Nous avons modifié sa façon d'y créer des périphériques et en particulier retiré tous les PORTs bidirectionnels qui ne servent à rien dans un FPGA. Nous en avons fait aussi une version directement utilisable pour les circuits Altera.

  L'hébergement de mon site perso se termine le 5 septembre 2023 ! A ce jour je n'ai pas encore décidé comment je vais gérer ce problème dont je ne suis pas à l'origine. Il en résulte que les liens de l'ensemble des corrections qui utilisent mon site perso seront indisponibles à partir de cette date pour tout ce livre. Cela concerne entre autre la remarque ci-dessous !


Mon site n'étant pas indéfiniment disponible, nous en publions ici une version utilisée dans ce TP. Les modifications citées n'ont été réalisées que dans le fichier "microcontroleur.vhd".

Fichier top modifier


Fichier de réalisation du cœur modifier

Fichier mémoire RAM modifier

Fichier mémoire ROM modifier

Ce fichier est donné et expliqué dans l'annexe I plus loin.

Fichier de contraintes modifier

Nous donnons le fichier de contraintes sous la forme csv. Il vous faudra importer ce fichier pour qu’il soit pris en compte.

To,Direction,Location,I/O Bank,VREF Group,I/O Standard,Reserved
clk,Input,PIN_Y2,2,B2_N0,3.3-V LVTTL,
Rst,Input,PIN_Y23,5,B5_N2,2.5 V,
Aff7segs[6],Output,PIN_H22,6,B6_N0,2.5 V,
Aff7segs[5],Output,PIN_J22,6,B6_N0,2.5 V,
Aff7segs[4],Output,PIN_L25,6,B6_N1,2.5 V,
Aff7segs[3],Output,PIN_L26,6,B6_N1,2.5 V,
Aff7segs[2],Output,PIN_E17,7,B7_N2,2.5 V,
Aff7segs[1],Output,PIN_F22,7,B7_N0,2.5 V,
Aff7segs[0],Output,PIN_G18,7,B7_N2,2.5 V,
Diz7segs[6],Output,PIN_U24,5,B5_N0,2.5 V,
Diz7segs[5],Output,PIN_U23,5,B5_N1,2.5 V,
Diz7segs[4],Output,PIN_W25,5,B5_N1,2.5 V,
Diz7segs[3],Output,PIN_W22,5,B5_N0,2.5 V,
Diz7segs[2],Output,PIN_W21,5,B5_N1,2.5 V,
Diz7segs[1],Output,PIN_Y22,5,B5_N0,2.5 V,
Diz7segs[0],Output,PIN_M24,6,B6_N2,2.5 V,
Led[7],Output,PIN_H19,7,B7_N2,2.5 V,
Led[6],Output,PIN_J19,7,B7_N2,2.5 V,
Led[5],Output,PIN_E18,7,B7_N1,2.5 V,
Led[4],Output,PIN_F18,7,B7_N1,2.5 V,
Led[3],Output,PIN_F21,7,B7_N0,2.5 V,
Led[2],Output,PIN_E19,7,B7_N0,2.5 V,
Led[1],Output,PIN_F19,7,B7_N0,2.5 V,
Led[0],Output,PIN_G19,7,B7_N2,2.5 V,
sw[7],Input,PIN_AB26,5,B5_N1,2.5 V,
sw[6],Input,PIN_AD26,5,B5_N2,2.5 V,
sw[5],Input,PIN_AC26,5,B5_N2,2.5 V,
sw[4],Input,PIN_AB27,5,B5_N1,2.5 V,
sw[3],Input,PIN_AD27,5,B5_N2,2.5 V,
sw[2],Input,PIN_AC27,5,B5_N2,2.5 V,
sw[1],Input,PIN_AC28,5,B5_N2,2.5 V,
sw[0],Input,PIN_AB28,5,B5_N1,2.5 V,
In_PINB[7],Input,PIN_AA22,5,B5_N2,2.5 V,
In_PINB[6],Input,PIN_AA23,5,B5_N2,2.5 V,
In_PINB[5],Input,PIN_AA24,5,B5_N2,2.5 V,
In_PINB[4],Input,PIN_AB23,5,B5_N2,2.5 V,
In_PINB[3],Input,PIN_AB24,5,B5_N2,2.5 V,
In_PINB[2],Input,PIN_AC24,5,B5_N2,2.5 V,
In_PINB[1],Input,PIN_AB25,5,B5_N1,2.5 V,
In_PINB[0],Input,PIN_AC25,5,B5_N2,2.5 V,

Ce fichier pourra être utilisé pour toute la partie processeur du TP.

Pour information modifier

Pour information la réalisation des périphériques en sortie a été réalisée comme dans la figure ci-contre. Rappelez-vous que la réalisation de périphérique de sortie se fait dans le fichier microcontroleur.vhd et dans le process iowr... et que c’est ce qui est montré dans cette figure.

 
Périphériques au départ du TP

Exercices modifier

Voici un exemple de programme C :

#include "avr/io.h"
#undef F_CPU 
#define F_CPU 15000000UL
#include "util/delay.h"

//#define UCSRB	_SFR_IO8(0x01) 
//#define UCSRA	_SFR_IO8(0x02) 
//#define UDR	_SFR_IO8(0x03)
// UCSRA
//#define RXC 7
//#define TXC 6
//#define UDRE 5
//UCSRB
//#define RXEN 4
//#define TXEN 3


//***********************************************************************
// main 
//*********************************************************************** 

 int main (void) {
   unsigned char ch=128; 
   while(1) { 
   // echo simple
     PORTA = ch;
     ch >>= 1; 
     if (ch == 0) ch = 128;
     _delay_ms(300); // on défiler les valeurs     
   } 
   return 0; 
 }

Repérez dans ce code comment ne pas aller trop vite, comment décaler une valeur, comment sortir sur les leds....

Exercice 1 modifier

Vous allez réaliser divers chenillards dans un premier temps :

  • chenillard gauche droite (très facile non ?)
  • chenillard droite gauche
  • chenillard droite et gauche simultanés
  • chenillard à accumulation

Exercice 2 modifier

On vous donne deux sous-programmes facilitant cet exercice :

void incrementBCD(unsigned char *cnt) { 
  (*cnt)++;    
  if ((*cnt & 0x0F) > 0x09) *cnt += 6; 
  if ((*cnt & 0xF0) > 0x90) *cnt = 0; 
} 

void decrementBCD(unsigned char *cnt) { 
  (*cnt)--;    
  if ((*cnt & 0x0F) == 0x0F) *cnt -= 6; 
  if ((*cnt & 0xF0) == 0xF0) *cnt = 0x99; 
}

ainsi qu'un tableau de valeurs précalculées

const unsigned char digit7segs[16]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};

Vous allez réaliser divers compteurs et utiliser le ou les afficheurs sept segments.

  • compteur binaire assez lent pour que l’affichage se fasse correctement en hexadécimal sur deux digits
  • compteur décimal sur deux digits

Notez que c’est à vous, programmeur, de réaliser le transcodage. Un moyen simple de faire cela est d’utiliser un tableau. Ce n'est peut être pas un hasard si l’on vous a donné un tableau.

Exercice 3 modifier

Réaliser le compteur de passages. On vous demande de repérer dans le code ci-dessous la réalisation du séquenceur.

#include "avr/io.h"
#undef F_CPU 
#define F_CPU 15000000UL
#include "util/delay.h"

//#define UCSRB	_SFR_IO8(0x01) 
//#define UCSRA	_SFR_IO8(0x02) 
//#define UDR	_SFR_IO8(0x03)
// UCSRA
//#define RXC 7
//#define TXC 6
//#define UDRE 5
//UCSRB
//#define RXEN 4
//#define TXEN 3

//const unsigned char digit7segs[16]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E}; 
void incrementBCD(unsigned char *cnt);
void decrementBCD(unsigned char *cnt);
//***********************************************************************
// main 
//*********************************************************************** 

 int main (void) {
   //unsigned char transcod7segs[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0xFF,0x00};
   unsigned char transcod7segs[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};

   unsigned char cmpt=0,ch=128,swPresent=0,swPasse=0,etat=1; 
   while(1) { 
   // compteur simple
     PORTB = transcod7segs[cmpt&0x0F];
     DDRB = transcod7segs[(cmpt&0xF0)>>4];
     swPresent = PINA;
     switch (etat) {
        case 0x01 : if (((swPresent & 0x03)==0x01) && ((swPasse & 0x01)==0x00)) {etat = 0x02;break;}
                    if (((swPresent & 0x03)==0x02) && ((swPasse & 0x02)==0x00)) {etat = 0x08;break;}    
        case 0x02 : if (((swPresent & 0x03)==0x02) && ((swPasse & 0x02)==0x00)) etat = 0x04;break;
        case 0x04 : etat = 0x01; break;        
        case 0x08 : if (((swPresent & 0x03)==0x01) && ((swPasse & 0x01)==0x00)) etat = 0x10;break;
        case 0x10 : etat = 0x01; break;
        default : etat = 0x01;
      }
      if (etat==0x04) incrementBCD(&cmpt);
      if (etat==0x10) decrementBCD(&cmpt);
      swPasse = swPresent;
     PORTA = ch;
     ch >>= 1; 
     if (ch == 0) ch = 128;
     _delay_ms(300); // on verra passer les caractères     
   } 
   return 0; 
 }

void incrementBCD(unsigned char *cnt) { 
  (*cnt)++;    
  if ((*cnt & 0x0F) > 0x09) *cnt += 6; 
  if ((*cnt & 0xF0) > 0x90) *cnt = 0; 
} 

void decrementBCD(unsigned char *cnt) { 
  (*cnt)--;    
  if ((*cnt & 0x0F) == 0x0F) *cnt -= 6; 
  if ((*cnt & 0xF0) == 0xF0) *cnt = 0x99; 
}

Modifier ce code pour être plus conforme au séquenceur du TP3 (7 états contre 5 ici).

TP 5 (1h30) modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7. Nous mettons la ressource complète sur notre site : M4209TinyStart.zip.

Nous allons déporter le transcodage du langage C vers le matériel, comme le montre la figure ci-contre.

 
Périphériques en écriture : deux transcodeurs sept segments

Vous devez remarquer sur cette figure que maintenant le PORTB (8 bits) permet de commander deux afficheurs sept segments. Votre seul problème maintenant est de réaliser un compteur BCD sur 8 bits et de sortir sa valeur dans PORTB.

Exercice 1 modifier

Réaliser la partie matérielle dans microcontroleur.vhd en ajoutant les deux transcodeurs.

Exercice 2 modifier

Réaliser C un compteur BCD qui compte ou décompte en fonction d'une entrée sur un interrupteur. Évidemment ce que l’on vous demande de faire ici, c’est un programme C qui sera compilé et chargé dans le processeur.

Exercice 3 modifier

Refaire le compteur de passages correctement. Inspirez-vous de ce que vous venez de faire dans l'exercice précédent et du compteur de passages du TP précédent.

TP 6 (1h30) modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7. Nous mettons la ressource complète sur notre site : M4209TinyStart.zip.

Nous arrivons maintenant au terme de notre série de TPs. Notre objectif maintenant est d'ajouter les deux compteurs BCD comme périphériques. Ils attaqueront les deux transcodeurs qui seront chargés de l'affichage.

 
Périphériques : deux compteurs BCD et deux transcodeurs

À partir de maintenant, fini les calculs d'additions et de soustractions BCD en C. C'est le matériel qui fera tout. Bien, le matériel fait tout mais il faut lui en donner l'ordre. Et cela, c’est de la responsabilité du processeur.

Il y a plusieurs possibilités pour réaliser cela. Nous avons choisi de réaliser cela de la manière suivante :

  • le processeur est incapable de mettre une valeur particulière dans les deux compteurs BCD
  • pour incrémenter le processeur écrit '1' dans le PORTB
  • pour décrémenter, le processeur écrit '0' dans le PORTB

Exercice 1 modifier

  • Réaliser la partie matérielle correspondant à la figure.
  • Modifier et tester le programme du compteur de passages


Exercice 2 modifier

Modifier, pour terminer, la partie matérielle pour que la lecture par le processeur des deux compteurs BCD soit possible. Réaliser maintenant un programme pour tester. Une idée possible est d'afficher la valeur lue sur les LEDs du PORTA qui ne sont pas utilisées.

TP 7 Évaluation (1h30) modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7. Nous mettons la ressource complète sur notre site : M4209TinyStart.zip.

1°) À partir de la Correction du TP6, on vous demande de montrer que vous êtes capables de :

  • faire un projet à partir de la ressource fournie
  • mettre au bon endroit le programme C donné dans la correction
  • le transformer en fichier .mif
  • compiler la partie matérielle en remplaçant le microcontroleur.vhd de la ressource par celui de la correction
  • faire le test qui montre que l’on a bien un compteur de passages

2°) Vous allez maintenant ajouter 8 leds en supplément dans votre microcontrôleur pour réaliser un chenillard sur 16 leds. Les 8 premières leds sont présentent depuis le TP4 et sont commandées par PORTA. Les 8 nouvelles seront reliées à DDRB qui n'est plus utilisé. Montrer que vous êtes capable de rajouter une sortie sur 8 bits comme indiqué dans le schéma ci-dessous :

 
Ajout d'un PORT pour utiliser 8 LEDs supplémentaires

Comme d'habitude, ce que vous avez à réaliser est indiqué en rouge. Tout ce qui est en noir est déjà réalisé dans la correction qui est accessible.

Les leds ajoutées nécessitent l'ajout des contraintes :

To,Direction,Location,I/O Bank,VREF Group,I/O Standard,Reserved
LED2[7],Output,PIN_G15,7,B7_N2,2.5 V,
LED2[6],Output,PIN_F15,7,B7_N2,2.5 V,
LED2[5],Output,PIN_H17,7,B7_N2,2.5 V,
LED2[4],Output,PIN_J16,7,B7_N2,2.5 V,
LED2[3],Output,PIN_H16,7,B7_N2,2.5 V,
LED2[2],Output,PIN_J15,7,B7_N2,2.5 V,
LED2[1],Output,PIN_G17,7,B7_N1,2.5 V,
LED2[0],Output,PIN_J17,7,B7_N2,2.5 V,

Réaliser ensuite un chenillard simple montrant le bon fonctionnement. Il devra obligatoirement être sur 16 LEDs.

  À partir de maintenant, c'est une autre série de TP qui commence.

L'objectif de ces Travaux pratiques est de réaliser partiellement un réveil. Les trois premiers TP réalisent un comptage pour réveil en logique traditionnelle avec des composants combinatoires, les transcodeurs sept segments, et des composants séquentiels, des compteurs décimaux et modulo 6. Puis nous introduirons un processeur pour faciliter la gestion du réveil.

TP1b : Réalisation d'un transcodeur sept segments modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7.

Pour commencer simplement avec l'environnement Quartus, nous allons réaliser le célèbre transcodeur 7 segments.

Exercice 1 modifier

Vous partirez du code suivant :

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
ENTITY transcod7segs IS PORT(
  e : in std_logic_vector(3 downto 0);
  s7segs : out std_logic_vector(6 downto 0));
END ENTITY transcod7segs;
ARCHITECTURE arch of transcod7segs IS 
BEGIN
  with e select
             --abcdefg
    s7segs <= "0000001" when "0000",
              "1001111" when "0001",
              "0010010" when "0010",
              "0000110" when "0011",
              "1001100" when "0100",
              "0100100" when "0101",
              "0100000" when "0110",
              "0001111" when "0111",
              "0000000" when "1000",
              "0000100" when "1001",
              "0001000" when "1010",
              "1100000" when "1011",
              "0110001" when "1100",
              "1000010" when "1101",
              "0110000" when "1110",
              "0111000" when others;
END;

Le fichier de contraintes sera :

To,Direction,Location,I/O Bank,VREF Group,I/O Standard,Reserved
s7segs[0],Output,PIN_H22,6,B6_N0,2.5 V,
s7segs[1],Output,PIN_J22,6,B6_N0,2.5 V,
s7segs[2],Output,PIN_L25,6,B6_N1,2.5 V,
s7segs[3],Output,PIN_L26,6,B6_N1,2.5 V,
s7segs[4],Output,PIN_E17,7,B7_N2,2.5 V,
s7segs[5],Output,PIN_F22,7,B7_N0,2.5 V,
s7segs[6],Output,PIN_G18,7,B7_N2,2.5 V,
e[3],Input,PIN_AD27,5,B5_N2,2.5 V,
e[2],Input,PIN_AC27,5,B5_N2,2.5 V,
e[1],Input,PIN_AC28,5,B5_N2,2.5 V,
e[0],Input,PIN_AB28,5,B5_N1,2.5 V,

Exercice 2 : Utilisation de 4 digits modifier

On désire étendre le travail réalisé en exercice 2 sur 4 digits.

Le fichier de contraintes sera :

To,Direction,Location,I/O Bank,VREF Group,I/O Standard,Reserved
DIGIT0[0],Output,PIN_H22,6,B6_N0,2.5 V,
DIGIT0[1],Output,PIN_J22,6,B6_N0,2.5 V,
DIGIT0[2],Output,PIN_L25,6,B6_N1,2.5 V,
DIGIT0[3],Output,PIN_L26,6,B6_N1,2.5 V,
DIGIT0[4],Output,PIN_E17,7,B7_N2,2.5 V,
DIGIT0[5],Output,PIN_F22,7,B7_N0,2.5 V,
DIGIT0[6],Output,PIN_G18,7,B7_N2,2.5 V,
DIGIT1[0],Output,PIN_U24,5,B5_N0,2.5 V,
DIGIT1[1],Output,PIN_U23,5,B5_N1,2.5 V,
DIGIT1[2],Output,PIN_W25,5,B5_N1,2.5 V,
DIGIT1[3],Output,PIN_W22,5,B5_N0,2.5 V,
DIGIT1[4],Output,PIN_W21,5,B5_N1,2.5 V,
DIGIT1[5],Output,PIN_Y22,5,B5_N0,2.5 V,
DIGIT1[6],Output,PIN_M24,6,B6_N2,2.5 V,
DIGIT2[0],Output,PIN_W28,5,B5_N1,2.5 V,
DIGIT2[1],Output,PIN_W27,5,B5_N1,2.5 V,
DIGIT2[2],Output,PIN_Y26,5,B5_N1,2.5 V,
DIGIT2[3],Output,PIN_W26,5,B5_N1,2.5 V,
DIGIT2[4],Output,PIN_Y25,5,B5_N1,2.5 V,
DIGIT2[5],Output,PIN_AA26,5,B5_N1,2.5 V,
DIGIT2[6],Output,PIN_AA25,5,B5_N1,2.5 V,
DIGIT3[0],Output,PIN_Y19,4,B4_N0,3.3-V LVTTL,
DIGIT3[1],Output,PIN_AF23,4,B4_N0,3.3-V LVTTL,
DIGIT3[2],Output,PIN_AD24,4,B4_N0,3.3-V LVTTL,
DIGIT3[3],Output,PIN_AA21,4,B4_N0,3.3-V LVTTL,
DIGIT3[4],Output,PIN_AB20,4,B4_N0,3.3-V LVTTL,
DIGIT3[5],Output,PIN_U21,5,B5_N0,2.5 V,
DIGIT3[6],Output,PIN_V21,5,B5_N1,2.5 V,
SW[15],Input,PIN_AA22,5,B5_N2,2.5 V,
SW[14],Input,PIN_AA23,5,B5_N2,2.5 V,
SW[13],Input,PIN_AA24,5,B5_N2,2.5 V,
SW[12],Input,PIN_AB23,5,B5_N2,2.5 V,
SW[11],Input,PIN_AB24,5,B5_N2,2.5 V,
SW[10],Input,PIN_AC24,5,B5_N2,2.5 V,
SW[9],Input,PIN_AB25,5,B5_N1,2.5 V,
SW[8],Input,PIN_AC25,5,B5_N2,2.5 V,
SW[7],Input,PIN_AB26,5,B5_N1,2.5 V,
SW[6],Input,PIN_AD26,5,B5_N2,2.5 V,
SW[5],Input,PIN_AC26,5,B5_N2,2.5 V,
SW[4],Input,PIN_AB27,5,B5_N1,2.5 V,
SW[3],Input,PIN_AD27,5,B5_N2,2.5 V,
SW[2],Input,PIN_AC27,5,B5_N2,2.5 V,
SW[1],Input,PIN_AC28,5,B5_N2,2.5 V,
SW[0],Input,PIN_AB28,5,B5_N1,2.5 V,

et vous donne le nom de vos entrées et des sorties.

TP2b : Réalisation d'un réveil HH:MN à Trois hertz modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7.

Nous disposons d'un compteur BCD sur 4 digits et nous allons réaliser un réveil en modifiant un peu l'ensemble.

Exercice 1 : Faire fonctionner l'ensemble donné modifier

 
Cascader des compteurs décimaux pour 4 digits

Nous allons réaliser ce qui est présenté dans la figure ci-contre mais sans le multiplexeur. Le retrait du multiplexeur est lié à la gestion des afficheurs sur la carte qui va nous servir pour les TPs. Sur cette carte il n'y a aucun multiplexage, c'est-à-dire qu'il est possible d'envoyer des valeurs différentes sur chacun des afficheurs sept segments.

Étant donné que chacun des compteurs a une sortie sur 4 bits et que celle-ci doit commander un affichage 7 segments, il faut donc remplacer le multiplexeur par 4 transcodeurs.

Pour vous entraîner à la lecture des "PORT MAP", un exercice intéressant est de partir du code donné ci-dessous et de refaire le schéma correspondant. Une autre manière de dire les choses est que le schéma ci-contre donne l'idée générale (cascader des compteurs BCD) mais ne représente pas complètement le code ci-dessous. Nous garderons cet étrangeté pour vous obliger à faire un dessin.

On vous donne donc le code suivant :

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Compteur4Digits is
port (
   clk : in std_logic;
   DIGIT3, DIGIT2, DIGIT1, DIGIT0 : out std_logic_vector(6 downto 0)
  );
end Compteur4Digits;

architecture arch_Compteur4Digits of Compteur4Digits is

COMPONENT cmpt24bits IS
  PORT(clk : IN STD_LOGIC;
    eno3Hz : OUT STD_LOGIC);
END COMPONENT cmpt24bits;

component CounterBCD is
   port( EN: in std_logic;
 	 Clock: in std_logic;
 	 Reset: in std_logic;
	 ENO : out std_logic;
 	 Output: out std_logic_vector(3 downto 0));
end component CounterBCD;

component transcod7segs IS PORT(
  e : in std_logic_vector(3 downto 0);
  s7segs : out std_logic_vector(6 downto 0));
END component transcod7segs;

signal s_en3Hz : std_logic;
signal s_eno, s_eno2, s_eno3 : std_logic;
signal s_eno2_heure : std_logic_vector(8 downto 0);
signal s_reset : std_logic; -- pour les heures 
signal s_data16 : std_logic_vector(15 downto 0);

begin
  i1: cmpt24bits port map (
         clk => clk,
         eno3Hz => s_en3Hz);

  bcdUnit: CounterBCD port map( 
    EN => s_en3Hz,
 	 Clock => clk,
 	 Reset => '0',
	 ENO => s_eno,
 	 Output => s_data16(3 downto 0));
  bcdDiz: CounterBCD port map( 
    EN => s_eno,
 	 Clock => clk,
 	 Reset => '0',
	 ENO => s_eno2,
 	 Output => s_data16(7 downto 4));
  bcdCent: CounterBCD port map( 
    EN => s_eno2,
 	 Clock => clk,
 	 Reset => s_reset,
	 ENO => s_eno3,
 	 Output => s_data16(11 downto 8));
  bcdMil: CounterBCD port map( 
    EN => s_eno3,
 	 Clock => clk,
 	 Reset => '0',
	 ENO => open,
 	 Output => s_data16(15 downto 12));	
  
					  
  i4: transcod7segs port map (
         e => s_data16(3 downto 0),
			s7segs =>  DIGIT0) ;
  i5: transcod7segs port map (
         e => s_data16(7 downto 4),
			s7segs =>  DIGIT1) ;
  i6: transcod7segs port map (
         e => s_data16(11 downto 8),
			s7segs =>  DIGIT2);
  i7: transcod7segs port map (
         e => s_data16(15 downto 12),
			s7segs =>  DIGIT3) ;		
end arch_Compteur4Digits;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity CounterBCD is
   port( EN: in std_logic;
 	 Clock: in std_logic;
 	 Reset: in std_logic;
	 ENO : out std_logic;
 	 Output: out std_logic_vector(3 downto 0));
end CounterBCD;
 
architecture Behavioral of CounterBCD is
   signal cmpt: std_logic_vector(3 downto 0);
   signal s_en_cmpt: std_logic_vector(4 downto 0);
begin   process(Clock,Reset)
   begin
      if(rising_edge(Clock)) then
		  if Reset='1' then
         cmpt <= "0000";
 	      elsif EN='1' then
	         if cmpt="1001" then
	            cmpt<="0000";
	         else
	           cmpt <= cmpt + 1;
	         end if;
         end if;
      end if;
   end process;
   Output <= cmpt;
	s_en_cmpt <= en & cmpt;

   with s_en_cmpt select
     ENO <= '1' when "11001",
            '0' when others;
end Behavioral;

Le fichier de contraintes sera :

To,Direction,Location,I/O Bank,VREF Group,I/O Standard,Reserved
CLK,Input,PIN_Y2,2,B2_N0,3.3-V LVTTL,
DIGIT0[0],Output,PIN_H22,6,B6_N0,2.5 V,
DIGIT0[1],Output,PIN_J22,6,B6_N0,2.5 V,
DIGIT0[2],Output,PIN_L25,6,B6_N1,2.5 V,
DIGIT0[3],Output,PIN_L26,6,B6_N1,2.5 V,
DIGIT0[4],Output,PIN_E17,7,B7_N2,2.5 V,
DIGIT0[5],Output,PIN_F22,7,B7_N0,2.5 V,
DIGIT0[6],Output,PIN_G18,7,B7_N2,2.5 V,
DIGIT1[0],Output,PIN_U24,5,B5_N0,2.5 V,
DIGIT1[1],Output,PIN_U23,5,B5_N1,2.5 V,
DIGIT1[2],Output,PIN_W25,5,B5_N1,2.5 V,
DIGIT1[3],Output,PIN_W22,5,B5_N0,2.5 V,
DIGIT1[4],Output,PIN_W21,5,B5_N1,2.5 V,
DIGIT1[5],Output,PIN_Y22,5,B5_N0,2.5 V,
DIGIT1[6],Output,PIN_M24,6,B6_N2,2.5 V,
DIGIT2[0],Output,PIN_W28,5,B5_N1,2.5 V,
DIGIT2[1],Output,PIN_W27,5,B5_N1,2.5 V,
DIGIT2[2],Output,PIN_Y26,5,B5_N1,2.5 V,
DIGIT2[3],Output,PIN_W26,5,B5_N1,2.5 V,
DIGIT2[4],Output,PIN_Y25,5,B5_N1,2.5 V,
DIGIT2[5],Output,PIN_AA26,5,B5_N1,2.5 V,
DIGIT2[6],Output,PIN_AA25,5,B5_N1,2.5 V,
DIGIT3[0],Output,PIN_Y19,4,B4_N0,3.3-V LVTTL,
DIGIT3[1],Output,PIN_AF23,4,B4_N0,3.3-V LVTTL,
DIGIT3[2],Output,PIN_AD24,4,B4_N0,3.3-V LVTTL,
DIGIT3[3],Output,PIN_AA21,4,B4_N0,3.3-V LVTTL,
DIGIT3[4],Output,PIN_AB20,4,B4_N0,3.3-V LVTTL,
DIGIT3[5],Output,PIN_U21,5,B5_N0,2.5 V,
DIGIT3[6],Output,PIN_V21,5,B5_N1,2.5 V,

Exercice 2 : Compteur modulo6 modifier

Pour compter les dizaines des minutes, il nous faut un compteur modulo 6 qui soit cascadable. Modifier le compteur BCD donné pour qu'il compte de 0 à 5 et génère un signal ENO quand il est à 5 et quand son entrée EN est à 1.

Indication : le compteur BCD à modifier est donné ci-dessous :

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity CounterBCD is
   port( EN: in std_logic;
 	 Clock: in std_logic;
 	 Reset: in std_logic;
	 ENO : out std_logic;
 	 Output: out std_logic_vector(3 downto 0));
end CounterBCD;
 
architecture Behavioral of CounterBCD is
   signal cmpt: std_logic_vector(3 downto 0);
	signal s_en_cmpt: std_logic_vector(4 downto 0);
begin   process(Clock,Reset)
   begin
      if(rising_edge(Clock)) then
		  if Reset='1' then
         cmpt <= "0000";
 	      elsif EN='1' then
	         if cmpt="1001" then
	            cmpt<="0000";
	         else
	           cmpt <= cmpt + 1;
	         end if;
         end if;
      end if;
   end process;
   Output <= cmpt;
	s_en_cmpt <= en & cmpt;
   with s_en_cmpt select
     ENO <= '1' when "11001",
            '0' when others;
end Behavioral;

Vous remplacerez le compteur des dizaines des minutes par ce nouveau compteur et en ferez un test. Restera donc la réalisation correcte des heures.

Exercice 3 : Compteur des heures modifier

Nous allons ajouter un comptage correct des heures au compteur de l'exercice 2 qui compte normalement la partie minutes.

Le comptage des heures est lui aussi très particulier. Les unités nécessitent un compteur décimal mais qui doit être interrompu lorsque les dizaines passent à 2 ! On ne doit pas alors dépasser 3. Nous allons utiliser un montage bouclé pour réaliser cela : lorsque l'on est à 23, un EN='1' fait repasser les heures à 0. Ce n'est pas la peine de le faire pour les minutes, cela sera automatique.

Indication : la gestion du bouclage peut être réalisé par quelque chose du genre :

HeurUnit: CounterBCD port map( 
    EN => s_eno2,
 	 Clock => clk,
 	 Reset => s_reset,
	 ENO => s_eno3,
 	 Output => s_data16(11 downto 8));
  HeurDiz: CounterBCD port map( 
    EN => s_eno3,
 	 Clock => clk,
 	 Reset => s_reset,
	 ENO => open,
 	 Output => s_data16(15 downto 12));
	
  -- reset quand 23 est detecte	par rebouclage
    s_eno2_heure <= s_eno2 & s_data16(15 downto 8);
    with s_eno2_heure select
	   s_reset <= '1' when "100100011",
                 '0' when others;

Faites un schéma pour comprendre.

TP3b : Réaliser un réveil qui sonne modifier

 
Le diagramme d'évolution comme moyen de spécifier le calcul de l'état futur en fonction de l'état présent

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7.

Le graphe d'évolution du réveil qui sonne est présenté ci-contre. La réalisation de ce graphe d'évolution nécessite la réalisation de ses deux entrées :

  • Key : sera simplement une entrée (un switch). Il sert pour l'armement de la sonnerie du réveil.
  • Trip : détecte que l'heure de sonnerie est égale à l'heure courante. L'heure courante est naturellement réalisé par le travail du TP2. L'heure de réveil à ce stade sera réalisée par 16 interrupteurs

La sortie sonnerie sera matérialisée par une LED. Une autre LED peut être utilisée pour matérialisée l'armement du réveil

Exercice : Un réveil qui sonne modifier

Le graphe d'évolution sera réalisé avec un case when et sans initialisation. Le test de bon fonctionnement ne peut se faire qu'avec deux interrupteurs en entrées (un pour ArmKey et un pour Trip) et pas à 50 MHz pour éviter la prise en compte des rebonds. La sortie se fera sur une LED.

Indication 1 : On rappelle encore une fois que le style « case when » permet de ne pas chercher les équations de récurrences. Mais comme nos diagrammes d'évolutions se sont compliqués (par l'ajout d'étiquettes sur les transitions), il nous faudra ajouter des "if then". Cela est tellement intuitif que nous passons directement aux exemples. Nous commençons par présenter partiellement le réveil.

Indication 2 : Programmation sans initialisation : le principe consiste à déclarer d'abord un type énuméré avec une définition symbolique de chacun des états (ici Armed, Off, Ringing) :

TYPE typetat IS (Armed, Off, Ringing); -- dans architecture
SIGNAL etat : typetat;

Ensuite dans un « case when » on détaillera toutes les transitions possibles comme montré ci-dessous dans le cas où l'on ne s'intéresse pas à une initialisation :

-- sans initialisation
BEGIN
  PROCESS (clock) BEGIN
    IF clock'EVENT AND clock='1' THEN
      CASE etat IS
      WHEN Off => IF key ='1' THEN etat <= Armed; 
                  ELSE etat <= Off; 
                  END IF;
                  ....
      END CASE;
    END IF;
  END PROCESS;
  ....

L'idée générale est donc d'utiliser un « case » sur les états avec des « if » pour gérer l'ensemble des transitions.

Indication 3 : Il serait bon d'ajouter au réveil une entrée ENA qui sera une division de l'horloge par 2**20. Ceci pour éviter les rebonds des interrupteurs.

Indication 4 : le réveil est abordé dans un autre livre sous toutes les formes et il est même possible d'y trouver une solution sans initialisation et avec l'entrée ena.

Exercice 2 : Un réveil qui sonne (suite) modifier

Compléter l'exercice 1 pour utiliser le séquenceur de la sonnerie mais avec Trip réalisé avec l'heure courante qui défile. Par contre l'heure de sonnerie sera réalisée par des interrupteurs.

TP4b : Un processeur seul modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7.

 
Tiny 861 de départ avec ses afficheurs, ses leds et ses interrupteurs

Indication : Pour la mise à jour du contenu de la mémoire seulement, sans passer par un temps de recompilation complet de l’application (donc plus ou moins équivalent à data2mem), il faut valider l'option "use smart compilation". Pour y accéder : menu assignements => settings => compilation process settings => puis cocher l'option. Ne pas oublier de faire "apply" avant de quitter la fenêtre !

Voir le TP4 de ce chapitre pour la présentation.

Évidemment, la ressource donnée n'est pas identique à celle du TP4 puisque nous avons besoin de 4 digits d'affichage. C'est ce qui est présenté dans la figure.

Votre objectif sera de prendre contact avec un processeur qui ne possède aucun périphérique. Votre travail consistera à réaliser :

  • quelques chenillards
  • un comptage BCD sur 4 digits, en utilisant les sous-programmes du TP4, puis

TP5b : Déplacer les transcodeurs et s'en servir comme périphérique modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7.

Indication : Pour la mise à jour du contenu de la mémoire seulement, sans passer par un temps de recompilation complet de l’application (donc plus ou moins équivalent à data2mem), il faut valider l'option "use smart compilation". Pour y accéder : menu assignements => settings => compilation process settings => puis cocher l'option. Ne pas oublier de faire "apply" avant de quitter la fenêtre !

 
Déplacer les transcodeurs comme périphérique du Tiny 861

L'utilisation de l'affichage sur quatre digits avec le Tiny861 nécessite l'utilisation de quatre registres : un par afficheur. Elle nécessite aussi l'utilisation d'un tableau pour transcoder. En clair pour que 0x1234 finisse sur les afficheurs sept segments il faut d'abord découper 0x1234 en quatre parties contenant 1, 2, 3 et 4 et les transcoder. Cela représente un travail important à réaliser par programme. Nous désirons simplifier le travail du programmeur en déplaçant le transcodage logiciel (par tableau) dans le matériel à l'aide des transcodeurs déjà réalisés dans les TPs précédents. L'affichage de 0x1234 sera alors simplement coupé en deux 0x12 et 0x34 et envoyés sur deux ports. Le transcodage sera alors complètement automatique.

Exercice 1 modifier

  1. Réaliser le périphérique demandé. Ce qui est demandé est dessiné en rouge dans la figure de cette section.
  2. Modifier le programme de l'exercice précédent pour que l'on affiche toujours les heures d'un réveil sur ce nouveau matériel.

TP6b : Un compteur complet comme périphérique modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7.

Indication : Pour la mise à jour du contenu de la mémoire seulement, sans passer par un temps de recompilation complet de l’application (donc plus ou moins équivalent à data2mem), il faut valider l'option "use smart compilation". Pour y accéder : menu assignements => settings => compilation process settings => puis cocher l'option. Ne pas oublier de faire "apply" avant de quitter la fenêtre !

 
Interface pour retrouver l'heure courante

Nous allons utiliser la correction de l'exercice 3 du TP2b et en faire un périphérique. Il s'agit de l'ajouter à ce qui a été fait dans le TP5b. Ainsi l'heure du TP 5b correspond à une heure de réveil. Il est très facile de manipuler celle-ci en incrémentation ou décrémentation par un processeur.

Exercice 1 modifier

Prendre les 4 compteurs HH:MM du TP2 et en faire un composant.

Il devra donc avoir 2 entrées :

  • horloge encore appelée clk,
  • EN entrée de validation qui est reliée à un signal de 3 Hz. Le processeur devra pouvoir accéder directement aux sorties de tous les compteurs, avant le transcodage. Celles-ci devront donc être des entrées pour le processeur.

Les nouvelles sorties globales sept segments devront utiliser quatre autre digits.

Montrer qu'après réalisation de la partie matérielle, vous êtes capable de détecter que l'heure réveil est égale à l'heure courante en allumant une LED.

Exercice 2 modifier

Pouvez-vous améliorer le comportement de votre réveil pour un réglage de l'heure réveil ?


  À partir de maintenant, c'est une autre série de TP qui commence.

TP1c : premier contact avec Quartus et l'affichage LCD modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7. Cette carte DE2-115 possède un afficheur LCD de deux lignes de 16 caractères.

Contrairement à ce qu'il se passe pour les TPs TP1 et TP1b, la sortie ne peut pas être directe sur l'afficheur LCD. Nous voulons dire que ce que vous allez réaliser est enfoui dans une partie de code VHDL qui est donné. Vous devez donc repérer l'entité et l'architecture à modifier pour arriver à vos fins.

Exercice 1 modifier

On vous donne complètement le module qui affiche sur l'afficheur. Pour cela, nous allons essayer dans cette section, d'utiliser un module VHDL touvé chez Opencores. Il se trouve dans Projets → Other → 16x2 LCD controller et a été réalisé par Daniel Drescher. Pour éviter d'aller les chercher sur Internet, ces fichiers vous sont fournis maintenant.

  • d'abord le fichier de démonstration
  • puis le fichier du coeur lcd, fichier que l'on gardera tout au long de ce TP

1°) En suivant ce que fait l'enseignant, on vous demande de compiler et d'essayer le module d'Opencores.org

2°) Modifier le texte affiché à votre convenance

Indications :

To,Direction,Location,I/O Bank,VREF Group,I/O Standard,Reserved
CLK,Input,PIN_Y2,2,B2_N0,3.3-V LVTTL,
LCD_E,Output,PIN_L4,1,B1_N1,3.3-V LVTTL,
LCD_ON,Output,PIN_L5,1,B1_N1,3.3-V LVTTL,
LCD_RS,Output,PIN_M2,1,B1_N2,3.3-V LVTTL,
LCD_RW,Output,PIN_M1,1,B1_N2,3.3-V LVTTL,
LCD_DB[7],Output,PIN_M5,1,B1_N2,3.3-V LVTTL,
LCD_DB[6],Output,PIN_M3,1,B1_N1,3.3-V LVTTL,
LCD_DB[5],Output,PIN_K2,1,B1_N1,3.3-V LVTTL,
LCD_DB[4],Output,PIN_K1,1,B1_N1,3.3-V LVTTL,

Exercice 2 modifier

Notre objectif étant d'afficher des heures minutes, nous allons spécialiser un peu cet afficheur. Dans un premier temps, on le destine à afficher les 4 digits d'un compteur binaire. En clair il doit afficher entre 0000 et FFFF. Mais l'exercice précédent vous a montré que l'afficheur lcd ne connaît que les codes ASCII. Vous aller réaliser un circuit combinatoire qui réalise cela. Comme il nous faut garder le gestionnaire de l'écran lcd, nous allons vous proposer un fichier lcd16x2_ctrl_demo.vhd modifié dans lequel on vous demande de modifier la partie combinatoire en fin de fichier.

Indications :

  • on vous a préparé une horloge à 10 Hz pour le compteur
  • L'ensemble donné fonctionne mais pas correctement : il affiche mal les chiffres au-delà de 9 !!!
  • la seule chose que vous avez à réaliser est le transcodeur tout en bas du fichier. Vous remplacerez l'équation naïve par un "with select when"

TP2c : réalisation d'un affichage HH:MN modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7.

Exercice 1 modifier

Le problème du transcodeur réalisé dans l'exercice 2 du TP1c peut être facilement résolu si l'on remplace les compteurs hexadécimaux par des compteurs BCD (qui ne comptent que de 0 à 9). C'est ce que fait le code ci-dessous. Vous y remarquerez la disparition du transcodeur de l'exercice 2 tu TP1c. Essayez de comprendre pourquoi.

Dans cet exercice, on vous demande simplement d'insérer un ":" entre les deux premiers digits et les deux derniers. On vous rappelle en effet que l'on finira par afficher les heures et minutes (qui en général sont séparées par ce ":") d'où le titre de ce TP.

Exercice 2 : Compteur modulo6 modifier

Pour compter les dizaines des minutes, il nous faut un compteur modulo 6 qui soit cascadable. Modifier le compteur BCD donné pour qu'il compte de 0 à 5 et génère un signal ENO quand il est à 5 et quand son entrée EN est à 1.

Indication : le compteur BCD à modifier est donné ci-dessous :

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity CounterBCD is
   port( EN: in std_logic;
 	 Clock: in std_logic;
 	 Reset: in std_logic;
	 ENO : out std_logic;
 	 Output: out std_logic_vector(3 downto 0));
end CounterBCD;
 
architecture Behavioral of CounterBCD is
   signal cmpt: std_logic_vector(3 downto 0);
	signal s_en_cmpt: std_logic_vector(4 downto 0);
begin   process(Clock,Reset)
   begin
      if(rising_edge(Clock)) then
		  if Reset='1' then
         cmpt <= "0000";
 	      elsif EN='1' then
	         if cmpt="1001" then
	            cmpt<="0000";
	         else
	           cmpt <= cmpt + 1;
	         end if;
         end if;
      end if;
   end process;
   Output <= cmpt;
	s_en_cmpt <= en & cmpt;
   with s_en_cmpt select
     ENO <= '1' when "11001",
            '0' when others;
end Behavioral;

Vous remplacerez le compteur des dizaines des minutes par ce nouveau compteur et en ferez un test. Restera donc la réalisation correcte des heures.

Exercice 3 : Compteur des heures modifier

Nous allons ajouter un comptage correct des heures au compteur de l'exercice 2 qui compte normalement la partie minutes.

Le comptage des heures est lui aussi très particulier. Les unités nécessitent un compteur décimal mais qui doit être interrompu lorsque les dizaines passent à 2 ! On ne doit pas alors dépasser 3. Nous allons utiliser un montage bouclé pour réaliser cela : lorsque l'on est à 23, un EN='1' fait repasser les heures à 0. Ce n'est pas la peine de le faire pour les minutes, cela sera automatique.

Indication : la gestion du bouclage peut être réalisé par quelque chose du genre :

HeurUnit: CounterBCD port map( 
    EN => s_eno2,
 	 Clock => clk,
 	 Reset => s_reset,
	 ENO => s_eno3,
 	 Output => s_data16(11 downto 8));
  HeurDiz: CounterBCD port map( 
    EN => s_eno3,
 	 Clock => clk,
 	 Reset => s_reset,
	 ENO => open,
 	 Output => s_data16(15 downto 12));
	
  -- reset quand 23 est detecte	par rebouclage
    s_eno2_heure <= s_eno2 & s_data16(15 downto 8);
    with s_eno2_heure select
	   s_reset <= '1' when "100100011",
                 '0' when others;

Faites un schéma pour comprendre, avant d'en regarder la solution.

TP3c : réalisation d'une sonnerie modifier

 
Le diagramme d'évolution comme moyen de spécifier le calcul de l'état futur en fonction de l'état présent

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7.

Quand l'heure courante est égale à l'heure de réveil et que le réveil est armé il faut que le réveil sonne. Ceci doit être géré par une machine séquentielle que l'on cherche à réaliser.

Le graphe d'évolution du réveil qui sonne est présenté ci-contre. La réalisation de ce graphe d'évolution nécessite la réalisation de ses deux entrées :

  • Key : sera simplement une entrée (un switch). elle sert pour l'armement de la sonnerie du réveil.
  • Trip : détecte que l'heure de sonnerie est égale à l'heure courante. L'heure courante est naturellement réalisé par le travail du TP2. L'heure de réveil à ce stade sera réalisée par 16 interrupteurs

La sortie sonnerie sera matérialisée par une LED. Une autre LED peut être utilisée pour matérialisée l'armement du réveil

Exercice 1 : Un mécanisme de sonnerie pour sonnerie de réveil modifier

Vous allez partir de la correction de l'exercice 2 du TP2c disponible ICI

 

Il n'y aura aucune interaction entre l'heure courante et l'heure réveil (qui n'existe pas à ce stade). On rajoute simplement l'automatisme de sonnerie. Ceci permet simplement un test de l'automatisme de sonnerie.

Ajoutez deux entrées (ArmKey et Trip) et une sortie "led_out" pour tester votre machine d'états. L'entrée "ena" du mécanisme de sera reliée à la sortie du timer "eno10Hz" du module "lcd16x2_ctrl_demo.vhd". Le fichier de contrainte sera :

To,Direction,Location,I/O Bank,VREF Group,I/O Standard,Reserved
CLK,Input,PIN_Y2,2,B2_N0,3.3-V LVTTL,
LCD_E,Output,PIN_L4,1,B1_N1,3.3-V LVTTL,
LCD_ON,Output,PIN_L5,1,B1_N1,3.3-V LVTTL,
LCD_RS,Output,PIN_M2,1,B1_N2,3.3-V LVTTL,
LCD_RW,Output,PIN_M1,1,B1_N2,3.3-V LVTTL,
LCD_DB[7],Output,PIN_M5,1,B1_N2,3.3-V LVTTL,
LCD_DB[6],Output,PIN_M3,1,B1_N1,3.3-V LVTTL,
LCD_DB[5],Output,PIN_K2,1,B1_N1,3.3-V LVTTL,
LCD_DB[4],Output,PIN_K1,1,B1_N1,3.3-V LVTTL,
led_out,Output,PIN_G19,7,B7_N2,2.5 V,
Armkey,Input,PIN_AC28,5,B5_N2,2.5 V,
Trip,Input,PIN_AB28,5,B5_N1,2.5 V,

avec Trip en sw0 et ArmKey en sw1.

Le graphe d'évolution sera réalisé avec un case when et sans initialisation.

Indication 1 : On rappelle encore une fois que le style « case when » permet de ne pas chercher les équations de récurrences. Mais comme nos diagrammes d'évolutions se sont compliqués (par l'ajout d'étiquettes sur les transitions), il nous faudra ajouter des "if then". Cela est tellement intuitif que nous passons directement aux exemples. Nous commençons par présenter partiellement le réveil.

Indication 2 : Programmation sans initialisation : le principe consiste à déclarer d'abord un type énuméré avec une définition symbolique de chacun des états (ici Armed, Off, Ringing) :

TYPE typetat IS (Armed, Off, Ringing); -- dans architecture
SIGNAL etat : typetat;

Ensuite dans un « case when » on détaillera toutes les transitions possibles comme montré ci-dessous dans le cas où l'on ne s'intéresse pas à une initialisation :

-- sans initialisation
BEGIN
  PROCESS (clock) BEGIN
    IF clock'EVENT AND clock='1' THEN
      CASE etat IS
      WHEN Off => IF key ='1' THEN etat <= Armed; 
                  ELSE etat <= Off; 
                  END IF;
                  ....
      END CASE;
    END IF;
  END PROCESS;
  ....

L'idée générale est donc d'utiliser un « case » sur les états avec des « if » pour gérer l'ensemble des transitions.

Indication 3 : Il serait bon d'ajouter au réveil une entrée ENA qui serait une division de l'horloge par 2**20. Ceci pour éviter les rebonds des interrupteurs.

Indication 4 : le réveil est abordé dans un autre livre sous toutes les formes et il est même possible d'y trouver une solution sans initialisation et avec l'entrée "ena".

Exercice 2 : Un réveil qui sonne (suite) modifier

Compléter l'exercice 1 pour utiliser le séquenceur de la sonnerie mais avec Trip réalisé avec l'heure courante qui défile. Par contre l'heure de sonnerie sera réalisée par des interrupteurs. Il serait bon aussi d'afficher correctement l'heure de réveil sur la deuxième ligne, en supposant qu'elle soit décimale.

Indications :

  • Vous partirez de la correction : Corrigé du TP2c
  • l'entité du fichier lcd16x_ctrl_demo.vhd devra donc évoluer maintenant :
entity lcd16x2_ctrl_demo is
  port (
    clk    : in  std_logic;
    Armkey    : in std_logic;
    HHMMAlarm : in std_logic_vector(15 downto 0);
    lcd_e  : out std_logic;
    lcd_rs : out std_logic;
    lcd_rw : out std_logic;
    lcd_db : out std_logic_vector(7 downto 4);
    led_out : out std_logic);
end entity lcd16x2_ctrl_demo;
  • vous remarquez l'apparition de l'entrée HHMMAlarm sur 16 bits. Elle sera donc reliée aux interrupteurs de la carte.
  • l'entrée Trip a disparu. Elle doit être remplacée par un signal, par exemple "egalite" pour coller à l'égalité de l'heure courante et de l'heure de l'alarme.
  • le fichier de contraintes peut être :
To,Direction,Location,I/O Bank,VREF Group,I/O Standard,Reserved
CLK,Input,PIN_Y2,2,B2_N0,3.3-V LVTTL,

LCD_DB[7],Output,PIN_M5,1,B1_N2,3.3-V LVTTL,
LCD_DB[6],Output,PIN_M3,1,B1_N1,3.3-V LVTTL,
LCD_DB[5],Output,PIN_K2,1,B1_N1,3.3-V LVTTL,
LCD_DB[4],Output,PIN_K1,1,B1_N1,3.3-V LVTTL,

LCD_E,Output,PIN_L4,1,B1_N1,3.3-V LVTTL,
LCD_ON,Output,PIN_L5,1,B1_N1,3.3-V LVTTL,
LCD_RS,Output,PIN_M2,1,B1_N2,3.3-V LVTTL,
LCD_RW,Output,PIN_M1,1,B1_N2,3.3-V LVTTL,

Armkey,Input,PIN_Y23,5,B5_N2,2.5 V,
SW[16],Input,PIN_Y24,5,B5_N2,2.5 V,
HHMMAlarm[15],Input,PIN_AA22,5,B5_N2,2.5 V,
HHMMAlarm[14],Input,PIN_AA23,5,B5_N2,2.5 V,
HHMMAlarm[13],Input,PIN_AA24,5,B5_N2,2.5 V,
HHMMAlarm[12],Input,PIN_AB23,5,B5_N2,2.5 V,
HHMMAlarm[11],Input,PIN_AB24,5,B5_N2,2.5 V,
HHMMAlarm[10],Input,PIN_AC24,5,B5_N2,2.5 V,
HHMMAlarm[9],Input,PIN_AB25,5,B5_N1,2.5 V,
HHMMAlarm[8],Input,PIN_AC25,5,B5_N2,2.5 V,
HHMMAlarm[7],Input,PIN_AB26,5,B5_N1,2.5 V,
HHMMAlarm[6],Input,PIN_AD26,5,B5_N2,2.5 V,
HHMMAlarm[5],Input,PIN_AC26,5,B5_N2,2.5 V,
HHMMAlarm[4],Input,PIN_AB27,5,B5_N1,2.5 V,
HHMMAlarm[3],Input,PIN_AD27,5,B5_N2,2.5 V,
HHMMAlarm[2],Input,PIN_AC27,5,B5_N2,2.5 V,
HHMMAlarm[1],Input,PIN_AC28,5,B5_N2,2.5 V,
HHMMAlarm[0],Input,PIN_AB28,5,B5_N1,2.5 V,

led_out,Output,PIN_G19,7,B7_N2,2.5 V,

  • le code VHDL pour réaliser un test d'égalité peut être :
egalite <= '1' when HHMMAlarm = s_data16 else
           '0';

TP4c : Un processeur seul modifier

Comme nous utilisons la carte DE2-115, le FPGA utilisé est un Cyclone IVE de référence EP4CE115F29C7.

 
Voici votre ressource avec en rouge ce qui commande l'heure réveil

Indications :

  • Pour la mise à jour du contenu de la mémoire seulement, sans passer par un temps de recompilation complet de l’application (donc plus ou moins équivalent à data2mem), il faut valider l'option "use smart compilation". Pour y accéder : menu assignements => settings => compilation process settings => puis cocher l'option. Ne pas oublier de faire "apply" avant de quitter la fenêtre !
  • La figure représente schématiquement la ressource que vous avez à disposition. Elle utilise directement l'afficheur lcd comme en TP3c. Pour être précis, l'affichage ne se fera pas exactement au même endroit qu'en TP3c ! L'heure courante du TP3c est gardée en matériel et le processeur n'agit que sur l'heure réveil.

Voir le TP4 de ce chapitre pour la présentation.

Évidemment, la ressource donnée n'est pas identique à celle du TP4 puisque nous avons besoin de 4 digits d'affichage et en plus l'affichage se fait sur lcd. Nous mettons la ressource complète sur notre site : TinyReveilLCDStart.zip. Cette ressource est destinée uniquement aux circuits Altera. Pour une version Xilinx, cherchez dans le chapitre précédent.

 
Vue interne des sorties pour l'ATTiny861 de nos ressources

Votre objectif sera de prendre contact avec un processeur qui est câblé comme dans la figure. Votre travail consistera à :

  • comprendre l'organisation de la ressource avec le sous-répertoire soft qui est absolument obligatoire
  • comprendre comment compiler un programme. Un script est disponible pour cela "compile_c.sh". il compile un programme qui a pour nom "test_tiny.c" pour en faire un fichier "test_tiny.mif"
  • si vous êtes curieux, ouvrez le fichier "pm.vhd" et vous verrez que le contenu de la mémoire est donné par "test_tiny.mif"
  • essayer de comprendre le rapport entre ce que vous voyez, sur les leds et le lcd, et le contenu du programme
  • réaliser quelques chenillards
  • réaliser un compteur binaire et afficher... Encore le problème des codes ASCII à résoudre. Comment le faire ?
  • réaliser un comptage BCD sur 4 digits, en utilisant les sous-programmes du TP4, puis
  • réaliser un comptage HH:MM (Pour la réalisation de l'arithmétique particulière des heures minutes :
void incrementHHMM(uint16_t *hh_mm) {
  (*hh_mm)++;
      if ((*hh_mm & 0x000F) > 0x0009)
      *hh_mm += 0x0006;
      if ((*hh_mm & 0x00F0) > 0x0050)
      *hh_mm += 0x00A0;
      if ((*hh_mm & 0x0F00) > 0x0900)
      *hh_mm += 0x0600;
      if ((*hh_mm & 0xFF00) > 0x2300)
      *hh_mm = 0x0000;
}
 
void decrementHHMM(uint16_t *hh_mm) {
  (*hh_mm)--;
      if ((*hh_mm & 0x000F) == 0x000F)
      *hh_mm -= 0x0006;
      if ((*hh_mm & 0x00F0) == 0x00F0)
      *hh_mm -= 0x00A0;
      if ((*hh_mm & 0x0F00) == 0x0F00)
      *hh_mm -= 0x0600;
      if ((*hh_mm & 0xFFFF) > 0x2359)
      *hh_mm = 0x2359;
}

)

Début d’un principe
Fin du principe


TP5c : Économiser deux PORTs modifier

 
Commande de l'heure réveil avec 2 PORTs seulement

La figure du TP4c montrait l'utilisation d'un PORT par digit affiché sur l'écran lcd. Ainsi, il est possible d'afficher n'importe quoi sur les 4 digits à disposition.

Cependant, cela ne nous sert pas puisque nous avons l'intention de n'y afficher que des chiffres de 0 à 9.

Exercice modifier

1°) On vous demande donc de faire la gestion des affichages des nombres de 0 à 9 sur 4 digits avec deux PORTs seulement et, malgré tout, sans utiliser de transcodeur.

2°) Réaliser ensuite la gestion des heures minutes sur ces afficheurs. On vous donne un petit bout de programme en C capable de réaliser l'arithmétique spéciale des Heures minutes. Il n'y a plus qu'à sortir sur les afficheurs.

#include <avr/io.h>
#include <avr/interrupt.h>
#undef F_CPU
#define F_CPU 15000000UL
#include "util/delay.h"

int main(int argc, char * argv[])
{   uint16_t hh_mm = 0; // pour les heures et minutes
    for (;;) {
      
      hh_mm++;
      if ((hh_mm & 0x000F) > 0x0009)
      hh_mm += 0x0006;
      if ((hh_mm & 0x00F0) > 0x0050)
      hh_mm += 0x00A0;
      if ((hh_mm & 0x0F00) > 0x0900)
      hh_mm += 0x0600;
      if ((hh_mm & 0xFF00) > 0x2300)
      hh_mm = 0x0000;
      _delay_ms(300);
    }
}

3°) Sur le même principe, on vous demande de réaliser une décrémentation heures/minutes.

Voir aussi modifier

TP6c : Réalisation du réglage de l'heure de réveil par le processeur modifier

Le travail du TP5c n'a pas modifié fondamentalement les responsabilités du processeur :

  • d'un côté le processeur gère complètement une heure réveil avec deux PORTs maintenant, c'est-à-dire 16 bits
  • de l'autre l'heure courante défile sur l'afficheur.

Exercice 1 modifier

 
Câbler un lcd16x2 avec un Tiny861 SOC

Comme le processeur n'est pas responsable de l'heure courante, vous devez lui donner la possibilité de lire cette heure sur deux PORTs.

Indications :

  • vous devez naturellement modifier l'entité de "lcd16x2_ctrl_demo.vhd" comme :
entity lcd16x2_ctrl_demo is
  port (
    clk    : in  std_logic;
    Armkey    : in std_logic;
    HHMMAlarm : in std_logic_vector(15 downto 0);
    HHMMCourante : out std_logic_vector(15 downto 0); -- ajouté pour besoins de cet exercice
    lcd_e  : out std_logic;
    lcd_rs : out std_logic;
    lcd_rw : out std_logic;
    lcd_db : out std_logic_vector(7 downto 4);
    led_out : out std_logic);
end entity lcd16x2_ctrl_demo;
  • il n'est pas difficile de trouver un signal 16 bits à l'intérieur de l'architecture qui contient cette information et de la sortir
  • chercher le process de lecture et modifier le en conséquence.

Exercice 2 modifier

À partir du code C donné au TP précédent, on vous demande d'imaginer comment se passe la décrémentation de HH:MN ?

Modifier le programme pour qu'un interrupteur au choix incrémente l'heure de réveil et qu'un autre interrupteur la décrémente.

Exercice 3 modifier

Réaliser un programme qui gère complètement le réveil, c'est-à-dire que celui-ci sonne lorsqu'il est armé et que l'heure courante est égale à l'heure de réveil.

Exercice 4 modifier

Pour cet exercice, vous pouvez soit partir de la ressource initiale du TP4c (TinyReveilLCDStart.zip) ou de cette ressource avec le Corrigé du TP5c. Votre choix déterminera simplement votre façon d'afficher l'heure de réveil par le nombre de ports utilisés : 4 dans la première version et deux dans la deuxième.

Nous n'avons jamais retiré l'automate qui gère la sonnerie du réveil du fichier lcd16x2_ctrl_demo.vhd. Pouvez-vous imaginer une architecture matérielle capable de gérer collectivement :

  1. heure courante comme tout au long de ce TP, réalisée en externe : ce n'est pas le processeur qui s'en occupe.
  2. heure alarme réglée par le processeur en incrémentation et décrémentation : un bouton pour incrémenter, un bouton pour décrémenter.
  3. bouton ArmKey géré par le processeur mais passé à l'automate. L'automate de sonnerie s'appelle SequSonnerie et si vous regardez son câblage dans lcd16x2_ctrl_demo vous verrez qu'il est relié à 0.
  4. sonnerie gérée par l'automate. Vous devez la sortir sur une led.

ANNEXE I : Comment utiliser l'ATTiny861 avec Altera modifier

Nous avons réalisé une version pour Altera de ce processeur. Comme nous nous y attendions le seul écueil pour le portage est la mémoire programme.

Comme déjà évoqué, nous mettons la ressource sur notre site : M4209TinyStart.zip. Cela représente l’ensemble des fichiers nécessaires à la réalisation sous Linux de tous les TPs de ce chapitre. Nous mettrons à jour au plus vite pour Windows.

L'organisation des répertoires doit être la suivante :

  • dans le répertoire du projet mettre les fichiers vhd et cvs
  • dans un sous répertoire soft mettre le script de compilation, et le programme .c à compiler ainsi que mifwrite.cpp et sa compilation.

Le programme micrcontroleur.vhd modifier

Il est possible de prendre la version donnée plus haut. Altera semble utiliser le nom de l'entité top pour se faire une idée de la hiérarchie (ce n'est peut être qu'une option qui peut être retirée). Il vous faudra donc éventuellement changer le nom de l'entité. Mais si vous êtes arrivé ici jusqu'ici dans ce livre, cela ne doit être qu'une promenade de santé.

Version de pm.vhd modifier

Comme déjà évoqué, la gestion de mémoire est très différente chez Altera de chez Xilinx. Voici donc une version de la mémoire programme. Elle utilise la librairie LPM plutôt que le MegaWizzard IP proposé par Quartus.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- for memory
LIBRARY lpm;
USE lpm.lpm_components.ALL;
LIBRARY altera_mf;
USE altera_mf.altera_mf_components.all;

entity pm is
	Port (
           clk    : in std_logic;
           Rst    : in std_logic;
           PM_A   : in std_logic_vector(15 downto 0);
           PM_Drd : out std_logic_vector(15 downto 0));
end pm;

architecture Arch of pm is
begin
progMemory: lpm_rom GENERIC MAP (
  lpm_widthad => 12,
  lpm_outdata => "REGISTERED",
  --
  lpm_address_control => "UNREGISTERED",
  lpm_file => "./soft/chenillar.mif",-- fill ram with content of file program.mif
  lpm_width => 16)
  PORT MAP (
    address => PM_A(11 downto 0), --8
    memenab => '1',
 --   inclock => Clk,
    outclock => clk,
    q => PM_Drd);
end Arch;

On voit qu'elle est associée à un fichier "soft/chenillar.mif". A priori un fichier .HEX peut faire aussi l'affaire.

Pour obtenir un fichier .mif, nous avons utilisé l'utilitaire trouvé sur Internet :

qui doit être compilé.

Script de compilation modifier

Le script donné ci-dessous est fonctionnel.

#!/bin/bash
avr-gcc -g -mmcu=attiny861 -Wall -Os -c chenillar.c
avr-gcc -g -mmcu=attiny861 -o chenillar.elf -Wl,-Map,chenillar.map chenillar.o
avr-objdump -h -S chenillar.elf > chenillar.lss
#avr-objcopy -R .eeprom -O ihex chenillar.elf chenillar.hex
avr-objcopy -O binary -R .eeprom chenillar.elf chenillar.bin
./mifwrite chenillar.bin chenillar.mif

Pour la mise à jour du contenu de la mémoire seulement, sans passer par un temps de recompilation complet de l’application (donc plus ou moins équivalent à data2mem), il faut valider l'option "use smart compilation". Pour y accéder : menu assignements => settings => compilation process settings => puis cocher l'option . ne pas oublier de faire "apply" avant de quitter la fenêtre !

À partir de là une seule compilation fera le travail. Un peu plus d'une minute de compilation. C'est quand même bien plus long que data2mem qui ne prend qu'une dizaine de secondes !

Script d'assemblage modifier

Il est en cours de développement. Seule la partie assemblage a été testée mais pas les deux dernières lignes qui sont sensée automatiser la mise en mémoire du programme. Nous avons eu des essais non concluants avec ces deux lignes et les laissons donc en commentaire.

#!/bin/bash
avr-gcc -mmcu=attiny861 chenillar.S -o chenillar.elf
avr-objdump -h -S chenillar.elf > chenillar.lss
#avr-objcopy -R .eeprom -O ihex chenillar.elf chenillar.hex
avr-objcopy -O binary -R .eeprom chenillar.elf chenillar.bin
./mifwrite chenillar.bin chenillar.mif
#!!! par defaut est installé dans /opt/altera mais ici dans /opt/Altera
#/opt/Altera/15.0/quartus/bin/quartus_cdb Tiny861 -c Tiny861 --update_mif
#/opt/Altera/15.0/quartus/bin/quartus_cdb --update_mif Tiny861
#/opt/Altera/15.0/quartus/bin/quartus_asm Tiny861

Un petit programme d'essai en assembleur pourrait être :

;********* chenillar.S ****************
#define __SFR_OFFSET 0 //obligatoire pour fonctionnement correct de "out" et "in"

.nolist
#include <avr/io.h>
.list

      .section .text    ; denotes code section
      .global main
main:
     LDI R16,1 ; setup
loop:
     LSL     R16    ; declage perpetuelle
     brne    suite
     LDI R16,1 ; setup
suite:
     OUT    PORTA, R16    ; result to port A
     rcall  delay
     RJMP   loop
     

delay: 
        ldi r23, 0x40           ; 0x80 sur Nexys3 mais probablement 0x40 Ã  l'UTT
delayloop_ext:
        ldi r24, 0xff		; load 0xffff to r24:25 
        ldi r25, 0xff 
delayloop: 
        sbiw r24,1		; decrement r24:25 
        brne delayloop		; branch if not 0 
        dec  r23
        brne delayloop_ext
        ret
.END

ANNEXE II modifier

Nous avions pour habitude d’utiliser les primitives d'instanciation des LUTs avec les outils Xilinx. Nous avons donc chercher comment faire avec les outils Altera et, à notre grande surprise, avons découvert que la primitive correspondante n'existe pas. Bien sûr les FPGAs Altera sont aussi bâtis autour des LUT (LUT4, LUT5, LUT6) mais leurs utilisation est un peu plus complexe. Pourquoi ? Parce que les seules primitives disponibles sont "lut_input" et "lut_output".

Pour rendre l’utilisation plus compréhensibles pour les habitués, nous avons procédé comme ceci.

1 - Création d'un composant LUT4 modifier

Voici le composant correspondant :

library ieee;
use ieee.std_logic_1164.all;
library altera;
use altera.altera_primitives_components.all;
entity LUT4 is 
  generic(mask : std_logic_vector(15 downto 0):=X"0000");
  port (
   in4 : in std_logic_vector(3 downto 0);
	out1 : out std_logic);
end LUT4;
architecture arch_lut4 of LUT4 is
signal s_lut : std_logic_vector(3 downto 0);
signal s_out : std_logic;
begin
  ic1:lut_input port map(a_in => in4(0),a_out=>s_lut(0));
  ic2:lut_input port map(a_in => in4(1),a_out=>s_lut(1));
  ic3:lut_input port map(a_in => in4(2),a_out=>s_lut(2));
  ic4:lut_input port map(a_in => in4(3),a_out=>s_lut(3));
  with s_lut select
    s_out <= mask(0) when "0000",
             mask(1) when "0001",
             mask(2) when "0010",
             mask(3) when "0011",
             mask(4) when "0100",
             mask(5) when "0101",
             mask(6) when "0110",
             mask(7) when "0111",
             mask(8) when "1000",
             mask(9) when "1001",
             mask(10) when "1010",
             mask(11) when "1011",
             mask(12) when "1100",
             mask(13) when "1101",
             mask(14) when "1110",
             mask(15) when "1111";
	ic5: lut_output port map(a_in=>s_out,a_out=>out1);
end arch_lut4;

Cela peut surprendre mais les seules primitives Altera sont "lut_input" et "lut_output", d'où le code ci-dessus.

2 - Instanciation modifier

Comme d'habitude :

-- declaration avant begin architecture
 component LUT4 is 
    generic(mask : std_logic_vector(15 downto 0):=X"0000");
    port (
     in4 : in std_logic_vector(3 downto 0);
	 out1 : out std_logic);
  end component LUT4;

-- puis après begin :
mylut:LUT4 generic map(mask => X"FFFE")
            port map (in4 => compteur(14 downto 11),
     	           OUT1 => led);

Chaque connaisseur aura reconnu la réalisation d'un OU à quatre entrées.

Voir aussi modifier