0

I have to develop a SDRAM controller for a class project in VHDL. But this is my first time working with VHDL, that has a very important learning curve.

I have downloaded a SDRAM controller from github (https://github.com/christianmiyoshi/SDRAM_Controller_VHDL/blob/master/sdram_controller.vhd) and I am trying to complete it.

I am trying to write a data in an address and later read it, but I cant read a single data. I dont know if my problem is in the writing or in the reading process.

Can anybody help me, please?

Thank you all!

library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity ram_controller is
port(
    clk : in std_logic;
    reset: in std_logic;
    refresh: in std_logic;
    read_write_enable: in std_logic;
    write_n: in std_logic;
    address: in std_logic_vector(21 downto 0);
    data_in: in std_logic_vector(15 downto 0);
    dqmu: in std_logic;
    dqml: in std_logic;
    ready: out std_logic;
    done: out std_logic;
    data_out: out std_logic_vector(15 downto 0);

    single_burst: in std_logic; --0 single y 1 burst

    SDRAM_CKE: out std_logic;
    SDRAM_CS_N: out std_logic;
    SDRAM_RAS_N: out std_logic;
    SDRAM_CAS_N: out std_logic;
    SDRAM_WE_N: out std_logic;
    SDRAM_BA: out std_logic_vector(1 downto 0);
    SDRAM_SA: out std_logic_vector(11 downto 0);
    SDRAM_DQ: inout std_logic_vector(15 downto 0);
    SDRAM_DQM: out std_logic_vector(1 downto 0)
);
end entity;


architecture behavior of ram_controller is


type state_type is (init_ckeLow, init_stableClock, init_wait, init_nopCommand, init_prechargeAll, init_refresh_1, init_mode, init_refresh_2, idle, refresh_state, activate_row, activate_rcd, read_write, ras1, ras2, precharge);
signal state: state_type := init_ckeLow;

signal ticks: std_logic_vector(7 downto 0) := (others => '0');
signal ticks_ref: integer := 0;
signal ticks_ref_refresh: integer := 0;


constant burstMode: std_logic := '0';
constant casLatency: std_logic_vector(2 downto 0) := "010";
constant burstType: std_logic := '0';
constant burstLength: std_logic_vector(2 downto 0) := "000";

--signal highz_output: std_logic:= '0';

constant MODE_REG: std_logic_vector(11 downto 0) := "00" & burstMode & "00" & casLatency & burstType & burstLength;
constant MODE_REG_BURST: std_logic_vector(11 downto 0) := "000000100111";
signal command: std_logic_vector(3 downto 0);
signal row: std_logic_vector(11 downto 0);
signal column: std_logic_vector(7 downto 0);
signal bank: std_logic_vector(1 downto 0);

signal sd_busdir_x: std_logic:='0';

-- Command truth table
-- CS_N, RAS_N, CAS_N, WE_N
constant CMD_ACTIVATE:  std_logic_vector(3 downto 0) := "0011";
constant CMD_PRECHARGE: std_logic_vector(3 downto 0) := "0010";
constant CMD_WRITE:     std_logic_vector(3 downto 0) := "0100";
constant CMD_READ:      std_logic_vector(3 downto 0) := "0101";
constant CMD_MODE:      std_logic_vector(3 downto 0) := "0000";
constant CMD_NOP:       std_logic_vector(3 downto 0) := "0111";
constant CMD_REFRESH:   std_logic_vector(3 downto 0) := "0001";

signal address_buffer: std_logic_vector(21 downto 0) := (others => '0');
signal data_in_buffer: std_logic_vector(15 downto 0) := (others => '0');
signal dqu_buffer: std_logic := '0';
signal dql_buffer: std_logic := '0';
signal ready_buffer: std_logic := '0';
signal done_buffer: std_logic := '0';
signal data_out_buffer: std_logic_vector(15 downto 0) := (others => '0');

signal CKE: std_logic;
signal CS_N: std_logic;
signal RAS_N: std_logic;
signal CAS_N: std_logic;
signal WE_N: std_logic;
signal BA: std_logic_vector(1 downto 0);
signal SA: std_logic_vector(11 downto 0);
signal DQ: std_logic_vector(15 downto 0);
signal DQM: std_logic_vector(1 downto 0);
signal contador : std_logic_vector(15 downto 0) := x"0000";
signal modo: std_logic := '0';
begin

(CS_N, RAS_N, CAS_N, WE_N) <= command;

SDRAM_CKE <= CKE;
SDRAM_CS_N <= CS_N;
SDRAM_RAS_N <= RAS_N;
SDRAM_CAS_N <= CAS_N;
SDRAM_WE_N <= WE_N;
SDRAM_BA <= BA;
SDRAM_SA <= SA;
--SDRAM_DQ <= DQ;
SDRAM_DQM <= DQM;


--SA <= address_buffer;
SDRAM_DQ <= data_in_buffer when sd_busdir_x = '1' else (others => 'Z');
DQM <= dqu_buffer & dql_buffer;


ready <= ready_buffer;
done <= done_buffer;
data_out <= data_out_buffer;



bank <= address(21 downto 20);
row <= address(19 downto 8);
column <= address(7 downto 0);

process(clk, reset)
begin
if reset = '0' then
    state <= init_ckeLow;
    ticks_ref <= 0;
elsif rising_edge(clk) then
    if ticks_ref /= 0 then
        ticks_ref <= ticks_ref - 1;
    else
        -- Micron datasheet instructions
        -- Frequency = 100 Mhz => period of 10ns
        -- 1: Apply Vdd and Vddq simultaneously
        case state is
            when init_ckeLow =>
                -- 2: Assert and hold CKE ant LVTTL logic low
                ticks_ref <= 10;
                CKE <= '0';             
                state <= init_stableClock;
            when init_stableClock =>    
                -- 3: Provide stable clock
                ticks_ref <= 10;
                state <= init_wait;
            when init_wait=>
                -- 4: Wait at least 100us
                -- 5: bring cke high at some point of the period
                -- with command inhibit or nop
                --ticks_ref <= 10000;
                ticks_ref <= 2; -- debugadd
                state <= init_nopCommand;
            when init_nopCommand =>
                --ticks_ref <= 10000;
                ticks_ref <= 2; -- debug
                CKE <= '1';
                command <= CMD_NOP;
                state <= init_prechargeAll;
            when init_prechargeAll =>
                -- 6: perform precharge all
                -- 7: wait at leas t_RP
                command <= CMD_PRECHARGE;
                BA <= "00";
                SA(10) <= '1'; -- all banks
                ticks_ref <= 2;
                ticks_ref_refresh <= 8;
                state <= init_refresh_1;
            when init_refresh_1 =>
                -- auto refresj period: < 64 ns
                if ticks_ref_refresh = 0 then
                    state <= init_mode;
                else
                    ticks_ref_refresh <= ticks_ref_refresh - 1;
                    command <= CMD_REFRESH;
                    ticks_ref <= 7;
                end if;
            when init_mode =>
                command <= CMD_MODE;
                if single_burst = '0' then
                    SA <= MODE_REG;
                    modo <= '0';
                else
                    SA <= MODE_REG_BURST;
                    modo <= '1';
                end if;
                BA <= "00";
                ticks_ref <= 2;
                ticks_ref_refresh <= 8;
                state <= init_refresh_2;
            when init_refresh_2 =>
                if ticks_ref_refresh = 0 then
                    state <= idle;
                    --done_buffer <= '1';
                else
                    ticks_ref_refresh <= ticks_ref_refresh - 1;
                    command <= CMD_REFRESH;
                    ticks_ref <= 7;
                end if;
            when idle =>
                done_buffer <= '0';
                contador <= (others => '0');
                if read_write_enable = '1' then
                    -- tras: active to precharge: 45 ns min, 120000ns max
                    state <= activate_row;
                    command <= CMD_ACTIVATE;
                    SA <= row;
                    BA <= bank;
                    --done_buffer <= '0';
                elsif refresh = '1' then
                    state <= refresh_state;
                    command <= CMD_REFRESH;
                    ticks_ref <= 7;
                    --done_buffer <= '0';
                end if;
            when refresh_state =>
                state <= idle;
                --done_buffer <= '1';
            when activate_row =>
                --trcd 20 ns
                command <= CMD_NOP;
                state <= activate_rcd;
                data_in_buffer <= data_in;
                ticks_ref <= 1;
            when activate_rcd =>
                -- trcs = 20ns min
                state <=read_write;
                SA <= "0000" & column;
                if write_n = '0' then
                    command <= CMD_WRITE;

                    dqu_buffer <=  dqmu;
                    dql_buffer <= dqml;
                    sd_busdir_x <= '1';  
                else
                    command <= CMD_READ;
                end if;

            when read_write =>
                --command <= CMD_NOP;
                state <= ras1;
                --if modo='0' then
                    --sd_busdir_x <= '0';
                --end if;
            when ras1 =>
                state <= ras2;
                command <= CMD_NOP;
            when ras2 =>
                -- trp = 20ns min
                if modo='1' and contador <= x"00FF" then
                    data_in_buffer <= data_in;
                    state <= ras2;
                    contador <= contador +1;
                else
                    contador <= (others => '0');
                    state <= precharge;
                    sd_busdir_x <= '0';
                    command <= CMD_PRECHARGE;
                    SA(10) <= '1';
                    data_out_buffer <= SDRAM_DQ;
                    ticks_ref <= 2;
                end if;
            when precharge =>
                state <= idle;
                done_buffer <= '1';
                ticks_ref <= 1;
        end case;
    end if; 
end if;
end process;




end architecture;

[enter image description here][1]


  [1]: https://i.stack.imgur.com/CaqqL.png
  • 1
    What specifically is not working? Do you know what it's supposed to do? And how does the functionality of your code deviate from that? When developing VHDL (and especially stuff as complex as a DRAM controller), it's a good practice to start with a testbench, that lets you develop this in simulation. You basically need an SDRAM VHDL component that you then pair with your controller, simulate, and then get it to work on your development computer, before loading it into an actual FPGA. – sonicwave Nov 13 '19 at 11:20
  • Find a VHDL simulation model of an SDRAM (micron.com used to have them on their website) and instantiate it and your controller in a testbench. Write tests to exercise your controller; from there on it's just good old fashioned debugging. –  Nov 15 '19 at 14:17

0 Answers0