VHDL - 7 Segment Göstergede Kayan Yazı

Başlatan yttuncel, 17 Aralık 2012, 02:12:30

yttuncel

Merhabalar,

VHDL ve BASYS2 board kullanarak küçük bir proje hazırlamaktayım, projenin sonuna geldiğimi düşünüyorum ancak bir yerde takıldım ve çözüme ulaşamıyorum. Sorunu size anlatmaya çalışacağım umarım yeterince açık olabilirim ve umarım sorunu birlikte çözeriz. Şimdiden teşekkürler.

Şimdi öncelikle projeyi, daha sonra modülleri ve modüllerin işlevlerini anlatayım. Projem başlıktan da anlaşılacağı gibi bir metni 7 segment göstergede kaydırma üzerine kurulu. Klavyeden basılan harfler yanyana eklenecek ve belli bir tuşa basıldığında yazı kaymaya başlayacak. Şimdilik yanyana ekleme kısmındayım, gerçi bundan sonrası daha kolay olacak gibi biraz detaylandırıp cilalama olacak sadece :) Şimdi modülleri anlatayım:( Kodlar ve yorumlar ingilizce ancak anlaşılacağını düşünüyorum)

1. KeyboardInterface.vhd
    Bu modül klavyeden gelen ScanCode'ları algılamakla görevli. Bu modülü ben yazmadım(Benim yazmadığım tek modül), ancak bildiğim kadarı ile debouncer var içinde. Bu koda bayağı zaman ayırdım üstünde kafa patlattım çünkü henüz çok deneyimli değilim VHDL'de, ancak anladığımı düşünüyorum. Parity check'de var aynı zamanda, gerçi kullanmadım ama ileride error koşulu eklenebilir tabii ki.
library IEEE;
	use IEEE.STD_LOGIC_1164.all;
	use IEEE.Numeric_std.all;

Entity KeyboardController is
	generic (FilterSize : positive := 8);
		port( Clk : in std_logic; -- System Clock
		Reset : in std_logic; -- System Reset
		PS2_Clk : in std_logic; -- Keyboard Clock Line
		PS2_Data : in std_logic; -- Keyboard Data Line
		Scan_Err : out std_logic; -- To outside : Parity or Overflow error
		Scan_DAV : out std_logic; -- To outside when a scan code has arrived
		Scan_Out : out std_logic_vector(7 downto 0) -- Eight bits Data Out
	);
end KeyboardController;

Architecture Behavioral of KeyboardController is
	signal PS2_Datr : std_logic;
	subtype Filter_t is std_logic_vector(7 downto 0);
	signal Filter : Filter_t;
	signal Fall_Clk : std_logic;
	signal Bit_Cnt : unsigned (3 downto 0);
	signal Parity : std_logic;
	signal Scan_DAVi : std_logic;
	signal S_Reg : std_logic_vector(8 downto 0);
	signal PS2_Clk_f : std_logic;
	Type State_t is (Idle, Shifting);
	signal State : State_t;
	signal Scan_Code : std_logic_vector(7 downto 0);
	
	begin
		Scan_DAV <= Scan_DAVi;
		-- This filters digitally the raw clock signal coming from the keyboard :
		-- * Eight consecutive PS2_Clk=1 makes the filtered_clock go high
		-- * Eight consecutive PS2_Clk=0 makes the filtered_clock go low
		-- Implies a (FilterSize+1) x Tsys_clock delay on Fall_Clk wrt Data
		-- Also in charge of the re-synchronization of PS2_Data
		process (Clk,Reset)
		begin
			if Reset='1' then
				PS2_Datr <= '0';
				PS2_Clk_f <= '0';
				Filter <= (others=>'0');
				Fall_Clk <= '0';
			elsif rising_edge (Clk) then
				PS2_Datr <= PS2_Data and PS2_Data; -- also turns 'H' into '1'
				Fall_Clk <= '0';
				Filter <= (PS2_Clk and PS2_CLK) & Filter(Filter'high downto 1);
				if Filter = Filter_t'(others=>'1') then
					PS2_Clk_f <= '1';
				elsif Filter = Filter_t'(others=>'0') then
					PS2_Clk_f <= '0';
						if PS2_Clk_f = '1' then
							Fall_Clk <= '1';
						end if;
				end if;
			end if;
		end process;

			-- This simple State Machine reads in the Serial Data
			-- coming from the PS/2 peripheral.
		process(Clk,Reset)
		begin
			if Reset='1' then
			State <= Idle;
			Bit_Cnt <= (others => '0');
			S_Reg <= (others => '0');
			Scan_Code <= (others => '0');
			Scan_Out <= (others => '0');
			Parity <= '0';
			Scan_Davi <= '0';
			Scan_Err <= '0';
		elsif rising_edge (Clk) then
			case State is
				when Idle =>
					Parity <= '0';
					Bit_Cnt <= (others => '0');
					-- note that we dont need to clear the Shift Register
					if Fall_Clk='1' and PS2_Datr='0' then -- Start bit
						Scan_Err <= '0';
						State <= Shifting;
					end if;
				when Shifting =>
				if Bit_Cnt >= 9 then
					if Fall_Clk='1' then -- Stop Bit
		-- Error is (wrong Parity) or (Stop='0') or Overflow
						Scan_Err <= (not Parity) or (not PS2_Datr) or Scan_DAVi;
						Scan_Davi <= '1';
						Scan_Code <= S_Reg(7 downto 0);
						if (Scan_Code /= "11110000") then
							Scan_Out <= Scan_Code;
						end if;
						State <= Idle;
					end if;
				elsif Fall_Clk='1' then
					Bit_Cnt <= Bit_Cnt + 1;
					S_Reg <= PS2_Datr & S_Reg (S_Reg'high downto 1); -- Shift right
					Parity <= Parity xor PS2_Datr;
					Scan_Davi <= '0';
				end if;
				when others => -- never reached
					State <= Idle;
			end case;
		end if;
	end process;
end Behavioral;


2. Shifter.vhd
    Bu modül kendisine iletilen sinyali kaydırmaktan sorumludur. İlk önce byte'lardan oluşan 8 uzunlukta bir arrayle yapmayı düşündüm ancak VHDLde arraylerden pek memnun kalmadım maalesef, packageda type tanımlamak falan RTL schematicde pek düzgün gözükmedi. Neyse uzun lafın kısası, 64bitlik bir vectoru 8er bit kaydırıyor bu modül ve 8. 7. 6. ve 5. byteları output olarak veriyor bir sonraki modüle.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.numeric_std.all;

entity my_shifter is
        port(clk      : in  std_logic;
				Scan_Dav : in  std_logic;
				Data_in  : in  std_logic_vector (7 downto 0);
				O1 : out std_logic_vector(7 downto 0);
				O2 : out std_logic_vector(7 downto 0);
				O3 : out std_logic_vector(7 downto 0);
				O4 : out std_logic_vector(7 downto 0)
				);
end my_shifter;

architecture bhv of my_shifter is

signal bytes : std_logic_vector(63 downto 0);
begin
    process (clk, Scan_Dav) begin
        if rising_edge(clk) then
				if Scan_Dav = '1' then
					bytes <= bytes (bytes'high-8 downto 0) & Data_in;
				end if;
		  end if;
    end process;
	 O1 <= bytes(63 downto 56);
	 O2 <= bytes(55 downto 48);
	 O3 <= bytes(47 downto 40);
	 O4 <= bytes(39 downto 32);
end bhv;


3. SevenSegmentController
    Bu modül de göstergelerin aynı anda farklı değer göstermelerini sağlamaktadır. İçinde 2bitlik bir counter var, bu counterin her değeri farklı bir sinyali göstergeleri iletmekte ve yine her değeri farklı bir göstergeyi aktif etmektedir. Gönderdiği sinyaller scancode oldukları için bu sinyaller son olarak bir decodera sokulmakta ve bu decoderin outputu 7 segment göstergelere iletilmektedir.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;

entity SevenSegmentController is
	port (
		CLK: in std_logic;
		DEC1, DEC2, DEC3, DEC4: in std_logic_vector(7 downto 0);
		SEGMENTS: out std_logic_vector(6 downto 0);
		ANODES: out std_logic_vector(3 downto 0)
	);
end SevenSegmentController;

architecture Behavioral of SevenSegmentController is
   signal DecoderInput: std_logic_vector(7 downto 0);
	signal CurrentDisplay: std_logic_vector(1 downto 0) := "00";
	signal Prescaler: std_logic_vector(15 downto 0) := (others => '0');
begin

	Multiplex: process(CLK)
	begin
		if rising_edge(CLK) then
			if Prescaler(15) = '0' then
				Prescaler <= Prescaler + 1;
			else
				CurrentDisplay <= CurrentDisplay + 1;
				Prescaler <= (others => '0');
			end if;
		end if;
	end process Multiplex;

	SevenSegmentDecoder: entity work.SevenSegment_Decoder(Behavioral)
		generic map ( INVERT_OUTPUT => '1' )
		port map ( number => DecoderInput, segment => SEGMENTS );	
		
	DecoderInput <= DEC1 when CurrentDisplay = "00" else
					    DEC2 when CurrentDisplay = "01" else
						 DEC3 when CurrentDisplay = "10" else
						 DEC4 when CurrentDisplay = "11";
						 
   ANODES <= "0111" when CurrentDisplay = "00" else
				 "1011" when CurrentDisplay = "01" else
				 "1101" when CurrentDisplay = "10" else
				 "1110" when CurrentDisplay = "11";				 

end Behavioral;

Bu da top modülümün RTL şematiği:


Decoderin koduna gerek olmadığını düşünerek sorularımı sormaya başlıyorum.
İlk olarak shifter modülümün algoritmasını tam kuramadım. Metni girerken clocka bağlı kayma istemiyorum, yeni scancode varsa kayma istiyorum. Bunun için Scan_Dav kullanacağım ama bu konuda biraz daha uğraşacağım daha tam çaresiz değilim gibi. Asıl sorum şu: Normalde klavye arayüzünü tek başına çalıştırıp decodera soktuğumda kaç kere bastıysam o kadar karakter alıyodum, ancak şu halde bir kere P'ye basıyorum 3 tane P alıyorum. Bu bana debouncer sorunu gibi geldi(halbuki klavye modülünün üst kısmında clock filter var), FPGA'nın clocku 50 MHz. Görüntü arayüzünün clockuda 50 MHz ancak modül içinde prescaler kulanarak 1.5kHz'e düşürüyorum, orda sorun yok. Benim kafamda shifterin clocku tam oturmadı. Ona ayrı clockdivider yazdım kolay oynayabileyim diye :) 
Kısacası temel sorunum sanırım debouncerla ya da bir yerde bir sinyal hatası yapıyorum ve bir kere basıp 3 kere alıyorum devamında da shifter'ın clockunun yazının kayma hızı dışında etkilediği bir şey var mı onu merak ediyorum. Sorunun ne olduğunu ben de tam anlayamadığım için nokta atışı soramıyorum malesef.. Her türlü eleştiriyi ve yardımı bekliyorum, tekrardan herkese teşekkürler

ahmett

merhaba bana 32*160 kayan yazı projesi lazım elinde olan yada bir bilgisi olan varsa lütfen tardımlarını esirgemesinler tez ödevim acil yapmam lazım.( hex dosyası ile birlikte olan varsa yardımcı olsun lütfen ).. yazrdımlarınız için şimdiden teşekkürler...