Prise en main carte FPGA Icebreaker

Prise en main carte FPGA Icebreaker

OBJECTIF :

Réaliser un chronomètre sur la carte FPGA ; l’affichage est fait sur un afficheur 7 segments.
Le contrôle du comptage ( pause, start, init ) est réalisé via les boutons poussoirs de la carte.

chronometre.svg


Diviseur de fréquence

L’horloge de base de la carte FPGA a une fréquence 12MHz.
On souhaite, pour le comptage principal, une incrémentation toutes les secondes.
Le composant div_freq_1s a pour rôle de fournir un signal fs asymétrique de fréquence 1Hz, qui sera utilisé dans la suite par le compteur principal, et un signal fs_sym symtétrique de fréquence 1 Hz, qui permettra de faire clignoter LED1.

diviseur_frequence.svg

chronogramme_diviseur_de_frequence.svg

Compléter le code ci-dessous, vérifier en simulation le bon fonctionnement du composant, puis effectuer la synthèse logique.

REMARQUE : comme le temps de simulation sera trop long pour une fréquence de sortie 1Hz, nous effectuerons une simulation de durée 5ms pour des fréquence de fs et fs_sym de 1kHz. La synthèse ( implantation sur la carte ) sera faite pour une fréquence 1Hz.

Diviseur de Fréquence

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity div_freq_1s is
port( 	clk,reset	:	in std_logic;
			fs		: 	out std_logic;
		fs_sym		: 	out std_logic);
end div_freq_1s;

architecture arch_div_freq_1s of div_freq_1s is
signal count_int : unsigned (23 downto 0);
begin
	process(clk,reset)
		begin
		if reset='1' then count_int <= (others => '0');
		elsif rising_edge(clk) then
				if count_int= --### A COMPLETER ###-- 
					then count_int <= (others => '0'); 
					else count_int <= count_int + 1; -- "+"(unsigned,int)
				end if;
		end if;
	end process;

fs_sym <= '0' when count_int < --### A COMPLETER ###-- 
	 else '1';
fs <= '1' when count_int = x"000000" 
	 else '0';

end arch_div_freq_1s;

--======================================================================  

library IEEE;
use IEEE.std_logic_1164.all;
use work.all;

entity icebreaker is
port( CLK, BTN_N : std_logic ; 
		BTN1, BTN2, BTN3 : in std_logic;
		LED1, LED2, LED3, LED4 : out std_logic ;
	   P1A1, P1A2, P1A3, P1A4, P1A7, P1A8, P1A9, P1A10 : out std_logic
	   );
end icebreaker;

architecture arch_icebreaker of icebreaker is

signal reset, clk_count, clk_sym_1s : std_logic ;
signal dash : std_logic;

begin 

reset <= not(BTN_N);

div_freq0 : entity  div_freq_1s port map (
clk => CLK,
reset => reset,
fs => clk_count,
fs_sym => LED1
);

end arch_icebreaker;

Compteur Principal

Ajouter le composant compteur au système, et vérifier par une simulation son fonctionnement.

compteur_diviseur_frequence.svg


Affichage 7 Segments

La broche P1A10 permet de sélectionner l’afficheur MSB ou LSB

7_segments.svg

Compléter le code ci-dessous, vérifier le fonctionnement en simulation, puis effectuer la synthèse.

Affichage 7 Segments
library IEEE;
use IEEE.std_logic_1164.all;

entity dec_sev_seg is
port( din :  in std_logic_vector( 3 downto 0 );
		dout : out std_logic_vector ( 6 downto 0));
end dec_sev_seg;		
		
architecture arch_dec_sev_seg of dec_sev_seg is
signal conv : std_logic_vector( 6 downto 0);
begin  -- GFEDCBA

	conv <= "0111111" when din = x"0"
	else	"0000110" when din = x"1"
	else	"1011011" when din = x"2"
	else	"1001111" when din = x"3"
    --## A COMPLETER ##--
	else	"1111001" when din = x"E"
	else	"1110001" when din = x"F"
	else	"0000000"; 		
dout <= not(conv);				

end arch_dec_sev_seg;

--======================================================================  

library IEEE;
use IEEE.std_logic_1164.all;
use work.all;

entity icebreaker is
port( CLK, BTN_N : std_logic ; 
		BTN1, BTN2, BTN3 : in std_logic;
		LED1, LED2, LED3, LED4 : out std_logic ;
	   P1A1, P1A2, P1A3, P1A4, P1A7, P1A8, P1A9, P1A10 : out std_logic
	   );
end icebreaker;

architecture arch_icebreaker of icebreaker is

signal reset : std_logic ;
signal sev_seg : std_logic_vector(6 downto 0);

begin 

reset <= not(BTN_N);

dec_sev_seg0 : entity dec_sev_seg port map (
din => "0111",
dout => sev_seg
);	

P1A10 <= '0';

P1A1 <= sev_seg(0);
P1A2 <= sev_seg(1);
P1A3 <= sev_seg(2);
P1A4 <= sev_seg(3);
P1A7 <= sev_seg(4);
P1A8 <= sev_seg(5);
P1A9 <= sev_seg(6);

end arch_icebreaker;

Comptage hexadecimal 4 bits et affichage

Réaliser le système suivant.
On devrait constater un comptage de 0 à F sur un des afficheurs 7 segments.

comptage_4_bits_et_affichage.svg


Commande du chronomètre avec les boutons poussoirs

La gestion des commandes des boutons poussoirs peut être représentée par un diagramme d’états.
Effectuer la description de la machine d’états correspondante, en tenant compte des exemples vus précédemments.

comptage_4_bits_boutons.svg

fsm.svg


Comptage decimal 8 bits et affichage

Les 2 afficheurs 7 segments utilisent les mêmes broches, la sélection d’un afficheur se fait avec P1A10.
En pilotant un multiplexeur et P1A10 avec une horloge à 12MHz255=47kHz\frac{12MHz}{255} = 47kHz , on peut mettre à jour alternativement ces afficheurs et donner l’illusion d’un fonctionnement simultané.

Le composant count_split a pour rôle de transformer une valeur de comptage désormais sur 8bits en 2 digits sur 4 bits représentant un comptage décimal ( de 0 à 99 ).

Ex: valeur du comptage : 45, en hexa : x"2D", en binaire : “00101011”
Je dois fournir en sortie de count_split : x"4" et x"5"

  • Pour trouver le digit décimal, je peux effectuer une division par 10 ( division entière ) : 45/10 = 4
  • Pour trouver les unités, je multiplie ce digit décimal par 10, et je soustrait cette valeur à 45 : 45-4*10 = 5

comptage_decimal_8bits.svg