• 0
MartinBuk

MIG implementation without Microblade

Question

Hi guys,
I've been working on implementation MIG into my project. I have a problem with write data into DDR2 (nexys 4ddr). Actually, it works but, if i want to write data into different address location. The previous one are lost. I can read and write data from the adress but i can't write data into an another addres and read both adress location. some how the previons data are lost. I will be very grateful for any help...

 

process(sig_clk)
    begin
        if rising_edge(sig_clk) then
            case aState is
                when stInit =>
                    if sig_calib_complete = '1' then
                        sig_en <= '0';
                        sig_wdf_wren <= '0';
                        sig_wdf_end <= '0';
                        --LED(15 downto 9) <= (others => '0');
                        if commnd = CMD_WRITE then
                            aState <= stWriteComd;
                        elsif commnd = CMD_READ then
                            aState <= stReadComd;
                        end if;
                    end if;
                when stReadComd =>
                    sig_en <= '1';
                    sig_cmd <= CMD_READ;
                    --LED(9) <= '1';
                    sig_addr(1 downto 0) <= SWI(15 downto 14);
                    aState <= stComdAcep;
                when stWriteComd =>
                    sig_en <= '1';
                    sig_cmd <= CMD_WRITE;
                    --LED(10) <= '1';
                    sig_addr(1 downto 0) <= SWI(15 downto 14);
                    aState <= stComdAcep;
                when stComdAcep =>
                    if sig_rdy = '1' then
                        sig_en <= '0';
                        --LED(12) <= '1';
                        if commnd = CMD_WRITE then
                            sig_wdf_wren <= '1';
                            sig_wdf_end <= '0';
                            sig_wdf_data(12 downto 0) <= "1010101111111";
                            aState <= stWriteData;
                        elsif commnd = CMD_READ then
                            aState <= stWaitRead;
                        end if;
                    end if;
                when stWriteData =>
                    if sig_wdf_rdy = '1' then
                        sig_wdf_wren <= '1';
                        sig_wdf_end <= '1';
                        --LED(13) <= '1';
                        sig_wdf_data(12 downto 0) <= "1010101010101";
                        aState <= stWaitAct;
                    end if;
                when stWaitRead =>
                    if sig_rd_data_valid = '1' and sig_rd_data_end = '1' then
                        --LED(14) <= '1';
                        aState <= stWaitAct;
                        data_out <= sig_rd_data;
                    end if;
                when stWaitAct =>
                        sig_wdf_wren <= '0';
                        sig_wdf_end <= '0';
                        --LED(15) <= '1';
                        if ready = '1' then
                            aState <= stInit;
                        end if;
            end case;
        end if;
    end process;

 

Share this post


Link to post
Share on other sites

17 answers to this question

Recommended Posts

  • 0

no.. it was just for testing reason. That's demo where i want to verify the reading and writing into memory. in furture, i want to create data stream from camera.

Share this post


Link to post
Share on other sites
  • 0

yeah, sorry for my english... The demo should somehow store data and be able to read them as well. for example (problem): i wrote data into address "001" and i could read them from same address. after that i was trying to wrote data into address "010" and i could read them as well but when i changed adress back to "001" in reading mode it was empty. 

Edited by MartinBuk

Share this post


Link to post
Share on other sites
  • 0

Are you guaranteeing a minimum number of clocks between your accesses?  The code you posted above doesn't show any means of feedback for telling the calling logic that it's busy with a request, and yet you reuse variables from one clock to the next.

Dan

Share this post


Link to post
Share on other sites
  • 0

Which access do you mean? like Read, Read? If you mean access to data it shoul be feasible. Because i use switches and the state machine is waiting to my physical action. Should i use variables in different way? By the way thank you for your effort. i appreciate that.

 

Share this post


Link to post
Share on other sites
  • 0

I mean, you haven't shown me the code that drives your state machine.  If some of the values your state machine depends upon change ... perhaps before you are expecting them to change, you might asking the memory to do something you are not expecting.

For example, if on clock 1 you send your controller a read request, your controller will switch to the read state.  On clock 2 it will be in the read state, switching to the command accepted state.  On clock three it will be in the command accepted state and transitioning to the read wait state.  (This assumes the DDR memory controller doesn't slow things down, which it will.  I've personally measured a 23-clock delay for a DDR3 controller ...)

What happens if the variables associated with the read request change between clock 1 and clock 3?  Are you guaranteeing that bus values (such as SWI) hold steady, and that you aren't starting a new request before the first returns?

I also didn't see anything in your code to signal, upon a successful read, that the value within data_out was available to be successfully read.

I guess what I'm saying is, at a first glance, the routine you outline above looks like it would work.  That's why I'm asking questions about the supporting logic.

Dan

Share this post


Link to post
Share on other sites
  • 0

There aren't any more meaningful logic circuits. In the final state(stWaitAct) of the state machine it is checking differences between actual and previous switch value. SWI is filtered output from physical switch. I wanted to avoid bouncing value. Maybe i would try to stretch de-bounce filter more. Request change between clock 1 and clock 3 could happen but it is unlikely. Because i was waiting to signal diode LED(15) in the final state..

 

 process(sig_clk)
    begin
        if rising_edge(sig_clk) then
            if aState = stWaitAct then
                 if adress /= SWI(15 downto 14) or comd /= ("00" & SWI(0)) then
                     adress <= SWI(15 downto 14);
                     comd <= ("00" & SWI(0));
                     ready <= '1';
                 else
                     ready <= '0';
                 end if;  
            end if;
        end if;
    end process;    
        
     
    commnd <= "00" & SWI(0);
    LED(8 downto 1) <= data_out(7 downto 0);

 

Share this post


Link to post
Share on other sites
  • 0

Ok, now I understand more about what you are doing.  That's cool.  I like your switch approach to testing this memory, rather ingenious if you ask me.

What's not going to work about it, though, is that you are running through your loop over and over and over again.  Suppose you chose to only leave the init state when a button is first pressed--not when it is held, but when it is first pressed.  (You'll need to debounce it to make certain one button press only gives you permission to leave that state once ...)  That should help guarantee that nothing changes within your loop when you aren't expecting it.

Dan

Share this post


Link to post
Share on other sites
  • 0

Maybe the issue is caused by IP implementation in my code. I set MIG by digilent and created own constraint file. As is shown below. Maybe MIG creates own constraint file as well. Do you know how IP core works?

##DDR2 SRAM
set_property -dict { PACKAGE_PIN R7   IOSTANDARD SSTL18_II } [get_ports { ddr2_dq[0] }];
set_property -dict { PACKAGE_PIN V6   IOSTANDARD SSTL18_II } [get_ports { ddr2_dq[1] }];

Share this post


Link to post
Share on other sites
  • 0

Do I know how the IP core works?  I have studied it in detail, and continue to study it.  No, I don't know how it works yet.  I'm working on it.

I do know that MIG creates it's own constraints file, and I know that I then commented out the DDR lines from my constraints file as a result.  For me, that constraint file can be found in ....srcs/sources_1/ip/<ip-name>/<ip-name>/user_design/constraints.

I also know that MIG wanted the ports named by its convention and not mine.

I also doubt that's the problem you are having.

Dan

Share this post


Link to post
Share on other sites
  • 0

You're right. i figured out, that address is the problem. i can't use the first three bits like an address. Rest works just fine. I don't know how is it so, but i can live with that. If you have any idea, let me know...

thank you,

Martin

Edited by MartinBuk

Share this post


Link to post
Share on other sites
  • 0

yeah i've kind of done that. not with button but with switch. Loop isn't running over and over again, because it is checking actual and previous state on switches. if i decide to change adress or read/write mode, the loop will run again and stop. I think that was your point. or did i miss your idea?

Martin

Share this post


Link to post
Share on other sites
  • 0

Well, let's think this through.  You need a single clock strobe--a signal that is only valid for one clock, and then off until you command it to be on again. 

If you create this strobe from your switches, and set it to strobe any time the switches change, then you may not have placed all of the switches into the configuration you want before the strobe fires--and so it might end up firing multiple times, and some of those times with invalid data.  I suppose you could create it from a single switch, so that you arrange all of the other switches the way you want, and then when the "command switch" flips you do your work ... but you do then realize you will need to debounce it both ways, right?  Otherwise, again, you'll get multiple strobes.

These are the reasons why I like using a button.  If you don't have a button, you can use a switch, but all subject to the problems above.

Dan

Share this post


Link to post
Share on other sites
  • 0

I used switches because i work with them in previous project (like component). My solution is rather simple. I don't need debounce both way, because it has already built in this solution. I noticed that debounce filter has to be set for event about 1.2 ms long. It means that clock in process should be about 22KHz.

 

process(CLK22KHZ)
begin
  	if rising_edge(CLK22KHZ) then
		but_buffer1 <= but_buffer1(39 downto 0) & INPUT(0);
	end if;
end process
  
	OUTPUT(0) <= '1' when but_buffer1 = X"FFFFFFFFFF" else '0';

switch.jpg

Share this post


Link to post
Share on other sites
  • 0

Promlem solved :). I found this sentence in MIG datasheet "The LSBs of the AXI byte address are masked to 0, depending on the data width of the memory array. If the memory array is 64 bits (8 bytes) wide, AXI address[2:0] are ignored and treated as 0." I've used the first three bits as an address and it didn't work

I'm gonna modify the code and share with you. Maybe it will be helpful for someone.

Edited by MartinBuk

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now