Jump to content
  • 0

pin assignment of DDR3 SDRAM arty7-35t


weilai

Question

Hi, guys:

I'm currently doing the '' write and read RAM'' project, in which I want to send characters to RAM through UART, and then read the data from the ram. I find two  problems:

1.pin assignment of RAM. is there the pin number of ram in ARTY achematic, but it seems the pin number interfaced with other pin or isn't vaild.I show this problem in my slide in the attachment. for example, pin'C2' for reset also occurs in a pin of DDR3 in the achematic file.

2. the voltage required for RAM is around 1.5V, but it's 3.3V for other parts like  clk or  button. so when I set up my contraints, and some error occurs. I put the error

module uart_top(
    input           sys_clk,          //system clk 100MHz
    input           sys_rst_n,        //reset
    //uart接口
    input           uart_rxd,         //UART receive port
    output          uart_txd,          //UART send port
    input           we,
    input           re,
    input           [2:0] addr,
    input           [7:0]wr_data
    );
    
//parameter define
parameter  CLK_FREQ = 100000000;       //sys_clk
parameter  UART_BPS = 115200;         //bps
    
//wire define   
wire       uart_en_w;                 //UART_send_enable
wire [7:0] uart_data_w;               //UART send data
wire       clk_1m_w;                  
wire [7:0] mem_data;
//*****************************************************
//**                    main code
//*****************************************************



//串口接收模块 例化    
uart_recv #(    //parameter revalue                      
    .CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率
    .UART_BPS       (UART_BPS)		  //设置串口接收波特率
)       
u_uart_recv(	//串口接收模块                 
    .sys_clk        (sys_clk), 
    .sys_rst_n      (sys_rst_n),
    
    .uart_rxd       (uart_rxd),
    .uart_done      (uart_en_w),
    .uart_data      (uart_data_w)
    );
//串口发送模块 例化    
uart_send #(     //parameter重新赋值                     
    .CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率
    .UART_BPS       (UART_BPS)		  //设置串口发送波特率
)       
u_uart_send(     //串口发送模块            
    .sys_clk        (sys_clk),
    .sys_rst_n      (sys_rst_n),
     
    .uart_en        (uart_en_w),
    .uart_din       (mem_data),
    .uart_txd       (uart_txd)
    );
uart_ram #(    //parameter重新赋值                      
    .CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率
    .UART_BPS       (UART_BPS)		  //设置串口接收波特率
)
u_uart_ram(     //ram connect to uart
    .clk    (sys_clk),
    .we     (we),
    .re     (re),
    .addr   (addr),
    .wr_data (uart_data_w),
    .dout   (mem_data)
);

endmodule 





module uart_recv(
    input			  sys_clk,                  
    input             sys_rst_n,                
    
    input             uart_rxd,                 
    output  reg       uart_done,                //接收一帧数据完成标志信号
    output  reg [7:0] uart_data                 //接收的数据
    );
    
//parameter define
parameter  CLK_FREQ = 100000000;                 //系统时钟频率 50M
parameter  UART_BPS = 115200;                     //串口波特率
localparam BPS_CNT  = CLK_FREQ/UART_BPS;        //为得到指定波特率,
                                                //需要对系统时钟计数BPS_CNT次
//reg define
reg        uart_rxd_d0;
reg        uart_rxd_d1;
reg [15:0] clk_cnt;                           
reg [ 3:0] rx_cnt;                              
reg        rx_flag;                             
reg [ 7:0] rxdata;                              

//wire define
wire       start_flag;

//*****************************************************
//**                    main code
//*****************************************************

//*************************************************************************************************


assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);    

always @(posedge sys_clk or negedge sys_rst_n) begin 
    if (!sys_rst_n) begin 
        uart_rxd_d0 <= 1'b0;
        uart_rxd_d1 <= 1'b0;          
    end
    else begin 
        uart_rxd_d0  <= uart_rxd;                  
        uart_rxd_d1  <= uart_rxd_d0;
    end   
end
//************************************************************************************************


//*****************************************************************************************************

always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                                  
        rx_flag <= 1'b0;
    else begin
        if(start_flag)                          
            rx_flag <= 1'b1;                   
        else if((rx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))	

            rx_flag <= 1'b0;                    
        else
            rx_flag <= rx_flag;
    end
end


always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin                             
        clk_cnt <= 16'd0;                                  
        rx_cnt  <= 4'd0;
    end                                                      
    else if ( rx_flag ) begin                   
            if (clk_cnt < BPS_CNT - 1) begin
                clk_cnt <= clk_cnt + 1'b1;
                rx_cnt  <= rx_cnt;
            end
            else begin
                clk_cnt <= 16'd0;               
                rx_cnt  <= rx_cnt + 1'b1;       
            end
        end
        else begin                              
            clk_cnt <= 16'd0;
            rx_cnt  <= 4'd0;
        end
end
//*****************************************************************************************************

always @(posedge sys_clk or negedge sys_rst_n) begin 
    if ( !sys_rst_n)  
        rxdata <= 8'd0;                                     
    else if(rx_flag)                            
        if (clk_cnt == BPS_CNT/2) begin         
            case ( rx_cnt )
             4'd1 : rxdata[0] <= uart_rxd_d1;   
             4'd2 : rxdata[1] <= uart_rxd_d1;
             4'd3 : rxdata[2] <= uart_rxd_d1;
             4'd4 : rxdata[3] <= uart_rxd_d1;
             4'd5 : rxdata[4] <= uart_rxd_d1;
             4'd6 : rxdata[5] <= uart_rxd_d1;
             4'd7 : rxdata[6] <= uart_rxd_d1;
             4'd8 : rxdata[7] <= uart_rxd_d1;   
             default:;                                    
            endcase
        end
        else 
            rxdata <= rxdata;
    else
        rxdata <= 8'd0;
end

//
always @(posedge sys_clk or negedge sys_rst_n) begin        
    if (!sys_rst_n) begin
        uart_data <= 8'd0;                               
        uart_done <= 1'b0;
    end
    else if(rx_cnt == 4'd9) begin                         
        uart_data <= rxdata;                    
        uart_done <= 1'b1;                      //并将接收完成标志位拉高
    end
    else begin
        uart_data <= 8'd0;                                   
        uart_done <= 1'b0; 
    end    
end

endmodule	

          
          
          
          
          
          
module uart_ram(//clk,we,re,addr,dout,wr_data
input clk,
input we,
input re,
input [2:0] addr,
output  reg [7:0] dout,
input [7:0]wr_data
);
parameter ADD_WIDTH=3;
parameter DATA_WIDTH=8;
/*input clk;
input we;
input re;
input [2:0] addr;
output  reg [7:0] dout;
input [7:0]wr_data;*/
//output reg [7:0] mod;
parameter  CLK_FREQ = 100000000;            //system clock
parameter  UART_BPS = 115200;                 //port bps
localparam BPS_CNT  = CLK_FREQ/UART_BPS;    //BPS_CNT
reg[DATA_WIDTH-1:0] mem [2**ADD_WIDTH-1:0];

always@(posedge clk)
begin
 if (we)
  begin 
     mem[addr]<=wr_data;
  end
end

always@(posedge clk)
begin
 if (re && !we)
  begin
   dout= mem[addr];
  // mod= dout[7:0];
  end
 else
  begin
   dout=8'd0;
   //mod=8'd0;
  end
end  
endmodule

          
          
          
          
module uart_send(
    input	      sys_clk,                  //系统时钟
    input         sys_rst_n,                //系统复位,低电平有效
    
    input         uart_en,                  //发送使能信号
    input  [7:0]  uart_din,                 //待发送数据
    output  reg   uart_txd                  //UART发送端口
    );
    
//parameter define
parameter  CLK_FREQ = 100000000;             //系统时钟频率
parameter  UART_BPS = 115200;                 //串口波特率
localparam BPS_CNT  = CLK_FREQ/UART_BPS;    //为得到指定波特率,对系统时钟计数BPS_CNT次

//reg define
reg        uart_en_d0; 
reg        uart_en_d1;  
reg [15:0] clk_cnt;                        
reg [ 3:0] tx_cnt;                        
reg        tx_flag;                         
reg [ 7:0] tx_data;                         

//wire define
wire       en_flag;

//*****************************************************
//**                    main code

assign en_flag = (~uart_en_d1) & uart_en_d0;	
                                                 

always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        uart_en_d0 <= 1'b0;                                  
        uart_en_d1 <= 1'b0;
    end                                                      
    else begin                                               
        uart_en_d0 <= uart_en;                               
        uart_en_d1 <= uart_en_d0;                            
    end
end

         
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin                                  
        tx_flag <= 1'b0;
        tx_data <= 8'd0;
    end 
    else if (en_flag) begin                                    
            tx_flag <= 1'b1;              
            tx_data <= uart_din;           
        end
        else 
        if ((tx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))
        begin                              
            tx_flag <= 1'b0;                
            tx_data <= 8'd0;
        end
        else begin
            tx_flag <= tx_flag;
            tx_data <= tx_data;
        end 
end


always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin                             
        clk_cnt <= 16'd0;                                  
        tx_cnt  <= 4'd0;
    end                                                      
    else if (tx_flag) begin                
        if (clk_cnt < BPS_CNT - 1) begin
            clk_cnt <= clk_cnt + 1'b1;
            tx_cnt  <= tx_cnt;
        end
        else begin
            clk_cnt <= 16'd0;              
            tx_cnt  <= tx_cnt + 1'b1;      
        end
    end
    else begin                              //发送过程结束
        clk_cnt <= 16'd0;
        tx_cnt  <= 4'd0;
    end
end


always @(posedge sys_clk or negedge sys_rst_n) begin        
    if (!sys_rst_n)  
        uart_txd <= 1'b1;        
    else if (tx_flag)
        case(tx_cnt)
            4'd0: uart_txd <= 1'b0;         
            4'd1: uart_txd <= tx_data[0];   
            4'd2: uart_txd <= tx_data[1];
            4'd3: uart_txd <= tx_data[2];
            4'd4: uart_txd <= tx_data[3];
            4'd5: uart_txd <= tx_data[4];
            4'd6: uart_txd <= tx_data[5];
            4'd7: uart_txd <= tx_data[6];
            4'd8: uart_txd <= tx_data[7];   
            4'd9: uart_txd <= 1'b1;        
            default: ;
        endcase
    else 
        uart_txd <= 1'b1;                   
end

endmodule	          

massage in the attachment too.

1.pptx error massage.txt

Link to comment
Share on other sites

5 answers to this question

Recommended Posts

@weilai,

I'm a bit confused.  1) I don't have MS, so I can't read your PPT image, 2) I don't remember RAM pins like WE, RE, or ADDR[2:0] on the top of the ARTY schematic, 3) you seem to have a RAM module within your code as well that, 4) checks for re && !we ... so let's back up a bit.

  1. Which board are you working with?  Is it the Arty A7-35T board?
  2. Are you trying to connect with any chips which are off of the board, or are you attempting to connect to components within your design, or the DDR3 SDRAM chip on the board?  If the latter, your interface is ... nowhere near the correct one.
  3. Have you simulated your design?  I discuss how to go about simulating a serial port design very similar to this one in my tutorial.
  4. Have you formally verified your design?  Also discussed in my tutorial.

Dan

Link to comment
Share on other sites

>>1: it's arty A7-35t Board

>>2: I'm trying to connect with the DDR3 SDRAM chip on the board. I try to avoid IP core and I want to build my module directly, but it seems almost all the tutorials are about how to access the memory by IP core.

>>3: no, I haven't simulated my design. But the problem now is I  can not access the coorect pin number of the DDR3 from the ARTY achematic. the pin number of DDR seems interface with other pin muber. but thanks for your tutorial. 

>>4:  I really want to know what's the problem with my contraints for DDR3. And I will upload image instead of ppt.

Thanks a lot

4`0Z(6)2G([8ATVYRTOV%PC.png

Link to comment
Share on other sites

Weilai,

Okay, trying to build your own DDR3 SDRAM controller ... and not sure what you are getting into, yet, okay ...

  • Dynamic RAM is not like static RAM.  It's built out of capacitors, rather than FF's, so it needs periodic refreshing as the capacitors drain their charge over time.
  • Synchronous Dynamic RAMs (SDRAMs) are typically organized into banks of memory, where each bank has a special row that may be "activated" and placed into FF memory.
  • Only the activated row may be read or written at any given time
  • It takes some time to activate a row, some time to deactivate it (called pre-charging), and some time to get the memory from the active row.  This all requires clock ticks.
  • The DDR3 SDRAM's use a very fast memory clock--typically 4x faster than your logic.  It's also 90 degrees offset from the logic as well.
  • Since most SDRAM's work based upon commands given to them, you'll need to examine and get familiar with the command set--there are also very strict requirements between commands too--for example, all banks must be precharged before issuing refresh commands, rows must be activated before access, etc.  You'll need an OSERDES of some type to issue these commands.
  • The data wires are the tricky part of the interface.  In general, the outgoing signals can be created with an 8:1 DDR IOSERDES.  That's not the hard part.  The hard part is on receive, where the "clock" for a given byte is returned in a data strobe wire.  This clock is discontinuous and only activated when return data is incoming.  Indeed, this was such a challenging part of the protocol to handle that Xilinx created special hard-IP blocks in most FPGAs for this purpose--the IOPLL, PHASER, and ... there's an I/O FIFO block of some type as well to handle the asynchronous clock rate conversion--since the DSTB return clock, while at the same frequency as the master clock, will have an uncontrolled phase difference to it.  To make matters worse, the key details of these components have been kept Xilinx proprietary, and so they are undocumented.
  • This is all covered by the JESD79-3E specification.  If you really want to interface with the SDRAM, you'll need to do some reading.  (JEDEC charges a small fee for a copy.)
  • You can read about my own attempts to build an open source DDR3 SDRAM controller here.  The code is still public.  I think I got all the logic right, up until the required Xilinx primitives and particularly the incoming DSTB logic.  Of course, since it has never been successfully demonstrated on real hardware you can just about rest assured that it's broken.
  • There is an open source DDR3 SDRAM driver that has been demonstrated.  I haven't used it myself, although I have browsed through the code.  It's not simple to do.

So, that said, let me ask, are you sure this is what you want to do?

Dan

Link to comment
Share on other sites

On 1/3/2020 at 1:43 AM, D@n said:

Weilai,

Okay, trying to build your own DDR3 SDRAM controller ... and not sure what you are getting into, yet, okay ...

  • Dynamic RAM is not like static RAM.  It's built out of capacitors, rather than FF's, so it needs periodic refreshing as the capacitors drain their charge over time.
  • Synchronous Dynamic RAMs (SDRAMs) are typically organized into banks of memory, where each bank has a special row that may be "activated" and placed into FF memory.
  • Only the activated row may be read or written at any given time
  • It takes some time to activate a row, some time to deactivate it (called pre-charging), and some time to get the memory from the active row.  This all requires clock ticks.
  • The DDR3 SDRAM's use a very fast memory clock--typically 4x faster than your logic.  It's also 90 degrees offset from the logic as well.
  • Since most SDRAM's work based upon commands given to them, you'll need to examine and get familiar with the command set--there are also very strict requirements between commands too--for example, all banks must be precharged before issuing refresh commands, rows must be activated before access, etc.  You'll need an OSERDES of some type to issue these commands.
  • The data wires are the tricky part of the interface.  In general, the outgoing signals can be created with an 8:1 DDR IOSERDES.  That's not the hard part.  The hard part is on receive, where the "clock" for a given byte is returned in a data strobe wire.  This clock is discontinuous and only activated when return data is incoming.  Indeed, this was such a challenging part of the protocol to handle that Xilinx created special hard-IP blocks in most FPGAs for this purpose--the IOPLL, PHASER, and ... there's an I/O FIFO block of some type as well to handle the asynchronous clock rate conversion--since the DSTB return clock, while at the same frequency as the master clock, will have an uncontrolled phase difference to it.  To make matters worse, the key details of these components have been kept Xilinx proprietary, and so they are undocumented.
  • This is all covered by the JESD79-3E specification.  If you really want to interface with the SDRAM, you'll need to do some reading.  (JEDEC charges a small fee for a copy.)
  • You can read about my own attempts to build an open source DDR3 SDRAM controller here.  The code is still public.  I think I got all the logic right, up until the required Xilinx primitives and particularly the incoming DSTB logic.  Of course, since it has never been successfully demonstrated on real hardware you can just about rest assured that it's broken.
  • There is an open source DDR3 SDRAM driver that has been demonstrated.  I haven't used it myself, although I have browsed through the code.  It's not simple to do.

So, that said, let me ask, are you sure this is what you want to do?

Dan

Thanks for your  explaination. but I'm a Beginer of RAM, so it's difficult for me to understand you. forget all of them, now I just want to get access to the SDRAM on my ARTY--7-35 board. I mean, send data to external SDRAM on my board from PC and receive them, through UART communication. Now I have successfully built my "send and receive"uart module, what should I do next? 

Thanks,

Dehao

Link to comment
Share on other sites

@weilai,

Both Digilent and Xilinx provide training materials for how to use the SDRAM on the Arty board.  These materials all involve using the schematic based board design.

I have not used this board design, as my own approach is an all Verilog approach.  If this is the approach you are interested in, than I would not recommend an SDRAM as your next project.  I would instead recommend a next project that you could use as a spring-board for other things--a project where you learn how to command/control your design externally, and to debug the design from within.  Only after you've learned these lessons will you be ready to go after the SDRAM.

These are all things I discuss on my blog.

Once you are ready to go after the SDRAM, there are a couple of approaches.  My own approach, and the one I use with my Arty board, is to instantiate Xilinx's controller via their Memory Interface Generator.  I then interact with this controller using a Wishbone bus structure common to all of my designs.  A Wishbone to AXI bridge renders this controller available to me.  I also use a UART to Wishbone converter, which then makes reading and writing peripherals within my design from a serial port fairly easy to do.  This, of course, is all before I get to the SDRAM--and becomes the infrastructure I use to figure out what is (or is not) going on when I build an SDRAM controller.

In other words, if you don't want to use a canned solution, then take a deep breath, slow down, and get there methodically.

Dan

 

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...