FPGA Günlükleri – Clock Division
- 4 sene önce, Baran EKREM yazdı.
- 0 Yorum
- 2.435 Kişi Okudu
Bir önceki yazılarda dijital temelleri hatırlarken artık zamanlama işlerine de girmem gerekiyor diye düşünüyordum. Artık vakit geldi. Olayın teorisi oldukça basitmiş. Bildiğiniz sayıcı tasarlıyoruz. Her arttırma 1 Clock’da yapılsın. Bunu yükselen kenar olarak yapalım. Her yükselen kenarda sayıcıyı 1 arttıralım. 50 MHz kristal için 50 milyona kadar saydığımızda 1 saniye geçmiş olacak. Bu sayma işlemlerini farklı sayaçlarda yaparak farklı zamanlama çıktıları elde edeceğiz. Hadi zamanı bükelim!
Öncelikle VHDL ortamında Toplama, Çıkarma, Büyük – Küçük Kontrol gibi işlemler için şu kütüphaneyi eklememiz gerekiyor.
1 |
USE IEEE.STD_LOGIC_UNSIGNED.all; |
Yapacağımız zamanlama için referansımız Clock girişi olacak bunu entity kısmında şu şekilde belirtiyoruz.
1 2 3 4 5 6 |
entity Clock_Division is port ( CLK_IN : in STD_LOGIC; LED1 : OUT STD_LOGIC ); end Clock_Division; |
Sayma işlemi için bir adet sayıcıya ve bir adet sabit değere ihtiyacımız var. Sabit değer üst limitimiz olacak. Son olarak uygulama için LED’i toggle edecek bir değişkene ihtiyacımız var.
Bu değişkenleri ve sabitleri VHDL ile tanımlamak normal yazılımlardan çok farklı gözüküyor diyebilirim. Örneğin bir sabit tanımlayalım.
1 |
constant COUNT_1HZ : natural := 25000000; |
Bu tanımlamada sabit olduğunu “constant” ifadesi ile belirtiyoruz. Sabitin ismi ise “COUNT_1HZ” olarak tanımlanıyor. Değeri ise “:= 25000000” bu şekilde atanıyor ve yazılımda olduğu gibi noktalı virgül ile satır son buluyor. Son olarak NATURAL ifadesi vardır ve bu da sabitin doğal sayılar kümesinde olduğunu belirtir. POSITIVE olsaydı sıfır dahil olmazdı.
Bunun dışında 2 adet “Signal” tanımlaması olacak.
1 2 |
signal VAL_TOGGLE_1HZ : std_logic := '0'; signal COUNTER_1HZ : natural range 0 to COUNT_1HZ; |
İlk tanımlama LED durumunu tutan toggle değişkeni olacak. Bit ataması için tek tırnak kullanılıyormuş.
İkinci sinyal ise 0 dan “COUNT_1HZ” sabitine kadar sayacak olan değişken olacak ama bu signal olarak tanımlı. RTL çıktısında daha iyi anlaşılıyor. Gerisini temel MCU ve yazılımdan hatırlayacaksınız.
Algoritma ise şöyle olacak :
- Yükselen kenarı algıla.
- Sayac istenen değere ulaştı mı ?
- Evet ise sayacı sıfırla ve biti tersle.
- Hayır ise 1 arttır.
- LED çıkışına toggle bitini yükle. (VAL_TOGGLE_1HZ)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
library IEEE; use IEEE.STD_LOGIC_1164.all; USE IEEE.STD_LOGIC_UNSIGNED.all; entity Clock_Division is port ( CLK_IN : in STD_LOGIC; LED1 : OUT STD_LOGIC ); end Clock_Division; architecture karakter of Clock_Division is constant COUNT_1HZ : natural := 25000000; signal VAL_TOGGLE_1HZ : std_logic := '0'; signal COUNTER_1HZ : natural range 0 to COUNT_1HZ; begin p_1_HZ : process (CLK_IN) is begin if rising_edge(CLK_IN) then if COUNTER_1HZ = COUNT_1HZ - 1 then VAL_TOGGLE_1HZ <= not VAL_TOGGLE_1HZ; COUNTER_1HZ <= 0; else COUNTER_1HZ <= COUNTER_1HZ + 1; end if; end if; end process p_1_HZ; LED1 <= VAL_TOGGLE_1HZ; end karakter; |
RTL Çıktısı :
Eğer birden çok zamanlama gerekirse şu şekilde yapılabilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
library IEEE; use IEEE.STD_LOGIC_1164.all; USE IEEE.STD_LOGIC_UNSIGNED.all; entity Clock_Division is port ( CLK_IN : in STD_LOGIC; LED1 : OUT STD_LOGIC; LED2 : OUT STD_LOGIC ); end Clock_Division; architecture karakter of Clock_Division is constant COUNT_1HZ : natural := 25000000; constant COUNT_2HZ : natural := 12500000; signal VAL_TOGGLE_1HZ : std_logic := '0'; signal VAL_TOGGLE_2HZ : std_logic := '0'; signal COUNTER_1HZ : natural range 0 to COUNT_1HZ; signal COUNTER_2HZ : natural range 0 to COUNT_2HZ; begin p_1_HZ : process (CLK_IN) is begin if rising_edge(CLK_IN) then if COUNTER_1HZ = COUNT_1HZ - 1 then VAL_TOGGLE_1HZ <= not VAL_TOGGLE_1HZ; COUNTER_1HZ <= 0; else COUNTER_1HZ <= COUNTER_1HZ + 1; end if; end if; end process p_1_HZ; p_2_HZ : process (CLK_IN) is begin if rising_edge(CLK_IN) then if COUNTER_2HZ = COUNT_2HZ - 1 then VAL_TOGGLE_2HZ <= not VAL_TOGGLE_2HZ; COUNTER_2HZ <= 0; else COUNTER_2HZ <= COUNTER_2HZ + 1; end if; end if; end process p_2_HZ; LED1 <= VAL_TOGGLE_1HZ; LED2 <= VAL_TOGGLE_2HZ; end karakter; |
RTL Çıktısı :
Logic Analyzer Çıktısı :
Çıktılara bakacak olursak her şey yolunda gözüküyor. Şimdilik bu kadar.
Esen kalın.