*

muuzoo

  • Lifetime Error!
  • *****
  • 5
    • Profili Görüntüle
    • Kişisel Blog
VHDL İle Clock Bölme
« : 25 Şubat 2016, 05:32:19 »
Yeni başlayanların ilk karşılaştığı şeylerden biri çoğunlukla daha yüksek frekansta çalışan clock üzerinden nasıl daha düşük frekanslar elde edeceğidir. Temelde frekans bölme işlemi basit bir sayıcı olarak düşünülebilir. Sayıcının ilgili bitleri kontrol edilerek clock frekansı 2 nin kuvvetleri cinsinden elde edilebilmektedir. Buna uygun bir kod parçası aşağıda verilmiştir. Basitçe açıklamak gerekirse "tmpCnt" sayacının 0. biti dikkate alınarak bir clock üretimi yapılırsa bu giriş clock işaretimizi ikiye bölecektir. Yani 50 MHz giriş uygulandığında 0. bit değişiminden 25 MHz, 1. bit değişiminden ise 12.5 Mhz işaret elde edilebilir.

Kod: VHDL
  1. library IEEE;
  2. use IEEE.STD_LOGIC_1164.all;
  3.  
  4. -- Uncomment the following library declaration if using
  5. -- arithmetic functions with Signed or Unsigned values
  6. use IEEE.NUMERIC_STD.all;
  7.  
  8. -- Uncomment the following library declaration if instantiating
  9. -- any Xilinx leaf cells in this code.
  10. --library UNISIM;
  11. --use UNISIM.VComponents.all;
  12.  
  13. entity clkManager is
  14.   port (
  15.     iClk     : in  std_logic;           -- Main System Clock
  16.     iRst     : in  std_logic;           -- Main Reset Signal
  17.     oClk25   : out std_logic);           -- 25 Mhz VGA Clock
  18. end clkManager;
  19.  
  20. architecture Behavioral of clkManager is
  21.   signal tmpCnt            : unsigned(1 downto 0) := '0';
  22.  
  23. begin
  24.  
  25.   -- purpose: Create 25 MHz From 50 Mhz Clock
  26.   -- type   : sequential
  27.   -- inputs : clk, rst
  28.   -- outputs: clk25
  29.   CLK_DIV : process (iclk, iRst) is
  30.   begin  -- process CLK_DIV
  31.     if iRst = '1' then           -- asynchronous reset (active low)
  32.       tmpCnt <= '0';
  33.     elsif iclk'event and iclk = '1' then  -- rising clock edge
  34.       tmpCnt <= tmpCnt + 1;
  35.     end if;
  36.   end process CLK_DIV;
  37.  
  38.   oClk25 <= tmpCnt(0);
  39.  
  40.  

Pekala ya 2'nin katları cinsinden bölmek istemezsek ? O zaman da bir sayıcının değerinin kontrolü ile istediğimiz frekans değerini elde etmek mümkün olacaktır. Basit matematik yapalım. 50 Mhz bir clock için her saat darbesi periyodu 20 ns süresindedir (20 * 10^-9 saniye). Peki biz eğer 1 sn periyoda sahip bir işaret elde etmek isteseydik? Yani 0.5 sn 0 değerine sahip 0.5 saniye 1 değerine sahip toplamda periyodu 1 sn olan bir işareti nasıl elde ederdik?

Cevap oldukça basit. Elimizdeki 20ns lik süreleri sayar ve toplam süreyi o şekilde bulabilirdik. 50 Mhz clock işareti demek o işaretin  saniyede 50.000.000 kez değiştiği manasına gelir. Eğer bir sayıcı yapıp 25  Milyon kez saydırıp, başka bir işareti değiştirirsek bu durumda 1 sn sürelik bir işaret elde etmiş oluruz. Bir önceki kodu bu şekilde güncellersek eğer:

Kod: VHDL
  1. library IEEE;
  2. use IEEE.STD_LOGIC_1164.all;
  3.  
  4. -- Uncomment the following library declaration if using
  5. -- arithmetic functions with Signed or Unsigned values
  6. use IEEE.NUMERIC_STD.all;
  7.  
  8. -- Uncomment the following library declaration if instantiating
  9. -- any Xilinx leaf cells in this code.
  10. --library UNISIM;
  11. --use UNISIM.VComponents.all;
  12.  
  13. entity clkManager is
  14.   generic (
  15.     freq : integer := 50);             -- Main Clock Frequency
  16.   port (
  17.     iClk     : in  std_logic;           -- Main System Clock
  18.     iRst     : in  std_logic;           -- Main Reset Signal
  19.     oClk25   : out std_logic;           -- 25 Mhz VGA Clock
  20.     oClkTime : out std_logic);          -- Ref. Clock For Time (1 Sec)
  21. end clkManager;
  22.  
  23. architecture Behavioral of clkManager is
  24.   constant periodConstTime : integer   := (freq*10**6)/2;  -- Total cycle for 0.5
  25.                                                            -- second timing.
  26.   constant periodConstDisp : integer   := (freq*10**3)/2;  -- Total cycle for 0.5
  27.                                                            -- milisecond timing.
  28.   signal oClkTimeTmp       : std_logic := '0';
  29.   signal tmpCnt            : std_logic := '0';
  30.  
  31. begin
  32.  
  33.   -- purpose: Create 25 MHz From 50 Mhz Clock
  34.   -- type   : sequential
  35.   -- inputs : clk, rst
  36.   -- outputs: clk25
  37.   CLK_DIV : process (iclk, iRst) is
  38.   begin  -- process CLK_DIV
  39.     if iRst = '0' then           -- asynchronous reset (active low)
  40.       tmpCnt <= '0';
  41.     elsif iclk'event and iclk = '1' then  -- rising clock edge
  42.       tmpCnt <= not tmpCnt;
  43.     end if;
  44.   end process CLK_DIV;
  45.  
  46.   oClk25 <= tmpCnt;
  47.  
  48.   -- purpose: 1 second ref. time.
  49.   -- type   : sequential
  50.   -- inputs : iClk, iRst
  51.   -- outputs: oClkTime
  52.   ClkTime1Sec : process (iClk, iRst) is
  53.     variable periodCounter : integer := 0;  -- Internal period counter.
  54.   begin  -- process FreqDivider
  55.     if iRst = '0' then                      -- asynchronous reset (active low)
  56.       oClkTimeTmp   <= '0';
  57.       periodCounter := 0;
  58.     elsif iClk'event and iClk = '1' then    -- rising clock edge
  59.       periodCounter := periodCounter + 1;
  60.       if (periodCounter = periodConstTime) then
  61.         oClkTimeTmp   <= not oClkTimeTmp;
  62.         periodCounter := 0;
  63.       end if;
  64.     end if;
  65.   end process ClkTime1Sec;
  66.  
  67.   oClkTime <= oClkTimeTmp;
  68.  
  69. end Behavioral;
  70.  

Görüleceği üzere "ClkTime1Sec" process yapısı içerisinde bulunan periodcounter sayıcısı sğrekli sayıyor ve bizim kodun üst kısmında tanımladığımız sabit değere ulaşıp ulaşmadığını kontrol ederek oClktimeTmp işaretini değiştirerek 1 sn lik bir işaret üretmiş oluyor. Böyle bir işaret mesela bir saat uygyulaması için kullanılabllir. Bu yüzden kod generic olarak tasarlanmış ve hangi giriş frekansında olursa olsun istenen çıkış değerinin elde edilmesi sağlanmış olur. Aynı kod yapısı kullanarak örneğin 7Segment uygulamaları için 1 KHz işaret üretmek isteseydik, kodumuz aşağıdaki şekilde olabilirdi.

Kod: VHDL
  1. library IEEE;
  2. use IEEE.STD_LOGIC_1164.all;
  3.  
  4. -- Uncomment the following library declaration if using
  5. -- arithmetic functions with Signed or Unsigned values
  6. use IEEE.NUMERIC_STD.all;
  7.  
  8. -- Uncomment the following library declaration if instantiating
  9. -- any Xilinx leaf cells in this code.
  10. --library UNISIM;
  11. --use UNISIM.VComponents.all;
  12.  
  13. entity clkManager is
  14.   generic (
  15.     freq : integer := 50);             -- Main Clock Frequency
  16.   port (
  17.     iClk     : in  std_logic;           -- Main System Clock
  18.     iRst     : in  std_logic;           -- Main Reset Signal
  19.     oClk25   : out std_logic;           -- 25 Mhz VGA Clock
  20.     oClk7Seg : out std_logic;           -- Clock source for 7 Segment Display
  21.     oClkTime : out std_logic);          -- Ref. Clock For Time (1 Sec)
  22. end clkManager;
  23.  
  24. architecture Behavioral of clkManager is
  25.   constant periodConstTime : integer   := (freq*10**6)/2;  -- Total cycle for 0.5
  26.                                                            -- second timing.
  27.   constant periodConstDisp : integer   := (freq*10**3)/2;  -- Total cycle for 0.5
  28.                                                            -- milisecond timing.
  29.   signal oClkTimeTmp       : std_logic := '0';
  30.   signal oClk7SegTmp       : std_logic := '0';
  31.   signal tmpCnt            : std_logic := '0';
  32.  
  33. begin
  34.  
  35.   -- purpose: Create 25 MHz From 50 Mhz Clock
  36.   -- type   : sequential
  37.   -- inputs : clk, rst
  38.   -- outputs: clk25
  39.   CLK_DIV : process (iclk, iRst) is
  40.   begin  -- process CLK_DIV
  41.     if iRst = '1' then           -- asynchronous reset (active low)
  42.       tmpCnt <= '0';
  43.     elsif iclk'event and iclk = '1' then  -- rising clock edge
  44.       tmpCnt <= not tmpCnt;
  45.     end if;
  46.   end process CLK_DIV;
  47.  
  48.   oClk25 <= tmpCnt;
  49.  
  50.   -- purpose: 1 second ref. time.
  51.   -- type   : sequential
  52.   -- inputs : iClk, iRst
  53.   -- outputs: oClkTime
  54.   ClkTime1Sec : process (iClk, iRst) is
  55.     variable periodCounter : integer := 0;  -- Internal period counter.
  56.   begin  -- process FreqDivider
  57.     if iRst = '1' then                      -- asynchronous reset (active low)
  58.       oClkTimeTmp   <= '0';
  59.       periodCounter := 0;
  60.     elsif iClk'event and iClk = '1' then    -- rising clock edge
  61.       periodCounter := periodCounter + 1;
  62.       if (periodCounter = periodConstTime) then
  63.         oClkTimeTmp   <= not oClkTimeTmp;
  64.         periodCounter := 0;
  65.       end if;
  66.     end if;
  67.   end process ClkTime1Sec;
  68.  
  69.   oClkTime <= oClkTimeTmp;
  70.  
  71.   -- purpose: 7 Segment Display Clock Generation (1Khz)
  72.   -- type   : sequential
  73.   -- inputs : iClk, iRst
  74.   -- outputs: oClk7Seg
  75.   Clk7SegGen : process (iClk, iRst) is
  76.     variable periodCounter : integer := 0;  -- Internal period counter.
  77.   begin  -- process Clk7SegGen
  78.     if iRst = '1' then                      -- asynchronous reset (active low)
  79.       oClk7SegTmp   <= '0';
  80.       periodCounter := 0;
  81.     elsif iClk'event and iClk = '1' then    -- rising clock edge
  82.       periodCounter := periodCounter + 1;
  83.       if (periodCounter = periodConstDisp) then
  84.         oClk7SegTmp   <= not oClk7SegTmp;
  85.         periodCounter := 0;
  86.       end if;
  87.     end if;
  88.   end process Clk7SegGen;
  89.  
  90.   oClk7Seg <= oClk7SegTmp;
  91.  
  92. end Behavioral;
  93.  

NOT: Bazı düzeltmeler eklendi, yazım hataları düzeltildi.
« Son Düzenleme: 01 Mart 2016, 07:19:10 Gönderen: muuzoo »

Ynt: VHDL İle Clock Bölme
« Yanıtla #1 : 12 Kasım 2016, 15:42:07 »
Merhaba;
Clock divider ile bir uygulama ödevi aldım ama konu hakkında pek bilgiye sahip değilim.
Clk_in, Reset ve mode(1 downto 0) girişlerine clk_out çıkışına sahip bir frekans bölücü VHDL dili ile tasarlayınız. Mode değerlerine göre çıkış frekansı değişecektir. Örneğin mode değeri 00 değerini aldığında clk_out çıkışında Girişin frekansının yarısını verecektir.
Mode    Clk_out (fout)
00    Fin/2
01    Fin/4
10    Fin/8
11    Fin/16
Bu soru çok başlangıç aşaması ama kaynaklarda aradığım anlatımı bulamadım kavrayamadım bir türlü konuyu. Buradaki clc_out çıkışına da mı down to ile tanımlamam gerekiyor, birde clc_in değişkeninin mode değişkeni ile ilgili ilişkisini nasıl kurabilirim.

*

muuzoo

  • Lifetime Error!
  • *****
  • 5
    • Profili Görüntüle
    • Kişisel Blog
Ynt: VHDL İle Clock Bölme
« Yanıtla #2 : 12 Kasım 2016, 23:20:09 »
Merhaba;
Clock divider ile bir uygulama ödevi aldım ama konu hakkında pek bilgiye sahip değilim.
Clk_in, Reset ve mode(1 downto 0) girişlerine clk_out çıkışına sahip bir frekans bölücü VHDL dili ile tasarlayınız. Mode değerlerine göre çıkış frekansı değişecektir. Örneğin mode değeri 00 değerini aldığında clk_out çıkışında Girişin frekansının yarısını verecektir.
Mode    Clk_out (fout)
00    Fin/2
01    Fin/4
10    Fin/8
11    Fin/16
Bu soru çok başlangıç aşaması ama kaynaklarda aradığım anlatımı bulamadım kavrayamadım bir türlü konuyu. Buradaki clc_out çıkışına da mı down to ile tanımlamam gerekiyor, birde clc_in değişkeninin mode değişkeni ile ilgili ilişkisini nasıl kurabilirim.

Aslında tasarımınız çok karışık değil. Aynı işi yapacak farklı kodlar yazılabilir. Ben basit bir değişiklik ile en baştaki kodu sizin istediğiniz hale getireceğim.
Kod: VHDL
  1. library IEEE;
  2. use IEEE.STD_LOGIC_1164.all;
  3.  
  4. -- Uncomment the following library declaration if using
  5. -- arithmetic functions with Signed or Unsigned values
  6. use IEEE.NUMERIC_STD.all;
  7.  
  8. -- Uncomment the following library declaration if instantiating
  9. -- any Xilinx leaf cells in this code.
  10. --library UNISIM;
  11. --use UNISIM.VComponents.all;
  12.  
  13. entity clkManager is
  14.   port (
  15.     iClk     : in  std_logic;           -- Main System Clock
  16.     iRst     : in  std_logic;           -- Main Reset Signal
  17.     mode  : in std_logic;            -- Mode Select
  18.     oClk   : out std_logic);           -- Output clock
  19. end clkManager;
  20.  
  21. architecture Behavioral of clkManager is
  22.   signal tmpCnt            : unsigned(3 downto 0) := "0000";
  23.  
  24. begin
  25.  
  26.   CLK_DIV : process (iclk, iRst) is
  27.   begin  -- process CLK_DIV
  28.     if iRst = '1' then           -- asynchronous reset (active low)
  29.       tmpCnt <= "0000";
  30.     elsif iclk'event and iclk = '1' then  -- rising clock edge
  31.       tmpCnt <= tmpCnt + 1;
  32.     end if;
  33.   end process CLK_DIV;
  34.  
  35.   oClk<= tmpCnt(0) when mode="00" else
  36.               tmpCnt(1) when mode="01" else
  37.               tmpCnt(2) when mode="10" else
  38.               tmpCnt(3) when mode="11";
  39.  

Daha önce bahsettiğim üzere tmpCnt basit bir sayaç ve bu sayacın ilgili bitlerini çıkış olarak dışarı alırsak basitçe bir clk bölme işlemi yapmış oluruz. Burada ki mantığı anlayabildiniz mi?

Ynt: VHDL İle Clock Bölme
« Yanıtla #3 : 13 Kasım 2016, 00:52:55 »
"library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity clcdivider is
port(
clc_in : in std_logic;
reset : in std_logic;
clc_out_div2 : out std_logic;
clc_out_div4 : out std_logic;
clc_out_div8 : out std_logic;
clc_out_div16 : out std_logic
);
 end clcdivider;

architecture clock of clcdivider is
signal mode : unsigned (3 downto 0);
begin
clock_divider: process(reset, clc_in)
begin
if (reset='0') then
mode <= ( others => '0');
elsif(rising_edge(clc_in)) then
mode <= mode + 1;
end if;
end process clock_divider;
clc_out_div2 <= mode(0);
clc_out_div4 <= mode(1);
clc_out_div8 <= mode(2);
clc_out_div16 <= mode(3);
end clock;"

Ben kodları bu şekilde yazmıştım ama birden fazla out kullanmadan yapamamıştım, yazdığınız koddaki out kısmını çözdüm daha basit olmuş. tmpCnt sayacı işi çözüyormuş. Peki bu kodlarda aynı işlemi yapar mı?
İlginiz çok teşekkür ederim :)

*

muuzoo

  • Lifetime Error!
  • *****
  • 5
    • Profili Görüntüle
    • Kişisel Blog
Ynt: VHDL İle Clock Bölme
« Yanıtla #4 : 13 Kasım 2016, 01:14:02 »
Kodunuzda yazım hataları var. Mesela mode giriş olarak tanımlı olması gerekirken tanımlanmamış. En başta kod ile alakalı olarak mode girişi olacak denmiş. Bu yüzden mode sinyal olarak tanımlamanız hatalı bir yaklaşım olmuş. Onun dışında bu yaklaşımla da olur ama bahsettiğiniz tasarım özelliklerini karşılamaz.

Ynt: VHDL İle Clock Bölme
« Yanıtla #5 : 13 Kasım 2016, 02:56:35 »
Kodunuzda yazım hataları var. Mesela mode giriş olarak tanımlı olması gerekirken tanımlanmamış. En başta kod ile alakalı olarak mode girişi olacak denmiş. Bu yüzden mode sinyal olarak tanımlamanız hatalı bir yaklaşım olmuş. Onun dışında bu yaklaşımla da olur ama bahsettiğiniz tasarım özelliklerini karşılamaz.

Anladım haklısınız. Simülasyon kısmında doğru sonuçları alamadım zaten. Yardımlarınız için teşekkür ederim. Elinize sağlık.