I am working with a DE0-nano board, on which is a Cyclone IV EP4CE22F17C6 FPGA, connected to an ISSI IS42S16160G-7TLI 16Mx16 SDRAM chip. In order to setup the communication between the FPGA, I've started with a simple program which allows me to initialize the SDRAM mode, then fill the whole memory with the first 16M integers.
The SDRAM core controller I've chosen to use is this one : https://github.com/nullobject/sdram-fpga. It's a simple VHDL SDRAM core, that writes/reads with 2 words bursts. I did a few changes to the code : removed the line 229 next_state <= state;
, and the line 232 next_cmd <= CMD_NOP;
(while putting back this line in the fsm wherever it was required). Here is the modified code :
-- __ __ __ __ __ __
-- /\ "-.\ \ /\ \/\ \ /\ \ /\ \
-- \ \ \-. \ \ \ \_\ \ \ \ \____ \ \ \____
-- \ \_\\"\_\ \ \_____\ \ \_____\ \ \_____\
-- \/_/ \/_/ \/_____/ \/_____/ \/_____/
-- ______ ______ __ ______ ______ ______
-- /\ __ \ /\ == \ /\ \ /\ ___\ /\ ___\ /\__ _\
-- \ \ \/\ \ \ \ __< _\_\ \ \ \ __\ \ \ \____ \/_/\ \/
-- \ \_____\ \ \_____\ /\_____\ \ \_____\ \ \_____\ \ \_\
-- \/_____/ \/_____/ \/_____/ \/_____/ \/_____/ \/_/
--
-- https://joshbassett.info
-- https://twitter.com/nullobject
-- https://github.com/nullobject
--
-- Copyright (c) 2020 Josh Bassett
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
-- This SDRAM controller provides a symmetric 32-bit synchronous read/write
-- interface for a 16Mx16-bit SDRAM chip (e.g. AS4C16M16SA-6TCN, IS42S16400F,
-- etc.).
entity sdram is
generic (
-- clock frequency (in MHz)
--
-- This value must be provided, as it is used to calculate the number of
-- clock cycles required for the other timing values.
CLK_FREQ : real;
-- 32-bit controller interface
ADDR_WIDTH : natural := 23;
DATA_WIDTH : natural := 32;
-- SDRAM interface
SDRAM_ADDR_WIDTH : natural := 13;
SDRAM_DATA_WIDTH : natural := 16;
SDRAM_COL_WIDTH : natural := 9;
SDRAM_ROW_WIDTH : natural := 13;
SDRAM_BANK_WIDTH : natural := 2;
-- The delay in clock cycles, between the start of a read command and the
-- availability of the output data.
CAS_LATENCY : natural := 2; -- 2=below 133MHz, 3=above 133MHz
-- The number of 16-bit words to be bursted during a read/write.
BURST_LENGTH : natural := 2;
-- timing values (in nanoseconds)
--
-- These values can be adjusted to match the exact timing of your SDRAM
-- chip (refer to the datasheet).
T_DESL : real := 100000.0; -- startup delay
T_MRD : real := 14.0; -- mode register cycle time
T_RC : real := 60.0; -- row cycle time
T_RCD : real := 15.0; -- RAS to CAS delay
T_RP : real := 15.0; -- precharge to activate delay
T_WR : real := 15.0; -- write recovery time
T_REFI : real := 7800.0 -- average refresh interval
);
port (
-- reset
reset : in std_logic := '0';
-- clock
clk : in std_logic;
-- address bus
addr : in unsigned(ADDR_WIDTH-1 downto 0);
-- input data bus
data : in std_logic_vector(DATA_WIDTH-1 downto 0);
-- When the write enable signal is asserted, a write operation will be performed.
we : in std_logic;
-- When the request signal is asserted, an operation will be performed.
req : in std_logic;
-- The acknowledge signal is asserted by the SDRAM controller when
-- a request has been accepted.
ack : out std_logic;
-- The valid signal is asserted when there is a valid word on the output
-- data bus.
valid : out std_logic;
-- output data bus
q : out std_logic_vector(DATA_WIDTH-1 downto 0);
-- SDRAM interface (e.g. AS4C16M16SA-6TCN, IS42S16400F, etc.)
sdram_a : out unsigned(SDRAM_ADDR_WIDTH-1 downto 0);
sdram_ba : out unsigned(SDRAM_BANK_WIDTH-1 downto 0);
sdram_dq : inout std_logic_vector(SDRAM_DATA_WIDTH-1 downto 0);
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_dqml : out std_logic;
sdram_dqmh : out std_logic
);
end sdram;
architecture arch of sdram is
function ilog2(n : natural) return natural is
begin
return natural(ceil(log2(real(n))));
end ilog2;
subtype command_t is std_logic_vector(3 downto 0);
-- commands
constant CMD_DESELECT : command_t := "1---";
constant CMD_LOAD_MODE : command_t := "0000";
constant CMD_AUTO_REFRESH : command_t := "0001";
constant CMD_PRECHARGE : command_t := "0010";
constant CMD_ACTIVE : command_t := "0011";
constant CMD_WRITE : command_t := "0100";
constant CMD_READ : command_t := "0101";
constant CMD_STOP : command_t := "0110";
constant CMD_NOP : command_t := "0111";
-- the ordering of the accesses within a burst
constant BURST_TYPE : std_logic := '0'; -- 0=sequential, 1=interleaved
-- the write burst mode enables bursting for write operations
constant WRITE_BURST_MODE : std_logic := '0'; -- 0=burst, 1=single
-- the value written to the mode register to configure the memory
constant MODE_REG : unsigned(SDRAM_ADDR_WIDTH-1 downto 0) := (
"000" &
WRITE_BURST_MODE &
"00" &
to_unsigned(CAS_LATENCY, 3) &
BURST_TYPE &
to_unsigned(ilog2(BURST_LENGTH), 3)
);
-- calculate the clock period (in nanoseconds)
constant CLK_PERIOD : real := 1.0/CLK_FREQ*1000.0;
-- the number of clock cycles to wait before initialising the device
constant INIT_WAIT : natural := natural(ceil(T_DESL/CLK_PERIOD));
-- the number of clock cycles to wait while a LOAD MODE command is being
-- executed
constant LOAD_MODE_WAIT : natural := natural(ceil(T_MRD/CLK_PERIOD));
-- the number of clock cycles to wait while an ACTIVE command is being
-- executed
constant ACTIVE_WAIT : natural := natural(ceil(T_RCD/CLK_PERIOD));
-- the number of clock cycles to wait while a REFRESH command is being
-- executed
constant REFRESH_WAIT : natural := natural(ceil(T_RC/CLK_PERIOD));
-- the number of clock cycles to wait while a PRECHARGE command is being
-- executed
constant PRECHARGE_WAIT : natural := natural(ceil(T_RP/CLK_PERIOD));
-- the number of clock cycles to wait while a READ command is being executed
constant READ_WAIT : natural := CAS_LATENCY+BURST_LENGTH;
-- the number of clock cycles to wait while a WRITE command is being executed
constant WRITE_WAIT : natural := BURST_LENGTH+natural(ceil((T_WR+T_RP)/CLK_PERIOD));
-- the number of clock cycles before the memory controller needs to refresh
-- the SDRAM
constant REFRESH_INTERVAL : natural := natural(floor(T_REFI/CLK_PERIOD))-10;
type state_t is (INIT, MODE, IDLE, ACTIVE, READ, WRITE, REFRESH);
-- state signals
signal state, next_state : state_t;
-- command signals
signal cmd, next_cmd : command_t := CMD_NOP;
-- control signals
signal start : std_logic;
signal load_mode_done : std_logic;
signal active_done : std_logic;
signal refresh_done : std_logic;
signal first_word : std_logic;
signal read_done : std_logic;
signal write_done : std_logic;
signal should_refresh : std_logic;
-- counters
signal wait_counter : natural range 0 to 1048575;
signal refresh_counter : natural range 0 to 1023;
-- registers
signal addr_reg : unsigned(SDRAM_COL_WIDTH+SDRAM_ROW_WIDTH+SDRAM_BANK_WIDTH-1 downto 0);
signal data_reg : std_logic_vector(DATA_WIDTH-1 downto 0);
signal we_reg : std_logic;
signal q_reg : std_logic_vector(DATA_WIDTH-1 downto 0);
-- aliases to decode the address register
alias col : unsigned(SDRAM_COL_WIDTH-1 downto 0) is addr_reg(SDRAM_COL_WIDTH-1 downto 0);
alias row : unsigned(SDRAM_ROW_WIDTH-1 downto 0) is addr_reg(SDRAM_COL_WIDTH+SDRAM_ROW_WIDTH-1 downto SDRAM_COL_WIDTH);
alias bank : unsigned(SDRAM_BANK_WIDTH-1 downto 0) is addr_reg(SDRAM_COL_WIDTH+SDRAM_ROW_WIDTH+SDRAM_BANK_WIDTH-1 downto SDRAM_COL_WIDTH+SDRAM_ROW_WIDTH);
begin
-- state machine
fsm : process (state, wait_counter, req, we_reg, load_mode_done, active_done, refresh_done, read_done, write_done, should_refresh)
begin
case state is
-- execute the initialisation sequence
when INIT =>
if wait_counter = 0 then
next_cmd <= CMD_DESELECT;
elsif wait_counter = INIT_WAIT-1 then
next_cmd <= CMD_PRECHARGE;
elsif wait_counter = INIT_WAIT+PRECHARGE_WAIT-1 then
next_cmd <= CMD_AUTO_REFRESH;
elsif wait_counter = INIT_WAIT+PRECHARGE_WAIT+REFRESH_WAIT-1 then
next_cmd <= CMD_AUTO_REFRESH;
elsif wait_counter = INIT_WAIT+PRECHARGE_WAIT+REFRESH_WAIT+REFRESH_WAIT-1 then
next_state <= MODE;
next_cmd <= CMD_LOAD_MODE;
end if;
-- load the mode register
when MODE =>
if load_mode_done = '1' then
next_state <= IDLE;
next_cmd <= CMD_NOP;
end if;
-- wait for a read/write request
when IDLE =>
if should_refresh = '1' then
next_state <= REFRESH;
next_cmd <= CMD_AUTO_REFRESH;
elsif req = '1' then
next_state <= ACTIVE;
next_cmd <= CMD_ACTIVE;
end if;
-- activate the row
when ACTIVE =>
if active_done = '1' then
if we_reg = '1' then
next_state <= WRITE;
next_cmd <= CMD_WRITE;
else
next_state <= READ;
next_cmd <= CMD_READ;
end if;
end if;
-- execute a read command
when READ =>
if read_done = '1' then
if should_refresh = '1' then
next_state <= REFRESH;
next_cmd <= CMD_AUTO_REFRESH;
elsif req = '1' then
next_state <= ACTIVE;
next_cmd <= CMD_ACTIVE;
else
next_state <= IDLE;
next_cmd <= CMD_NOP;
end if;
end if;
-- execute a write command
when WRITE =>
if write_done = '1' then
if should_refresh = '1' then
next_state <= REFRESH;
next_cmd <= CMD_AUTO_REFRESH;
elsif req = '1' then
next_state <= ACTIVE;
next_cmd <= CMD_ACTIVE;
else
next_state <= IDLE;
next_cmd <= CMD_NOP;
end if;
end if;
-- execute an auto refresh
when REFRESH =>
if refresh_done = '1' then
if req = '1' then
next_state <= ACTIVE;
next_cmd <= CMD_ACTIVE;
else
next_state <= IDLE;
next_cmd <= CMD_NOP;
end if;
end if;
end case;
end process;
-- latch the next state
latch_next_state : process (clk, reset)
begin
if reset = '1' then
state <= INIT;
cmd <= CMD_NOP;
elsif rising_edge(clk) then
state <= next_state;
cmd <= next_cmd;
end if;
end process;
-- the wait counter is used to hold the current state for a number of clock
-- cycles
update_wait_counter : process (clk, reset)
begin
if reset = '1' then
wait_counter <= 0;
elsif rising_edge(clk) then
if state /= next_state then -- state changing
wait_counter <= 0;
else
wait_counter <= wait_counter + 1;
end if;
end if;
end process;
-- the refresh counter is used to periodically trigger a refresh operation
update_refresh_counter : process (clk, reset)
begin
if reset = '1' then
refresh_counter <= 0;
elsif rising_edge(clk) then
if state = REFRESH and wait_counter = 0 then
refresh_counter <= 0;
else
refresh_counter <= refresh_counter + 1;
end if;
end if;
end process;
-- latch the rquest
latch_request : process (clk)
begin
if rising_edge(clk) then
if start = '1' then
-- we need to multiply the address by two, because we are converting
-- from a 32-bit controller address to a 16-bit SDRAM address
addr_reg <= shift_left(resize(addr, addr_reg'length), 1);
data_reg <= data;
we_reg <= we;
end if;
end if;
end process;
-- latch the output data as it's bursted from the SDRAM
latch_sdram_data : process (clk)
begin
if rising_edge(clk) then
if state = READ then
if first_word = '1' then
q_reg(31 downto 16) <= sdram_dq;
valid <= '0';
elsif read_done = '1' then
q_reg(15 downto 0) <= sdram_dq;
valid <= '1';
end if;
else
valid <= '0';
end if;
end if;
end process;
-- set wait signals
load_mode_done <= '1' when wait_counter = LOAD_MODE_WAIT-1 else '0';
active_done <= '1' when wait_counter = ACTIVE_WAIT-1 else '0';
refresh_done <= '1' when wait_counter = REFRESH_WAIT-1 else '0';
first_word <= '1' when wait_counter = CAS_LATENCY else '0';
read_done <= '1' when wait_counter = READ_WAIT-1 else '0';
write_done <= '1' when wait_counter = WRITE_WAIT-1 else '0';
-- the SDRAM should be refreshed when the refresh interval has elapsed
should_refresh <= '1' when refresh_counter >= REFRESH_INTERVAL-1 else '0';
-- a new request is only allowed at the end of the IDLE, READ, WRITE, and
-- REFRESH states
start <= '1' when (state = IDLE) or
(state = READ and read_done = '1') or
(state = WRITE and write_done = '1') or
(state = REFRESH and refresh_done = '1') else '0';
-- assert the acknowledge signal at the beginning of the ACTIVE state
ack <= '1' when state = ACTIVE and wait_counter = 0 else '0';
-- set output data
q <= q_reg;
-- deassert the clock enable at the beginning of the INIT state
sdram_cke <= '0' when state = INIT and wait_counter = 0 else '1';
-- set SDRAM control signals
(sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n) <= cmd;
-- set SDRAM bank
with state select
sdram_ba <=
bank when ACTIVE,
bank when READ,
bank when WRITE,
(others => '0') when others;
-- set SDRAM address
with state select
sdram_a <=
"0010000000000" when INIT,
MODE_REG when MODE,
row when ACTIVE,
"0010" & col when READ, -- auto precharge
"0010" & col when WRITE, -- auto precharge
(others => '0') when others;
-- decode the next 16-bit word from the write buffer
--sdram_dq <= data_reg((BURST_LENGTH-wait_counter)*SDRAM_DATA_WIDTH-1 downto (BURST_LENGTH-wait_counter-1)*SDRAM_DATA_WIDTH) when state = WRITE else (others => 'Z');
B_data_mux: block
type T_mux_sdram_dq is array (0 to BURST_LENGTH-1) of std_logic_vector(SDRAM_DATA_WIDTH-1 downto 0);
signal S_mux_sdram_dq: T_mux_sdram_dq;
signal addr_wait_counter: unsigned(ilog2(BURST_LENGTH)-1 downto 0);
begin
G_mux_sdram_dq: for i in 0 to BURST_LENGTH-1 generate
S_mux_sdram_dq(i) <= data_reg((BURST_LENGTH-i)*SDRAM_DATA_WIDTH-1 downto (BURST_LENGTH-i-1)*SDRAM_DATA_WIDTH);
end generate;
addr_wait_counter <= to_unsigned(wait_counter, addr_wait_counter'length);
sdram_dq <= S_mux_sdram_dq(to_integer(addr_wait_counter)) when state = WRITE else (others => 'Z');
end block;
-- set SDRAM data mask
sdram_dqmh <= '0';
sdram_dqml <= '0';
end architecture arch;
Along with this core, the main file is a pretty simple program with a few debug features. On startup, it does nothing, and after pressing a button, it starts writing the RAM with all integers from 0 to 8388607 (2^22-1). Once everything is written, I can press a second button which reads the next address, and shows 8 bits of the data result on the LEDs, such that I can see if there are errors or not. Here is the code :
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
use work.CLK100M;
use work.sdram;
entity SynthFPGA is
port (
clk50 : in std_logic;
dram_addr : out unsigned(12 downto 0);
dram_dq : inout std_logic_vector(15 downto 0);
dram_ba : out unsigned(1 downto 0);
dram_dqm : out std_logic_vector(1 downto 0);
dram_ras_n : out std_logic;
dram_cas_n : out std_logic;
dram_cke : out std_logic;
dram_clk : out std_logic;
dram_we_n : out std_logic;
dram_cs_n : out std_logic;
LEDS_n : out std_logic_vector(7 downto 0);
button1 : in std_logic;
button2 : in std_logic;
dummy_out : out std_logic_vector(31 downto 0)
);
end entity SynthFPGA;
architecture rtl of SynthFPGA is
signal clkmain : std_logic;
signal pll_locked : std_logic;
signal clk48k_audio : std_logic;
signal clk48k_audio_locked : std_logic;
signal initialized : std_logic := '0';
signal reset : std_logic := '0';
signal ram_ctrl_addr : unsigned(22 downto 0);
signal ram_ctrl_data : std_logic_vector(31 downto 0);
signal ram_ctrl_we : std_logic;
signal ram_ctrl_req : std_logic;
signal ram_ctrl_ack : std_logic;
signal ram_ctrl_valid : std_logic;
signal ram_ctrl_q : std_logic_vector(31 downto 0);
signal wr_ram_ctrl_addr : unsigned(22 downto 0);
signal wr_ram_ctrl_data : std_logic_vector(31 downto 0);
signal wr_ram_ctrl_we : std_logic;
signal wr_ram_ctrl_req : std_logic;
signal rd_ram_ctrl_addr : unsigned(22 downto 0);
signal rd_ram_ctrl_data : std_logic_vector(31 downto 0);
signal rd_ram_ctrl_we : std_logic;
signal rd_ram_ctrl_req : std_logic;
signal last_read_data : std_logic_vector(31 downto 0) := (others => '0');
signal rdcnt : natural range 0 to 8_388_607 := 0;
type main_state_type is (IDLE, WRITING_CMD, WRITING_ACK, READING, READING_BUTTON_RST);
signal main_state : main_state_type := IDLE;
type reading_state_type is (IDLE, START, ACKNOWLEDGED, TERMINATE);
signal reading_state : reading_state_type := IDLE;
signal wrcnt : natural range 0 to 8_388_607 := 0;
begin
dram_clk <= clkmain;
CLK_100M_I : CLK100M
port map(
inclk0 => clk50,
c0 => clkmain,
c1 => clk48k_audio,
locked => pll_locked
);
main : process(clkmain, reset)
begin
if reset = '1' then
--
elsif rising_edge(clkmain) and pll_locked = '1' then
case main_state is
when IDLE =>
if button1 = '0' then
main_state <= WRITING_CMD;
LEDS_N <= "01010101";
end if;
when WRITING_CMD =>
wr_ram_ctrl_addr <= to_unsigned(wrcnt, 23);
wr_ram_ctrl_data <= std_logic_vector(to_unsigned(wrcnt,32));
wr_ram_ctrl_we <= '1';
wr_ram_ctrl_req <= '1';
main_state <= WRITING_ACK;
LEDS_N <= "10101010";
when WRITING_ACK =>
if ram_ctrl_ack = '1' then
if wrcnt < 8_388_607 then
wrcnt <= wrcnt + 1;
wr_ram_ctrl_addr <= to_unsigned(wrcnt, 23);
wr_ram_ctrl_data <= std_logic_vector(to_unsigned(wrcnt,32));
wr_ram_ctrl_we <= '1';
wr_ram_ctrl_req <= '1';
LEDS_n <= std_logic_vector(to_unsigned(wrcnt, 23))(22 downto 15);
main_state <= WRITING_ACK;
else
wrcnt <= 0;
wr_ram_ctrl_we <= '0';
wr_ram_ctrl_req <= '0';
main_state <= READING;
end if;
end if;
when READING =>
if button1 = '1' then
main_state <= READING_BUTTON_RST;
end if;
when READING_BUTTON_RST =>
LEDs_n <= last_read_data(9 downto 2);
if button1 = '0' then
main_state <= IDLE;
end if;
end case;
end if;
end process;
process(main_state)
begin
if main_state = WRITING_CMD or main_state = WRITING_ACK then
ram_ctrl_addr <= wr_ram_ctrl_addr;
ram_ctrl_data <= wr_ram_ctrl_data;
ram_ctrl_we <= wr_ram_ctrl_we ;
ram_ctrl_req <= wr_ram_ctrl_req ;
elsif main_state = READING or main_state = READING_BUTTON_RST then
ram_ctrl_addr <= rd_ram_ctrl_addr;
ram_ctrl_data <= (others => 'Z');
ram_ctrl_we <= rd_ram_ctrl_we ;
ram_ctrl_req <= rd_ram_ctrl_req ;
end if;
end process;
reading_addr : process(clkmain)
begin
if rising_edge(clkmain) and pll_locked = '1' and (main_state = READING or main_state = READING_BUTTON_RST) then
case reading_state is
when IDLE =>
if button2 = '0' then
reading_state <= START;
rdcnt <= rdcnt + 1;
end if;
when START =>
if ram_ctrl_ack = '1' then
rd_ram_ctrl_req <= '0';
reading_state <= ACKNOWLEDGED;
else
rd_ram_ctrl_addr <= to_unsigned(rdcnt, 23);
rd_ram_ctrl_we <= '0';
rd_ram_ctrl_req <= '1';
end if;
when ACKNOWLEDGED =>
if ram_ctrl_valid = '1' then
last_read_data <= ram_ctrl_q;
reading_state <= TERMINATE;
end if;
when TERMINATE =>
if button2 = '1' then
reading_state <= IDLE;
end if;
end case;
end if;
end process reading_addr;
dummy_out <= last_read_data;
sdram_controller_instance : entity sdram
generic map(
CAS_LATENCY => 2,
CLK_FREQ => 133.0,
T_DESL => 200000.0,
T_MRD => 14.0,
T_RC => 60.0,
T_RCD => 15.0,
T_RP => 15.0,
T_WR => 15.0,
T_REFI => 20000.0
)
port map(
reset => not pll_locked,
clk => clkmain,
addr => ram_ctrl_addr,
data => ram_ctrl_data,
we => ram_ctrl_we,
req => ram_ctrl_req,
ack => ram_ctrl_ack,
valid => ram_ctrl_valid,
q => ram_ctrl_q,
sdram_a => dram_addr,
sdram_ba => dram_ba,
sdram_dq => dram_dq,
sdram_cke => dram_cke,
sdram_cs_n => dram_cs_n,
sdram_ras_n => dram_ras_n,
sdram_cas_n => dram_cas_n,
sdram_we_n => dram_we_n,
sdram_dqml => dram_dqm(0),
sdram_dqmh => dram_dqm(1)
);
end architecture rtl;
The PLL is a simple Altera PLL IP, which is fed by the 50MHz on-board clock of the DE0-nano board, generating a 133.035714MHz (149/56 of the 50) clock. However, this program does not seem to work correctly, the data I'm reading from the RAM is corrupted.
I'm honestly not sure what is going wrong, and the debugging is complicated. I don't have any oscilloscope that goes up above 30MHz signals, and for some reason, the Signal Tap Analyzer from Quartus Prime makes the FPGA behave strangely (or at least, differently than when it's not connected).
I'm pretty sure that the issue might come from some parameters that I did not setup correctly, but I can't find which ones. After double checking my assignments, and the SDRAM chip datasheet, I'm not able to find my mistake, and I'm completely unable to locate the issue in my system. Where can the issues come from in my logic ?