当前位置:   article > 正文

DDR3基础和数据读取_ddr3乒乓操作

ddr3乒乓操作

一、DDR3概述

1.简介

工作电压(1.5V),240线接口,支持8bit预读取,工作频率在133MHz即可实现总线1066MHz的总线频率。频率从400\533\667\800MHz起跳等。芯片封装方式FBGA

2.接口

引脚包括:

  • 电源、地、配置信号 ;
  • 控制信号:CS_N ODT(阻抗匹配使能) CKE(时钟使能) reset_n(复位信号) DQM RAS\CAS\WE TDQ\TDQS DQ\DQS
  • 时钟信号:差分时钟ck_p/ck_n
  • 地址信号:CS、BA0、BA1、BA2、A0~A9、A10(对所有Bank预充电时拉高)、A11、A12、A13
  • 数据信号:DQ0~DQ15在这里插入图片描述

3.模式寄存器

模式寄存器分为MR0MR1MR2MR4

  1. MR0用来存储DDR3的不同操作模式的数据:包括突发长度、读取突发种类、CAS长度、测试模式、DLL复位等。
  2. MR1用来存储是否使能DLL、输出驱动长度、Rtt_Nom、额外长度、写电平使能等。
  3. MR2用来存储控制更新的特性, Rtt_WR阻抗,和CAS写长度。
  4. MR3用来控制MPR

4.新增功能

  1. ZQ校准功能ZQ是一个新增的引脚,接有一个240欧姆的低公差参考电阻。

  2. ODT阻抗匹配使能 :可通过读写DDR3内部的MR1寄存器,来控制DDR3 SDRAM中各个信号内部终端电阻的连接或者断开。
    ODT终端电阻的电阻值RTT可通过模式寄存器MR1A9,A6,A2来进行设置,设置的真值表为:
    在这里插入图片描述

  3. 数据电平标准SSTL_15

  4. **预取位宽(**Prefetch width):8bit

  5. 突发长度:由于DDR3的预取为8bit,所以突发传输周期(Burst Length,BL)也固定为8BL=4也是常用的,DDR3为此增加了一个4bit Burst Chop(突发突变)模式,即由一个BL=4的读取操作加上一个BL=4的写入操作来合成一个BL=8的数据突发传输,届时可通过A12地址线来控制这一突发模式;

  6. 寻址时序Timing):DDR3则在5~11之间,且附加延迟(AL)的设计也有所变化,DDR3AL有三种选项,分别是0、CL-1CL-2。另外,DDR3还新增加了一个时序参数-写入延迟(CWD),这一参数将根据具体的工作频率而定。

  7. CAS Latency(CL): 5,6,7,8,9时钟周期

  8. tRCDRAS to CAS Delay,行选通到列激活最小延时,即行选通周期;

  9. tRPRAS预充电时间;

  10. tRAS,激活预充电延时;

  11. CMD,命令速率,芯片激活向存储器发送第一个数据的时间。

  12. 两个参考电压:在DDR3系统中,对于内存系统工作非常重要的参考电压信号VREF将分为两个信号,即为命令与地址信号服务的VREFCA和为数据总线服务的VREFDQ,这将有效地提高系统数据总线的信噪等级。

  13. 点对点连接Point-to-PointP2P):大大地减轻了地址/命令/控制与数据总线的负载。面向64位构架的DDR3显然在频率和速度上拥有更多的优势,此外,由于DDR3所采用的根据温度自动自刷新、局部自刷新等其它一些功能。

  14. JEDEC标准(JESD79-3)

规定的DDR3芯片以及内存条相关参数:
在这里插入图片描述

  1. DQS(数据选取脉冲),它的功能主要用来在一个时钟周期内准确的区分出每个传输周期,并便于接收方准确接收数据。

写时序
在这里插入图片描述

读时序
在这里插入图片描述

5.SDRAM与DDR速度对比:

DDR3DDR一样是双倍数据传输速率。
在这里插入图片描述

二、DDR3接口模块IP核调用

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、DDR3读写控制

通过控制模块,实现数据突发读写,将摄像头OV5640传过来的数据从慢时钟域到快时钟域传输数据,再从SDRAM按帧为单位,从快时钟域到慢时钟域发送数据,通过HDMI显示到屏幕上。
对于跨时钟域数据的传输采用异步FIFO缓存,然后通过乒乓操作,控制读写区域。先将SDRAMBank1用于写数据,同时读取Bank3的数据输出显示,当读写都完成后,在交换读写地址,并保证屏幕上输出的图像都是完整的一帧。
因此,对于读取侧数据没有读完之前,写侧就丢弃当前帧。

1.读写仲裁

通过这种乒乓操作保证数据的有效传输。

/************************读写优先级仲裁*****************************/
//rd_flag     ;//读请求标志
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            rd_flag <= 0;
        end 
        else if(rfifo_usedw <= `RD_LT)begin   
            rd_flag <= 1'b1;
        end 
        else if(rfifo_usedw > `RD_UT)begin 
            rd_flag <= 1'b0;
        end 
    end

//wr_flag     ;//写请求标志
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            wr_flag <= 0;
        end 
        else if(wfifo_usedw >= `USER_BL)begin 
            wr_flag <= 1'b1;
        end 
        else begin 
            wr_flag <= 1'b0;
        end 
    end

//flag_sel    ;//标记上一次操作
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            flag_sel <= 0;
        end 
        else if(read2done)begin 
            flag_sel <= 1;
        end 
        else if(write2done)begin 
            flag_sel <= 0;
        end 
    end

//prior_flag  ;//优先级标志 0:写优先级高   1:读优先级高     仲裁读、写的优先级
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            prior_flag <= 0;
        end 
        else if(wr_flag && (flag_sel || (~flag_sel && ~rd_flag)))begin   //突发写优先级高
            prior_flag <= 1'b0;
        end 
        else if(rd_flag && (~flag_sel || (flag_sel && ~wr_flag)))begin   //突发读优先级高
            prior_flag <= 1'b1;
        end 
    end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

2.OV5640的数据写入DDR3的操作

/*********************** wrfifo 写数据   ************************/
//控制像素数据帧 写入 或 丢帧

    always  @(posedge clk_in or negedge rst_n)begin
        if(~rst_n)begin
            wr_data_flag <= 1'b0;
        end 
        else if(~wr_data_flag & ~wr_finish_r[1] & din_sop)begin//可以向wrfifo写数据
            wr_data_flag <= 1'b1;
        end
        else if(wr_data_flag & din_eop)begin//不可以向wrfifo写入数据
            wr_data_flag <= 1'b0;
        end
    end

    always  @(posedge clk_in or negedge rst_n)begin //把wr_finish从wrfifo的读侧同步到写侧
        if(~rst_n)begin
            wr_finish_r <= 0;
        end
        else begin
            wr_finish_r <= {wr_finish_r[0],wr_finish};
        end
    end

/****************************************************************/
    
    //burst_write
    always  @(posedge clk or negedge rst_n)begin
        if(~rst_n)begin
            burst_write <= 1'b0;
        end
        else begin
            burst_write <= idle2write;
        end
    end

    //burst_read
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            burst_read <= 1'b0;
        end
        else begin
            burst_read <= idle2read;
        end
    end

    //avl_read
    always  @(posedge clk or negedge rst_n)begin
        if(~rst_n)begin
            avl_read <= 1'b0;
        end
        else if(idle2read)begin
            avl_read <= 1'b1;
        end
        else if(avl_read & avl_ready)begin 
            avl_read <= 1'b0;
        end 
    end

    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            avl_write <= 1'b0;
        end
        else if(idle2write)begin
            avl_write <= 1'b1;
        end
        else if(write2done)begin
            avl_write <= 1'b0;
        end
    end
  //rd_data rd_data_vld 输出给hdmi接口
    always  @(posedge clk_out or negedge rst_n)begin
        if(~rst_n)begin
            rd_data <= 0;
            rd_data_vld <= 1'b0;
        end
        else begin
            rd_data <= rfifo_q;
            rd_data_vld <= rfifo_rdreq;
        end
    end
    
    wrfifo u_wr_fifo(
    /*input                 */.aclr     (~rst_n       ),
    /*input   [129:0]       */.data     (wfifo_wrdata ),
    /*input                 */.rdclk    (clk          ),
    /*input                 */.rdreq    (wfifo_rdreq  ),
    /*input                 */.wrclk    (clk_in       ),
    /*input                 */.wrreq    (wfifo_wrreq  ),
    /*output  [129:0]       */.q        (wfifo_q      ),
    /*output                */.rdempty  (wfifo_empty  ),
    /*output  [8:0]         */.rdusedw  (wfifo_usedw  ),
    /*output                */.wrfull   (wfifo_full   )
    );

    assign wfifo_wrdata = {din_eop,din_sop,din};
    assign wfifo_wrreq  = ~wfifo_full & din_vld & ((~wr_finish_r[1] & din_sop) | wr_data_flag);
    assign wfifo_rdreq  = state_c == WRITE && avl_ready;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98

3.地址设计

// wr_addr   rd_addr
    always @(posedge clk or negedge rst_n) begin 
        if (rst_n==0) begin
            wr_addr <= 0; 
        end
        else if(add_wr_addr) begin
            if(end_wr_addr)
                wr_addr <= 0; 
            else
                wr_addr <= wr_addr + (`USER_BL << 4);
        end
    end
    assign add_wr_addr = write2done;
    assign end_wr_addr = add_wr_addr && wr_addr == (`BURST_MAX << 1)- (`USER_BL << 4);
    
    always @(posedge clk or negedge rst_n) begin 
        if (rst_n==0) begin
            rd_addr <= 0; 
        end
        else if(add_rd_addr) begin
            if(end_rd_addr)
                rd_addr <= 0;
            else
                rd_addr <= rd_addr + (`USER_BL << 4);
       end
    end
    assign add_rd_addr = read2done;
    assign end_rd_addr = add_rd_addr && rd_addr == (`BURST_MAX << 1)- (`USER_BL << 4);

//wr_finish     一帧数据全部写到SDRAM
    always  @(posedge clk or negedge rst_n)begin
        if(~rst_n)begin
            wr_finish <= 1'b0;
        end
        else if(~wr_finish & wfifo_q[129])begin  //写完  从wrfifo读出eop
            wr_finish <= 1'b1;
        end
        else if(wr_finish && end_rd_addr)begin  //读完
            wr_finish <= 1'b0;
        end
    end

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

4.乒乓操作

//change_bank ;//切换bank 
    always  @(posedge clk or negedge rst_n)begin
        if(~rst_n)begin
            change_bank <= 1'b0;
        end
        else begin
            change_bank <= wr_finish && end_rd_addr;
        end
    end

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

5.读侧FIFO

rdfifo u_rd_fifo(
    /*input               */.aclr   (~rst_n       ),
    /*input   [127:0]     */.data   (rfifo_wrdata ),
    /*input               */.rdclk  (clk_out      ),
    /*input               */.rdreq  (rfifo_rdreq  ),
    /*input               */.wrclk  (clk          ),
    /*input               */.wrreq  (rfifo_wrreq  ),
    /*output  [15:0]      */.q      (rfifo_q      ),
    /*output              */.rdempty(rfifo_empty  ),
    /*output              */.wrfull (rfifo_full   ),
    /*output  [8:0]       */.wrusedw(rfifo_usedw  )    
    );

    assign rfifo_wrdata = avl_rdata;
    assign rfifo_rdreq = ~rfifo_empty & rd_req;
    assign rfifo_wrreq = avl_rdata_valid & ~rfifo_full;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

6.ddr3_controller模块


    assign initial_done = rst_n & local_init_done & local_cal_success;

//模块例化

    ddr3_rw_ctrl  u_ctrl(
    /*input               */.clk                (afi_clk            ),//ddr3侧时钟
    /*input               */.clk_in             (clk_in             ),//摄像头数据输入侧时钟
    /*input               */.clk_out            (clk_out            ),//HDMI数据输出侧时钟
    /*input               */.rst_n              (rst_n              ),
    
    //user interface
    /*input               */.rd_req             (rd_req             ),//hdmi_driver读取数据请求
    /*input   [127:0]     */.din                (din                ),//摄像头写入mem的数据
    /*inpput              */.din_sop            (din_sop            ),
    /*input               */.din_eop            (din_eop            ),
    /*input               */.din_vld            (din_vld            ),
    /*output  [15:0]      */.dout               (dout               ),//发送到显示器的数据
    /*output              */.dout_vld           (dout_vld           ),

    //ddr3_interface interface
    /*output              */.avl_ready          (avl_ready          ),//avl.waitrequest_n
	/*input               */.avl_burstbegin     (avl_burstbegin     ),//.beginbursttransfer
	/*input   [25:0]      */.avl_addr           (avl_addr           ),//.address
	/*output              */.avl_rdata_valid    (avl_rdata_valid    ),//.readdatavalid
	/*output  [127:0]     */.avl_rdata          (avl_rdata          ),//.readdata
	/*input   [127:0]     */.avl_wdata          (avl_wdata          ),//.writedata
	/*input   [15:0]      */.avl_be             (avl_byteenable     ),//.byteenable
	/*input               */.avl_read_req       (avl_read_req       ),//.read
	/*input               */.avl_write_req      (avl_write_req      ),//.write
	/*input   [8:0]       */.avl_size           (avl_size           ) //.burstcount
    );

    ddr3_interface u_dddr3_intf(
	/*input  wire         */.pll_ref_clk         (clk               ),//给ip内部PLL的参考时钟
	/*input  wire         */.global_reset_n      (rst_n             ),//global_reset.reset_n
	/*input  wire         */.soft_reset_n        (1'b1              ),//soft_reset.reset_n
	/*output wire         */.afi_clk             (afi_clk           ),//afi_clk.clk
	/*output wire         */.afi_half_clk        (                  ),//afi_half_clk.clk
	/*output wire         */.afi_reset_n         (                  ),//afi_reset.reset_n
	/*output wire         */.afi_reset_export_n  (                  ),//afi_reset_export.
	/*output wire [14:0]  */.mem_a               (mem_addr          ),//memory.mem_a
	/*output wire [2:0]   */.mem_ba              (mem_bank          ),//.mem_ba
	/*output wire [0:0]   */.mem_ck              (mem_ck_p          ),//.mem_ck
	/*output wire [0:0]   */.mem_ck_n            (mem_ck_n          ),//.mem_ck_n
	/*output wire [0:0]   */.mem_cke             (mem_cke           ),//.mem_cke
	/*output wire [0:0]   */.mem_cs_n            (mem_cs_n          ),//.mem_cs_n
	/*output wire [3:0]   */.mem_dm              (mem_dqm           ),//.mem_dm
	/*output wire [0:0]   */.mem_ras_n           (mem_rasn          ),//.mem_ras_n
	/*output wire [0:0]   */.mem_cas_n           (mem_casn          ),//.mem_cas_n
	/*output wire [0:0]   */.mem_we_n            (mem_wen           ),//.mem_we_n
	/*output wire         */.mem_reset_n         (mem_rest_n        ),//.mem_reset_n
	/*inout  wire [31:0]  */.mem_dq              (mem_dq            ),//.mem_dq
	/*inout  wire [3:0]   */.mem_dqs             (mem_dqs_p         ),//.mem_dqs
	/*inout  wire [3:0]   */.mem_dqs_n           (mem_dqs_n         ),//.mem_dqs_n
	/*output wire [0:0]   */.mem_odt             (mem_odt           ),//.mem_odt
	/*output wire         */.avl_ready           (avl_ready         ),//avl.waitrequest_n
	/*input  wire         */.avl_burstbegin      (avl_burstbegin    ),//.beginbursttransfer
	/*input  wire [25:0]  */.avl_addr            (avl_addr          ),//.address
	/*output wire         */.avl_rdata_valid     (avl_rdata_valid   ),//.readdatavalid
	/*output wire [127:0] */.avl_rdata           (avl_rdata         ),//.readdata
	/*input  wire [127:0] */.avl_wdata           (avl_wdata         ),//.writedata
	/*input  wire [15:0]  */.avl_be              (avl_byteenable    ),//.byteenable
	/*input  wire         */.avl_read_req        (avl_read_req      ),//.read
	/*input  wire         */.avl_write_req       (avl_write_req     ),//.write
	/*input  wire [8:0]   */.avl_size            (avl_size          ),//.burstcount
	/*output wire         */.local_init_done     (local_init_done   ),//local_init_done
	/*output wire         */.local_cal_success   (local_cal_success ),//local_cal_success
	/*output wire         */.local_cal_fail      (local_cal_fail    ),//.local_cal_fail
	/*input  wire         */.oct_rzqin           (mem_rzq           ) //oct.rzqin

    //PLL未设置sharing模式,所以这些信号未使能
	//output wire         pll_mem_clk,               //pll_sharing.pll_mem_clk
	//output wire         pll_write_clk,             //.pll_write_clk
	//output wire         pll_locked,                //.pll_locked
	//output wire         pll_write_clk_pre_phy_clk, //.pll_write_clk_pre_phy_clk
	//output wire         pll_addr_cmd_clk,          //.pll_addr_cmd_clk
	//output wire         pll_avl_clk,               //.pll_avl_clk
	//output wire         pll_config_clk,            //.pll_config_clk
	//output wire         pll_mem_phy_clk,           //.pll_mem_phy_clk
	//output wire         afi_phy_clk,               //.afi_phy_clk
	//output wire         pll_avl_phy_clk            //.pll_avl_phy_clk
	);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号