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

SDRAM without HPS

HTolentino
Beginner
1,016 Views

Hello, I am using a DE1-SOC cyclone v board.

I am trying to read and write into/from my 64Mb SDRAM without using the NIOS hps.

I understand that this topic has been mentioned at 

https://community.intel.com/t5/Intel-Quartus-Prime-Software/Sdram/m-p/174628#M43315

 

However, after going to terasic and downloading  DE1_SoC_SDRAM_RTL_Test on the DE1_SOC system CD I found it difficult to understand.

First, I mainly code in VHDL so I have a hard time translating the verilog example.

Next, there are a lot of attached components which I assume is part of the debugging process.

 

Is there a simple way to confirm reading and writing in SDRAM with a simple wrapper code?

I just assume that controller from the platform designer deal with all the nitty gritty and the "conduit" wires deal with the controller interacting with the SDRAM.

1) Is there going to be complex timing I have to consider in order to read and write from SDRAM?

2) How can we verify that it is working, I tried using signal tap but there are so many weird signals; and signals I want such as counters are not in the list. Also ISSP seems kind of too simplistic.

 

HTolentino_0-1698690711311.png

 

The code I have is simple, I have the platform designer component wrapped as "ramsys" and I just have a top level design called SDRAM.

In the top level, I simply toggled the Read and write enable by a counter. Likewise, the address follows a counter.

Note: I just have a random FF because I was messing with it to see if the signal can appear in signaltap.

 

Is this process correct? Or am I too naive?

Thank you

 

 

 

---==================================================================

library ieee;
 
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
 
 
--use work.pcg.all;
 
 
entity sdram is
 
port(
 
CLOCK_50: IN STD_LOGIC;
SW: IN STD_LOGIC_VECTOR(9 downto 0);
------------------SDRAM---------------------------
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,DRAM_UDQM: OUT STD_LOGIC
);
 
 
end sdram;
 
architecture main of sdram is
 
 
TYPE STAGES IS (ST0,ST1);
SIGNAL BUFF_CTRL: STAGES:=ST0;
---------------------------test signals----------------------------
--signal counter : integer range 0 to 1000;
--signal test: std_logic:='0';
--signal testdata: std_logic_vector(7 downto 0):="00000000";
--signal Xpos,Ypos: integer range 0 to 799:=0;
---------------------------sync-----------------------------
signal BUFF_WAIT: std_logic:='0';
signal VGAFLAG: std_logic_vector(2 downto 0);
------------------vga----------------------------------
 
SIGNAL CLK100: STD_LOGIC;
------------------sdram--------------------------------
SIGNAL SDRAM_ADDR: STD_LOGIC_VECTOR(24 downto 0):= (others => '0');
SIGNAL SDRAM_ADDR_CTR: STD_LOGIC_VECTOR(24 downto 0) := (others => '0');
SIGNAL SDRAM_BE_N: STD_LOGIC_VECTOR(1 downto 0);
SIGNAL SDRAM_CS: STD_LOGIC;
SIGNAL SDRAM_RDVAL,SDRAM_WAIT:STD_LOGIC;
SIGNAL SDRAM_RE_N,SDRAM_WE_N: STD_LOGIC;
attribute syn_keep: boolean;
SIGNAL SDRAM_READDATA: STD_LOGIC_VECTOR(15 downto 0);
attribute syn_keep of SDRAM_READDATA : signal is true;
SIGNAL SDRAM_WRITEDATA: STD_LOGIC_VECTOR(15 downto 0);
SIGNAL DRAM_DQM : STD_LOGIC_VECTOR(1 downto 0);
 
 
    component ramsys is
        port (
            clk_clk             : in    std_logic                     := 'X';             -- clk
            reset_reset_n       : in    std_logic                     := 'X';             -- reset_n
            wire_addr           : out   std_logic_vector(12 downto 0);                    -- addr
            wire_ba             : out   std_logic_vector(1 downto 0);                     -- ba
            wire_cas_n          : out   std_logic;                                        -- cas_n
            wire_cke            : out   std_logic;                                        -- cke
            wire_cs_n           : out   std_logic;                                        -- cs_n
            wire_dq             : inout std_logic_vector(15 downto 0) := (others => 'X'); -- dq
            wire_dqm            : out   std_logic_vector(1 downto 0);                     -- dqm
            wire_ras_n          : out   std_logic;                                        -- ras_n
            wire_we_n           : out   std_logic;                                        -- we_n
            sdram_address       : in    std_logic_vector(24 downto 0) := (others => 'X'); -- address
            sdram_byteenable_n  : in    std_logic_vector(1 downto 0)  := (others => 'X'); -- byteenable_n
            sdram_chipselect    : in    std_logic                     := 'X';             -- chipselect
            sdram_writedata     : in    std_logic_vector(15 downto 0) := (others => 'X'); -- writedata
            sdram_read_n        : in    std_logic                     := 'X';             -- read_n
            sdram_write_n       : in    std_logic                     := 'X';             -- write_n
            sdram_readdata      : out   std_logic_vector(15 downto 0);                    -- readdata
            sdram_readdatavalid : out   std_logic;                                        -- readdatavalid
            sdram_waitrequest   : out   std_logic                                         -- waitrequest
        );
    end component ramsys;
 
 
component FF_test is 
port(      Clk :in std_logic;  
Q : out std_logic_vector(15 downto 0);
      D :in  std_logic_vector(15 downto 0)  
);
 
end component;
signal counter : std_logic_vector(7 downto 0) := (others => '0');
signal counter0 : std_logic_vector(7 downto 0) := (others => '0');
signal s_Q :  std_logic_vector(15 downto 0) := (others => '0');
 
--=========================================
begin
     u0 : ramsys
        port map (
            clk_clk             => CLOCK_50,             --   clk.clk
            reset_reset_n       =>'1',       -- reset.reset_n
            wire_addr           => DRAM_ADDR,           --         wire.addr
            wire_ba             => DRAM_BA,             --             .ba
            wire_cas_n          => DRAM_CAS_N,          --             .cas_n
            wire_cke            => DRAM_CKE,            --             .cke
            wire_cs_n           => DRAM_CS_N,           --             .cs_n
            wire_dq             => DRAM_DQ,             --             .dq
            wire_dqm            => DRAM_DQM,            --             .dqm
            wire_ras_n          => DRAM_RAS_N,          --             .ras_n
            wire_we_n           => DRAM_WE_N,           --             .we_n
            sdram_address       => SDRAM_ADDR,       --        sdram.address
            sdram_byteenable_n  => SDRAM_BE_N,  --             .byteenable_n
            sdram_chipselect    => SDRAM_CS,    --             .chipselect
            sdram_writedata     => SDRAM_WRITEDATA,     --             .writedata
            sdram_read_n        => SDRAM_RE_N,        --             .read_n
            sdram_write_n       => SDRAM_WE_N,       --             .write_n
            sdram_readdata      => SDRAM_READDATA,      --             .readdata
            sdram_readdatavalid => SDRAM_RDVAL, --             .readdatavalid
            sdram_waitrequest   => SDRAM_WAIT    --             .waitrequest
        );
  
u1 : FF_test
port map ( clk => clk100,
Q => s_Q,
D => SDRAM_READDATA
 
 
);
DRAM_LDQM<=DRAM_DQM(0);
DRAM_UDQM<=DRAM_DQM(1);
DRAM_CLK<=CLK100;
SDRAM_CS<='1';
SDRAM_BE_N<="00";
 
process(clk100)
begin
if rising_edge(clk100) then
if(counter0 <= "00000111") then
SDRAM_WE_N<='0';
SDRAM_RE_N<='1';
counter0 <= counter0 + '1';
elsif(counter0 > "00000111") then
SDRAM_WE_N<='1';
SDRAM_RE_N<='0';
counter0 <= counter0 + '1';
elsif (counter0 > "00001111") then
counter0 <= (others => '0');
 
end if;
end if;
end process;
process(clk100)
begin
if rising_edge (clk100) then
case BUFF_CTRL is
when st0=>------------WRITE   
if (SDRAM_WAIT='0')then
 
if (SDRAM_RE_N ='1' and SDRAM_WE_N = '0') then
SDRAM_WRITEDATA(7 downto 0)<= counter; 
counter <= counter + '1';
SDRAM_ADDR<= SDRAM_ADDR_CTR;
SDRAM_ADDR_CTR <= SDRAM_ADDR_CTR + '1';
if SDRAM_ADDR_CTR = "000000000000000000000111" then
counter <= (others => '0');
SDRAM_ADDR_CTR <= (others => '0');
end if;
end if;
end if;
 
when st1=>-----------READ
      if (SDRAM_RE_N ='0' and SDRAM_WE_N = '1') then
  IF(SDRAM_WAIT='0')THEN
SDRAM_ADDR<= counter;
        END IF;
end if;
           
end case;
end if;
 
end process;
 
end main;

 

 

 

Labels (1)
0 Kudos
11 Replies
sstrell
Honored Contributor III
982 Views

Few things I notice.

You don't cover in your code if waitrequest is high.  You have to continue holding the address and control signals when this happens.  It might be easier to make use of some off the shelf component in Platform Designer instead of exporting the interface and coding your own Avalon host to communicate with the SDRAM.  Maybe a FIFO or something from the IP Catalog.

For Signal Tap, use the pre-synthesis Signal Tap filter when tapping nodes.  That way you'll recognize the signals from the code instead of the changed names you'll see if you use the post-fit filter.

Also, I presume you have a .sdc file with timing constraints and that you made pin assignments correctly in the Pin Planner.

0 Kudos
aikeu
Employee
932 Views

Hi HTolentino,


Any further follow up on the case?


Thanks.

Regards,

Aik Eu


0 Kudos
HTolentino
Beginner
905 Views

Hello. I apologize for the late reply. At the moment @sstrell was right about the sdc and and my lack of pin assignment. I was finally able to see the signals i wanted in signal tap after putting in pre synthesis.

Currently I am able to see some sort of correct semblance on the waveform but for some reason it is not quite right. 

I am certain it is my finite state machine code or something but I am still trying to find the problem functionally.

I wanted to see if I can get the waveform right before posting it.

 

I think my next problem is regarding SDRAM wait request. 

I coded it the address/data to latch when it is high and only change the data/address when it is low as suggested,.

On the other hand I cant predict when SDRAM will be high or not.

Is this something completely random or is there some kind of timing it follows so we can predict when SDRAM wait request will be low.

At the moment, I see this SDRAM wait request as some annoying enable signal. I wonder if this is completely natural in the memory interface.

 

Is it alright if I can work on it a bit longer before following up?

I apologize again for the delay.

 

But Thank you  for the replies.

 

-htolentino

0 Kudos
sstrell
Honored Contributor III
899 Views

waitrequest is a required signal with Avalon.  When it is high, control signals must be held until 1 cycle after waitrequest goes low.  It's not random.  It's based on what's happening in the system interconnect at any time.  See the Avalon spec here: https://www.intel.com/content/www/us/en/docs/programmable/683091/22-3/introduction-to-the-interface-specifications.html

0 Kudos
HTolentino
Beginner
892 Views

Hello thank you for the link.

 

Ive had the chance to look at this before but was confused about it.

I guess now is the best chance to ask about it.

 

Just for reference for the pictures - https://www.intel.com/content/www/us/en/docs/programmable/683091/22-3/typical-read-and-write-transfers.html

HTolentino_0-1699388314608.png

First, I wanted to ask what the vertical squigly lines.

Second, In the context above Who is the host. Who is agent?

In this picture it seems my top level custom logic is the M/Master/Host while the SDRAM controller is the S/Slave/Agent

HTolentino_1-1699389042775.png

However, I think based on the reading and writing example I think the host is the controller while the agent is the actual external SDRAM.

 

 

Next are some assumpltions. Please correct any assumptions I have:

-steps 1 - 4 are READING

-5 - 6 are for WRITING.

-The order of reading or writing first doesnot matter. '

-The memory have something initially or was written data before which is why it is able to READ first.

 

For READING.

Clock cycle 1 : the host sends data/address/read..........the agent asserts wait request

Clock cycle 2 : the host receives wait request = 1, thereby latching the data/address/read.

Clock cycle 3: the host still latch data/address/read.......the agents deasserts wait request

Clock cycle 4: the host receives wait request = 0, thereby finally sampling data/address/read.

 

Overall, wait request = 1 for only 2 clock cycles.

On the other hand, wait request for writing is much longer even though it seems the step is the same as the reading.

It says on step 6 the wait request deasserts after the rising edge of the clk but the which rising edge it choose seems random.

If we look at the reading part, the wait request becomes 0 immediately after the host spends a clock cycle to register it as 1.

But in the writing part it takes way longer

 

 

 

HTolentino_2-1699389507076.png

I apologize if I am making too many assumptions and complicating something that is simple.

Please let me know any concerns or comments.

I appreciate everyone as usual.

 

-htolentino

 

 

 

0 Kudos
sstrell
Honored Contributor III
889 Views

Squiggly lines: as long as waitrequest is held high, the other signals must be held.  This is showing that it could be multiple cycles before waitrequest is released.

Host is whatever system component is issuing read or write commands (previously referred to as a master).  Agent (previously a slave) responds to commands by either storing data on a write or replying with data on a read.

For external memory, you have an IP that responds to read/write commands on the Avalon interface that is an intermediary to the external memory.  That is the agent, not the external memory.

The waveforms are generic read and write transfers to understand the signaling on an Avalon interface.  It doesn't matter if read or write occurs first.

cycle 1: The interconnect asserts waitrequest (often due to arbitration due to multiple hosts accessing a single agent at the same time), unless the agent includes a waitrequest output signal for manual control of waitrequest.  So the note below the waveform indicates that the agent, in this case, is manually asserting waitrequest.

cycle 2: it's not a latching.  When the host sees waitrequest, logic in the host would know to continue asserting the control signals.

waitrequest can be any length needed.  It doesn't matter whether it's a read or a write.  It's up to whatever is controlling it, the interconnect or the agent.  Again, the waveform is illustrative to explain how the signaling works, not how every design must work.

 

 

0 Kudos
HTolentino
Beginner
861 Views

Hello thank you for the reply,

 

just to clarify, the  agent you mentioned is the SDRAM controller IP right?

 

In Platform designer I instantiated the SDRAM controller with the PLL.

This block design is called RAMSYS.

At the moment, RAMSYS has SDRAM wait request as the output port.

In my top level design (host), I connected this output to an interconnect which I used to determine if I can proceed with reading or writing.

I undestand wait request behaves a certain way based on the inputs of the controller .

It also seems it is dependent on some timing based on the figure before.

 

My confusion is that the clock cycle difference from read and write are different.

Even though write cycle provided the necessary inputs (data/address/read enable), same as the read cycle,

it still deasserts wait request  longer than write.

If it is indeed based on some sort of timing, can I assume it would be some static timing based if the inputs arrive at the same clock cycle? 

 

I realized that my host (state machine code)  depends on the wait request while the agent (SDRAM controller) depends on the inputs from the host.

I confused myself even further as it looks this looks like a feedback loop.

At the end of the day, I really dont know whos really reponsible for wait request. 

 

I understand you made a note on this ...

"

When the host sees waitrequest, logic in the host would know to continue asserting the control signals.

waitrequest can be any length needed.  It doesn't matter whether it's a read or a write.  It's up to whatever is controlling it, the interconnect or the agent.  Again, the waveform is illustrative to explain how the signaling works, not how every design must work.

"

In bold you note that the wait request is controlled by the agent and the one controlling it...isnt the one controlling it the host?.

OVerall it seems like I am going backwards as I dont even know which really controls who.

I will continue reading on it and I understand if this question is off tangent the original problem.

 

Thank you.

 

-htolentino

 

 

 

 

 

 

 

0 Kudos
sstrell
Honored Contributor III
821 Views

@HTolentino wrote:

Hello thank you for the reply,

 

just to clarify, the  agent you mentioned is the SDRAM controller IP right?

 

Yes.

 

In Platform designer I instantiated the SDRAM controller with the PLL.

This block design is called RAMSYS.

At the moment, RAMSYS has SDRAM wait request as the output port.

In my top level design (host), I connected this output to an interconnect which I used to determine if I can proceed with reading or writing.

I undestand wait request behaves a certain way based on the inputs of the controller .

It also seems it is dependent on some timing based on the figure before.

 

The interconnect I referred to is the interconnect automatically generated by Platform Designer.  I'm not sure what interconnect you are referring to here.  And again, waitrequest is not timing based.  It's based on logic.  When the agent cannot currently accept commands (arbitration is a common cause), depending on the design, either the interconnect or the agent (if it has manual waitrequest control with an output signal) holds waitrequest high as long as necessary.

 

My confusion is that the clock cycle difference from read and write are different.

Even though write cycle provided the necessary inputs (data/address/read enable), same as the read cycle,

it still deasserts wait request  longer than write.

 

Again, that's an illustrative waveform.  It's not showing the exact number of cycles for things to happen.

 

If it is indeed based on some sort of timing, can I assume it would be some static timing based if the inputs arrive at the same clock cycle? 

 

Again, no.  The assertion of waitrequest is not timing based.

 

I realized that my host (state machine code)  depends on the wait request while the agent (SDRAM controller) depends on the inputs from the host.

I confused myself even further as it looks this looks like a feedback loop.

At the end of the day, I really dont know whos really reponsible for wait request. 

 

The interconnect or agent is responsible for the generation of waitrequest.  The host (your design in this case) is responsible for interpreting waitrequest as an input signal and holding your output control signals steady as long as waitrequest is held high.  (i.e. "if waitrequest=1 on this clock cycle, hold outputs at current value until after the first clock cycle where waitrequest is released; that's the cycle the transfer takes place)

 

I understand you made a note on this ...

"

When the host sees waitrequest, logic in the host would know to continue asserting the control signals.

waitrequest can be any length needed.  It doesn't matter whether it's a read or a write.  It's up to whatever is controlling it, the interconnect or the agent.  Again, the waveform is illustrative to explain how the signaling works, not how every design must work.

"

In bold you note that the wait request is controlled by the agent and the one controlling it...isnt the one controlling it the host?.

 

Again, either the agent can control waitrequest manually or if it does not have a waitrequest output, the interconnect can generate and sent waitrequest to the host as needed.

 

OVerall it seems like I am going backwards as I dont even know which really controls who.

I will continue reading on it and I understand if this question is off tangent the original problem.

 

Thank you.

 

-htolentino

 

 

 

 

 

 

 


 

0 Kudos
aikeu
Employee
764 Views

Hi sstrell,


Thanks for your help and informative feedback on the issue.


Thanks.

Regards,

Aik Eu


0 Kudos
aikeu
Employee
752 Views

Hi HTolentino,


I will close this thread if no further question.


Thanks.

Regards,

Aik Eu


0 Kudos
aikeu
Employee
720 Views

Hi HTolentino,


I am closing the thread for now. This thread will be transitioned to community support. If you have a new question, feel free to open a new thread to get the support from Intel experts. Otherwise, the community users will continue to help you on this thread. Thank you.


Thanks.

Regards,

Aik Eu


0 Kudos
Reply