FPGA ile ADC128S022 Entegresinin Kontrolü

ADC128S022, National Semiconductor tarafından üretilen 14 bitlik ve 200ksps hızına sahip bir ADC entegresidir. Dahili multiplexer sayesinde 8 adet girişden veri okunabilir. İletişim olarak SPI'ı destekler. İç yapısı aşağıdaki gibidir:

İletişim protokolünün zamanlama diyagramı şu şekildedir:

ADC çevrim hızı 50ksps ile 200ksps arasında, SCLK sinyalin hızı ile ayarlanabilir. Her bir çevrim 16 clockda gerçekleşir. Bu uygulamada SCLK hızı 3.125Mhz olarak seçilmiş ve ADC hızı 195ksps olarak ayarlanmıştır. İletişimin  3, 4 ve 5. adımlarında DIN sinyalinde, okunmak istenen ADC kanalının adresi gönderilir. 12 bitlik ADC değeri 5. adımdan itibaren DOUT sinyalinden okunur. VHDL kodu:

--Kütüphaneler
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL; 

entity ADC is
    port(Clk : in std_logic;                          --Clock Girişi
        CS, SCLK, DIN : out std_logic;                --ADC Entegresinin CS, SCLK ve DIN Girişleri
        DOUT : in std_logic;                          --ADC Entegresinin DOUT Çıkışı
        LedOut : out std_logic_vector(11 downto 0));  --ADC'den okunan 12 bitlik sinyal
end ADC;

architecture Behavioral of ADC is

    --SCLK sinyali
    signal ADCClock : std_logic := '1';
    
    --Okunacak ADC kanalın adresi
    constant ADCChannel : std_logic_vector(2 downto 0) := "010";

begin

    --Sürekli veri okuma yapılacağından 
    --CS biti '0' yapıldı
    CS <= '0';
    
    --SCLK sinyal ataması
    SCLK <= ADCClock;
    
    --SCLK için clock bölücü process
    --50Mhz giriş sinyalini 3.125Mhz'e düşürür
    --Her bir ADC çevrimi 16 clockda yapılır
    --ADC örnekleme sayısı, 3.125Mhz / 16 = 195ksps
    process(Clk, ADCClock)
    variable ClkCnt : unsigned(3 downto 0) := (others => '0');
    variable NextClkCnt : unsigned(3 downto 0) := "0001";
    begin
        if rising_edge(Clk) then
    --Yükselen kenar ile sonraki count değerini, şimdiki count değerine yükle
            ClkCnt := NextClkCnt;
   --Eğer count değeri 7'ye ulaşmış ise ADCClock sinyalini tersle    ve
    --sonraki count değerine '0' yükle
            if ClkCnt = 7 then
                NextClkCnt := (others => '0');
                ADCClock <= not ADCClock;
    --Count değeri 15'e ulaşmamış ise sonraki count değerini 1 arttır
            else 
                NextClkCnt := ClkCnt + 1;
            end if;            
        end if;
    end process;
    
    
    --ADC entegresi ile iletişim kuran process
    process(ADCClock, DOUT)
    variable State : unsigned(4 downto 0) := (others => '0');
    variable NextState : unsigned(4 downto 0) := "00001";
    begin
    
    --Durum sayacı
    --1 ADC okuması toplamda 16 durumda gerçekleşir
    if falling_edge(ADCClock) then
    --Düşen kenar ile sonraki durumu, şimdiki duruma yükle
        State := NextState;
    --Eğer 16. duruma gelindi ise sonraki durumu 1 yap
        if State = 16 then
            NextState := "00001";
    --16. duruma gelinmedi ise sonraki durumu 1 arttır
        else
            NextState := State + 1;
        end if;
    end if;
    
    --3, 4 ve 5. adımlarda okunacak ADC kanalının
    --adresi DIN sinyalinden gönderilir.
    if (State > 2) and (State < 6) then
    --ADC kanal bilgisinin ilk olarak 2. biti ve son olarak
    --0. biti gönderileceğinden dolayı, ADC kanal bilgisinin
    --bitleri terslenmiş şekilde DIN sinyaline gönderilir
        DIN <= ADCChannel(to_integer(5 - State));
    else
        DIN <= '0';
    end if;
    
    --5, 6, .. 16. adımlarda DOUT sinyalinden
    --veriler alınmaya başlar
    if (State > 4) and (State < 17) then
        if rising_edge(ADCClock) then
    --Veriler tersden geldiğinden, yani ilk olarak 11. bit
    --son olarak 0. bit geldiğinden dolayı gelen veriler
    --ters çevrilerek LedOut sinyaline atanır
            LedOut(to_integer(16 - State)) <= DOUT;
        end if;
    end if;
    
    end process;
        
end Behavioral;

Tasarımın Quartus-II programı tarafından oluşturulmuş RTL şeması:

Video:

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.