Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
20817 Discussions

SDRAM Controller Intel FPGA IP not working as expected


I'm writing a simple RAM and VGA testing module.
At first data gets written to the SDRAM (repeatedly 0 to 4095) and then it's read from the sdram and written to a FIFO to show it as pixels on the 4 bit VGA.

Because it didn't work properly I analyzed it in Signal Tap.
The expected output would be a 0 at read_pointer 0, a 10 at read_pointer 10 and so on.
At first the outputs seemed random, but I realized that I forgot the phase shift in the sdram clock. Now it's still wrong but in another, maybe better way.
I extracted the phase shift from the SDRAM test application that is delivered together with the board.

The error now is that the output numbers go up as expected, but the timing is wrong. While the readdatavalid signal is HIGH the data is obviously not correct but old.

As you can see in the Signal Tap screenshot, the 1 as ram output is visible when the read_pointer hits 4 but the ram_rdval signal is always high thus I can't trust it.

You can also see that the rdval signal is low at read_pointer 0 until the 0 arrives at the output but it doesnt go low afterwards.

I can't find the error and don't have starting point. Is it a wrongly tuned PLL? Is there some fault in my sdram controller config?

I'm using Quartus 20.1 lite and a DE10-lite board that uses a 10M50DAF484C7G FPGA and a issi 45S16320d sdram.
I can't use a newer Quartus version because the SDRAM Controller component was moved to the paid version.


Code of the main entity:

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

entity ram_vga_demonstrator is
  port (
    clock_50 : in    std_logic;
    reset_n  : in    std_logic;

    dram_addr  : out   std_logic_vector(12 downto 0);
    dram_ba    : out   std_logic_vector(1 downto 0);
    dram_cas_n : out   std_logic;
    dram_cke   : out   std_logic;
    dram_clk   : out   std_logic;
    dram_cs_n  : out   std_logic;
    dram_dq    : inout std_logic_vector(15 downto 0);
    dram_ras_n : out   std_logic;
    dram_we_n  : out   std_logic;
    dram_ldqm  : out   std_logic;
    dram_udqm  : out   std_logic;

    h_sync      : out   std_logic;
    v_sync      : out   std_logic;
    valid_pixel : out   std_logic;
    vga_out     : out   std_logic_vector(11 downto 0);

    ----------------- flags -----------------------------
    wr_full   : out   std_logic;
    rd_empty  : out   std_logic;
    ram_rdval : out   std_logic;

    data_out : out   std_logic_vector(15 downto 0);
    data_in  : in    std_logic_vector(9 downto 0)   
    end entity ram_vga_demonstrator;

   architecture arch of ram_vga_demonstrator is

  type modes is (read_t, write_t);

  ----------------- clocks ------------------------------
  signal clk143_s        : std_logic;
  signal clk25_175_s     : std_logic;
  signal clk_143_shift_s : std_logic; --! Signal zur Versorgnung von Signaltap

  signal mode_s                              : modes := write_t;
  signal sdram_addr_s                        : std_logic_vector(24 downto 0);
  signal sdram_be_n_s                        : std_logic_vector(1 downto 0);
  signal sdram_cs_s                          : std_logic;
  signal sdram_rdval_s,    sdram_wait_s      : std_logic;
  signal sdram_re_n_s,     sdram_we_n_s      : std_logic;
  signal sdram_readdata_s, sdram_writedata_s : std_logic_vector(15 downto 0);
  signal dram_dqm_s                          : std_logic_vector(1 downto 0);
  signal sdram_out_data_s                    : std_logic_vector(15 downto 0);


  signal fifo_data_s : std_logic_vector(15 downto 0);
  -- signal fifo_rdclk_s   : std_logic;
  signal fifo_rdreq_s : std_logic;
  -- signal fifo_wrclk_s   : std_logic;
  signal fifo_wrreq_s          : std_logic;
  signal fifo_q_s              : std_logic_vector(15 downto 0);
  signal fifo_rdempty_s        : std_logic;
  signal fifo_wrfull_s         : std_logic;
  signal fifo_wrusedw_s        : std_logic_vector(7 downto 0);
  signal fifo_rdusedw_s        : std_logic_vector(7 downto 0);
  signal fifo_wralmostfull_s   : std_logic;
  signal fifo_rd_almostempty_s : std_logic;

  signal valid_pixel_s : std_logic;
  signal pixel_data_s  : std_logic_vector(11 downto 0);

  signal ram_write_pointer_s : integer range 0 to 307199; -- 480*640 = 307.200

  signal ram_read_pointer_s        : integer range -1 to 307199; -- 480*640 = 307.200
  signal ram_write_ready_s         : std_logic;
  signal vga_out_almost_finished_s : std_logic;

  signal rgb_count_s : integer range 0 to 4094;

  component ramsys is
    port (
      clk_clk             : in    std_logic                     := 'X';
      clk_system_clk   : out   std_logic;
      clk_25_175_clk      : out   std_logic;
      reset_reset_n       : in    std_logic                     := 'X';
      sdram_address       : in    std_logic_vector(24 downto 0) := (others => 'X');
      sdram_byteenable_n  : in    std_logic_vector(1 downto 0)  := (others => 'X');
      sdram_chipselect    : in    std_logic                     := 'X';
      sdram_writedata     : in    std_logic_vector(15 downto 0) := (others => 'X');
      sdram_read_n        : in    std_logic                     := 'X';
      sdram_write_n       : in    std_logic                     := 'X';
      sdram_readdata      : out   std_logic_vector(15 downto 0);
      sdram_readdatavalid : out   std_logic;
      sdram_waitrequest   : out   std_logic;
      wire_addr           : out   std_logic_vector(12 downto 0);
      wire_ba             : out   std_logic_vector(1 downto 0);
      wire_cas_n          : out   std_logic;
      wire_cke            : out   std_logic;
      wire_cs_n           : out   std_logic;
      wire_dq             : inout std_logic_vector(15 downto 0) := (others => 'X');
      wire_dqm            : out   std_logic_vector(1 downto 0);
      wire_ras_n          : out   std_logic;
      wire_we_n           : out   std_logic;
      clk_sdram_clk         : out   std_logic
  end component ramsys;

  component fifo is
    port (
      data    : in    std_logic_vector(15 downto 0);
      rdclk   : in    std_logic;
      rdreq   : in    std_logic;
      wrclk   : in    std_logic;
      wrreq   : in    std_logic;
      q       : out   std_logic_vector(15 downto 0);
      rdempty : out   std_logic;
      wrfull  : out   std_logic;
      wrusedw : out   std_logic_vector(7 downto 0);
      rdusedw : out   std_logic_vector(7 downto 0)
  end component fifo;

  component vga_controller is
    port (
      clock_25    : in    std_logic;
      reset_n     : in    std_logic;
      h_sync      : out   std_logic;
      v_sync      : out   std_logic;
      valid_pixel : out   std_logic;
      data_in     : in    std_logic_vector(11 downto 0);
      data_out    : out   std_logic_vector(11 downto 0)
  end component vga_controller;


  u0 : component ramsys
    port map (
      clk_clk             => clock_50,
      reset_reset_n       => reset_n,
      clk_system_clk         => clk_system_s,
      clk_25_175_clk      => clk25_175_s,
      clk_sdram_clk   => clk_sdram_s,
      wire_addr           => dram_addr,
      wire_ba             => dram_ba,
      wire_cas_n          => dram_cas_n,
      wire_cke            => dram_cke,
      wire_cs_n           => dram_cs_n,
      wire_dq             => dram_dq,
      wire_dqm            => dram_dqm_s,
      wire_ras_n          => dram_ras_n,
      wire_we_n           => dram_we_n,
      sdram_address       => sdram_addr_s,
      sdram_byteenable_n  => sdram_be_n_s,
      sdram_chipselect    => sdram_cs_s,
      sdram_writedata     => sdram_writedata_s,
      sdram_read_n        => sdram_re_n_s,
      sdram_write_n       => sdram_we_n_s,
      sdram_readdata      => sdram_readdata_s,
      sdram_readdatavalid => sdram_rdval_s,
      sdram_waitrequest   => sdram_wait_s

  u1 : component fifo
    port map (
      data    => sdram_out_data_s,
      rdclk   => clk25_175_s,
      rdreq   => fifo_rdreq_s,
      wrclk   => clk_system_s,
      wrreq   => fifo_wrreq_s,
      q       => fifo_q_s,
      rdempty => fifo_rdempty_s,
      wrfull  => fifo_wrfull_s,
      wrusedw => fifo_wrusedw_s,
      rdusedw => fifo_rdusedw_s

  u2 : component vga_controller
    port map (
      clock_25    => clk25_175_s,
      reset_n     => reset_n,
      h_sync      => h_sync,
      v_sync      => v_sync,
      valid_pixel => valid_pixel_s,
      data_in     => pixel_data_s,
      data_out    => vga_out

  dram_ldqm    <= dram_dqm_s(0);
  dram_udqm    <= dram_dqm_s(1);
  dram_clk     <= clk_sdram_s;
  sdram_cs_s   <= '1';
  sdram_be_n_s <= "00";
  data_out     <= sdram_readdata_s;

  p_ram_flag : process (sdram_wait_s, ram_read_pointer_s) is

  end process p_ram_flag;

  p_ram : process (clk_system_s) is

    if rising_edge(clk_system_s) then

      case mode_s is

        when write_t =>

          if (sdram_wait_s = '0') then
            sdram_we_n_s <= '0';

            sdram_writedata_s <= "0000" & std_logic_vector(to_unsigned(rgb_count_s, 12));

            if (rgb_count_s < 4095) then
              rgb_count_s <= rgb_count_s + 1;
              rgb_count_s <= 0;
            end if;

            sdram_addr_s(24 downto 0) <= std_logic_vector(to_unsigned(ram_write_pointer_s, sdram_addr_s'length));

            if (ram_write_pointer_s < 307199) then
              ram_write_pointer_s <= ram_write_pointer_s + 1;
              ram_write_pointer_s <= 0;
              ram_read_pointer_s  <= 0;
              mode_s              <= read_t;
            end if;
          end if;

        when read_t =>

          sdram_we_n_s              <= '1';
          sdram_addr_s(24 downto 0) <= std_logic_vector(to_unsigned(ram_read_pointer_s, sdram_addr_s'length));

          if (sdram_rdval_s = '1' and fifo_wrfull_s = '0') then
            fifo_wrreq_s     <= '1';
            sdram_out_data_s <= sdram_readdata_s;

            if (ram_read_pointer_s < 307199) then
              ram_read_pointer_s <= ram_read_pointer_s + 1;
              ram_write_pointer_s <= 0;
              ram_read_pointer_s  <= 0;

              mode_s <= write_t;
            end if;
            fifo_wrreq_s <= '0';
          end if;

      end case;

    end if;

  end process p_ram;

  vga : process (clk25_175_s) is

    if rising_edge(clk25_175_s) then

      if (fifo_rdempty_s = '0' and valid_pixel_s = '1') then
        fifo_rdreq_s <= '1';
        pixel_data_s <= fifo_q_s(11 downto 0);
        fifo_rdreq_s <= '0';
      end if;
    end if;

  end process vga;

  wr_full   <= fifo_wrfull_s;
  rd_empty  <= fifo_rdempty_s;
  ram_rdval <= sdram_rdval_s;

end architecture arch;

qsys config:



PLL config:





SDRAM Controller IP config:



qsys output





Labels (1)
0 Kudos
5 Replies

Hi Tim,

I'm not really familiar with this application.

Usually I will always checking the timing parameter in the IP.

Does the example design working normally to verify the SDRAM is working?



0 Kudos

Hi Adzim,

thanks for your answer!

Some flaw in my timing settings was my first idea. I checked it twice and couldn't find one. I was hoping that somebody could take a look at my settings to see if I miss something. (Visible in the last screenshots).

That's the SDRAM mounted on the board:



And that's the doc I used (it's the online version of the pdf attached to the CD):

While writing this I realized that on the photo there is an 'F' as last character visible not a 'D' as in the CD docs. I couldn't spot any difference timing wise, but to be sure that's the one with an 'F':


I want to point out that the "only" problem is that the read valid signal is not reliable. The data itself seems to be correct.
I write values from 0 to 4095 and I get values from 0 to 4095, but I would expect the read valid signal to go down one clock cycle after one value was spit out and only go on again when the next one is there.
As you can see in the screenshot of Signal Tap, the read valid signal stays high although there is still the first 0 visible.

Am I misunderstanding the meaning of readvalid?


I just tried the "SDRAM_RTL_Test" design and I suppose it works as expected.

LEDR 0 is on constantly .
LEDR 1 blinks at first and then stops to be constantly on too.
LEDR 2 blinks all time

I couldn't understand the purpose of LEDR 0 but as far as I understood, LEDR 1 blinks as long as the test runs and then is either constantly on to show success (or goes off to show failure).
LEDR seems to be a heartbeat and is only constantly on if KEY 0 is pressed.




0 Kudos

Hi Tim,

I think there is a Manual that you can refer to run the test. It's should explain the purpose of LED and behavior of the SDRAM.

I think the readvalid signal will go high after the read signal is go high. It's will indicate the data is valid and available .



0 Kudos

Hello Adzim,

that's true! The problem is that the readvalid signal should go down if the next value isn't ready yet and that doesn't seem to happen.

Although I found another solution using a completely different controller, I would be interested in the cause of the issue. 

The settings of the IP are so simple, I would consider it as foolproof. If there is any chance that this is not an issue caused by me but some "bug" in the IP it may be interesting to investigate it.

0 Kudos

I have had some similar issues, my timing and waveforms are all correct though nothing is returned when after a read cycle (even when read valid is high). On a forum I saw that the Avalon-MM interface could have a minimum burst transfer for the IP core though the official documentation does not say any of this and is not great.

0 Kudos