• DDR3-基于正点原子达芬奇100Tpro1.0版本


    1.DDR3硬件设计

    在这里插入图片描述

    2.DDR3引脚作用

    信号类型作用
    CK,~CKInput一对差分信号时钟,可在CK的上升沿和下降沿采样
    CKEInput时钟使能,操作使能,为低时只能自刷新
    CSInput片选信号
    RAS,CAS,WEInput指令线
    For x8 DM,Forx16 DMU DMLInput屏蔽数据
    BA0-BA2Inputbank地址
    A10/APInput自动刷新的控制
    For x8, A0-A14/For x16 A0-A13Inpout地址线
    A12/BCInput突发模式控制线,默认8突发
    ODTInput自动的电压校准,使差分时钟保持稳定,低有效
    RESET_NInput复位信号
    DQInput/Output数据线
    For x8DQS,(DQS_N)/For x8 DQSL,DQSUInput/output数据选择脉冲
    For x8,TDQSOutput

    3.DDR3时序

    3.1 初始化时序

    在这里插入图片描述
    1.上电时复位信号保持低电平,其他信号随意。复位低电平至少保持200us,CKE要在复位信号拉高之前至少保持10ms的低电平。
    2.复位信号失效后需要等待500us,CKE信号开始拉高,在此期间DRAM开始初始化。
    3.CKE为高电平且稳定后,需要加载寄存器。
    4.配置寄存器时指令是相同的,通过BA0-BA2来控制是配置MR。如MR2是BA2-BA0->010;
    5.配置完成后需要ZQCL校准。

    3.2DDR3寄存器配置

    在这里插入图片描述

    寄存器作用
    BL突发长度
    CL突发长度
    RBT顺序读还是常规读
    CASCL延迟配置
    BL突发长度

    4.程序设计

    DDR3 SDRAM程序过于复杂,因此官方提供MIG IP核来简化DDR3 SDRAM的驱动程序开发
    MIG IP核集成了SDRAM DDR2 DDR3接口,将原本的上电、刷新、读、写四个过程简化为了只有读写两个过程,且不用考虑行选通和列选通的等待时间,大大简化了DDR控制器的操作难度
    在这里插入图片描述

    4.1 MIG核 接口介绍

    DDR3有四突发和八突发模式,当控制时钟和DDR的时钟在1:4时默认八突发。此时数据线是DDR硬件位宽的八倍。128:16或者256:32。
    读数据接口

    Column 1Column 2
    app_addr[ADDR_WIDTH-1:0]DDR3的地址线
    app_cmd[2:0]DDR3指令手册,只有读写两个指令
    app_enMIG核的使能信号
    app_rdy表示MIG核可以接受指令
    app_hi_pri优先级指令
    app_rd_data[APP_DATA_WIDTH-1:0]读出的数据
    app_rd_data_end最后一次突发,突发结束标志位
    app_rd_data_valid读数据有效标志
    app_sz需要保留并置零

    写数据接口

    Column 1Column 2
    app_wdf_data[APP_DATA_WIDTH-1:0]为写命令提供数据
    app_wdf_end突发写操作的最后一个时钟周期
    app_wdf_mask[APP_DATA_WIDTH-1:0]数据掩码
    app_wdf_rdy写数据允许标志
    app_wdf_wren写数据使能
    app_correct_en_i纠错功能
    app_sr_req保留并且置零
    app_sr_active保留

    其他接口

    Column 1Column 2
    app_ref_req刷新请求
    app_ref_ack刷新请求的应答
    app_zq_req校准请求
    app_zq_ack校准请求应答
    ui_clk用户时钟,由DRAM时钟的四分之一或者二分之一
    init_calib_complete初始化完成标志
    app_ecc_multiple_err[7:0]当开启ECC功能并且数据有效时的纠错指示位
    ui_clk_sync_rstUI复位,高电平有效
    app_ecc_single_err[7:0]

    4.2 MIG核时序

    在这里插入图片描述
      当app_en和app_rdy同时为高时,地址和写命令才有效
    背靠背和非背靠背
      地址和命令是否连续。
    在这里插入图片描述
    如上图所示,写数据有三种情形均可以正确写入:
      (1)写数据时序和写命令时序发生在同一拍;
      (2)写数据时序比写命令时序提前一拍;
      (3)写数据时序比写命令时序至多延迟晚两拍;

    5.程序源码

    //****************************************Copyright (c)***********************************//
    //原子哥在线教学平台:www.yuanzige.com
    //技术支持:www.openedv.com
    //淘宝店铺:http://openedv.taobao.com 
    //关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
    //版权所有,盗版必究。
    //Copyright(C) 正点原子 2018-2028
    //All rights reserved	                               
    //----------------------------------------------------------------------------------------
    // File name:           ddr3_rw_top
    // Last modified Date:  2019/8/21 9:56:36
    // Last Version:        V1.0
    // Descriptions:        读写测试实现模块
    //----------------------------------------------------------------------------------------
    // Created by:          正点原子
    // Created date:        2019/8/21 10:55:56
    // Version:             V1.0
    // Descriptions:        The original version
    //
    //****************************************************************************************//
    
     module ddr3_rw (          
         input                    ui_clk,                //用户时钟
         input                    ui_clk_sync_rst,       //复位,高有效
         input                    init_calib_complete,   //DDR3初始化完成
         input                    app_rdy,               //MIG 命令接收准备好标致
         input                    app_wdf_rdy,           //MIG数据接收准备好
         input                    app_rd_data_valid,     //读数据有效
         input          [255:0]   app_rd_data,           //用户读数据
         output reg     [27:0]    app_addr,              //DDR3地址                      
         output                   app_en,                //MIG IP发送命令使能
         output                   app_wdf_wren,          //用户写数据使能
         output                   app_wdf_end,           //突发写当前时钟最后一个数据 
         output         [2:0]     app_cmd,               //MIG IP核操作命令,读或者写
         output reg     [255:0]   app_wdf_data,          //用户写数据
         output reg     [1 :0]    state,                 //读写状态
         output reg     [23:0]    rd_addr_cnt,           //用户读地址计数
         output reg     [23:0]    wr_addr_cnt,           //用户写地址计数
         output reg     [20:0]    rd_cnt,                //实际读地址标记
         output reg               error_flag,            //读写错误标志
         output reg               led                    //读写测试结果指示灯
         );
     
     //parameter define
     parameter  TEST_LENGTH = 1000;
     parameter  L_TIME = 25'd25_000_000;
     parameter  IDLE        = 2'd0;            //空闲状态
     parameter  WRITE       = 2'd1;            //写状态
     parameter  WAIT        = 2'd2;            //读到写过度等待
     parameter  READ        = 2'd3;            //读状态
     
     //reg define
     reg  [24:0]  led_cnt;    //led计数
     
     //wire define
     wire         error;     //读写错误标记
     wire         rst_n;     //复位,低有效
     
      //*****************************************************
     //**                    main code
     //***************************************************** 
     
     assign rst_n = ~ui_clk_sync_rst;
     //读信号有效,且读出的数不是写入的数时,将错误标志位拉高
    assign error = (app_rd_data_valid && (rd_cnt!=app_rd_data));
     
     //在写状态MIG IP 命令接收和数据接收都准备好,或者在读状态命令接收准备好,此时拉高使能信号,
     assign app_en = ((state == WRITE && (app_rdy && app_wdf_rdy))
                     ||(state == READ && app_rdy)) ? 1'b1:1'b0;
                     
     //在写状态,命令接收和数据接收都准备好,此时拉高写使能
     assign app_wdf_wren = (state == WRITE && (app_rdy && app_wdf_rdy)) ? 1'b1:1'b0;
     
     //由于DDR3芯片时钟和用户时钟的分频选择4:1,突发长度为8,故两个信号相同
     assign app_wdf_end = app_wdf_wren; 
     
     //处于读的时候命令值为1,其他时候命令值为0
     assign app_cmd = (state == READ) ? 3'd1 :3'd0;  
         
     //DDR3读写逻辑实现
     always @(posedge ui_clk or negedge rst_n) begin
         if((~rst_n)||(error_flag)) begin 
             state    <= IDLE;          
             app_wdf_data <= 128'd0;     
             wr_addr_cnt  <= 24'd0;      
             rd_addr_cnt  <= 24'd0;       
             app_addr     <= 28'd0;          
         end
         else if(init_calib_complete)begin               //MIG IP核初始化完成
             case(state)
                 IDLE:begin
                     state    <= WRITE;
                     app_wdf_data <= 256'd0;   
                     wr_addr_cnt  <= 24'd0;     
                     rd_addr_cnt  <= 24'd0;       
                     app_addr     <= 28'd0;        
                  end
                 WRITE:begin
                     if(wr_addr_cnt == TEST_LENGTH - 1 &&(app_rdy && app_wdf_rdy))
                         state    <= WAIT;                  //写到设定的长度跳到等待状态
                     else if(app_rdy && app_wdf_rdy)begin   //写条件满足
                         app_wdf_data <= app_wdf_data + 1;  //写数据自加
                         wr_addr_cnt  <= wr_addr_cnt + 1;   //写地址自加
                         app_addr     <= app_addr + 8;      //DDR3 地址加8
                     end
                     else begin                             //写条件不满足,保持当前值
                         app_wdf_data <= app_wdf_data;      
                         wr_addr_cnt  <= wr_addr_cnt;
                         app_addr     <= app_addr; 
                     end
                   end
                 WAIT:begin                                                  
                     state   <= READ;                     //下一个时钟,跳到读状态
                     rd_addr_cnt <= 24'd0;                //读地址复位
                     app_addr    <= 28'd0;                //DDR3读从地址0开始
                   end
                 READ:begin                               //读到设定的地址长度    
                     if(rd_addr_cnt == TEST_LENGTH - 1 && app_rdy)
                         state   <= IDLE;                   //则跳到空闲状态 
                     else if(app_rdy)begin                  //若MIG已经准备好,则开始读
                         rd_addr_cnt <= rd_addr_cnt + 1'd1; //用户地址每次加一
                         app_addr    <= app_addr + 8;       //DDR3地址加8
                     end
                     else begin                             //若MIG没准备好,则保持原值
                         rd_addr_cnt <= rd_addr_cnt;
                         app_addr    <= app_addr; 
                     end
                   end
                 default:begin
                     state    <= IDLE;
                     app_wdf_data <= 256'd0;
                     wr_addr_cnt  <= 24'd0;
                     rd_addr_cnt  <= 24'd0;
                     app_addr     <= 28'd0;
                 end
             endcase
         end
     end   
                             
     //对DDR3实际读数据个数编号计数
     always @(posedge ui_clk or negedge rst_n) begin
         if(~rst_n) 
             rd_cnt  <= 0;              //若计数到读写长度,且读有效,地址计数器则置0                                    
         else if(app_rd_data_valid && rd_cnt == TEST_LENGTH - 1)
              rd_cnt <= 0;              //其他条件只要读有效,每个时钟自增1
         else if (app_rd_data_valid )
             rd_cnt <= rd_cnt + 1;
     end
     
     //寄存状态标志位
     always @(posedge ui_clk or negedge rst_n) begin
         if(~rst_n) 
             error_flag <= 0;
         else if(error)
             error_flag <= 1;
      end
      
     //led指示效果控制
     always @(posedge ui_clk or negedge rst_n) begin
          if((~rst_n) || (~init_calib_complete )) begin
             led_cnt <= 25'd0;
             led <= 1'b0;
         end
         else begin
             if(~error_flag)                        //读写测试正确         
                 led <= 1'b1;                       //led灯常亮
              else begin                            //读写测试错误
                 led_cnt <= led_cnt + 25'd1;
                 if(led_cnt == L_TIME - 1'b1) begin
                 led_cnt <= 25'd0;
                 led <= ~led;                      //led灯闪烁
                 end                    
              end
           end
     end
     
     endmodule
    
    
    • 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
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
  • 相关阅读:
    GmNAC181促进结瘤并提高根瘤的耐盐性
    Android毕业论文选题基于Uniapp实现的在线投票App问卷调查
    java项目之固定资产管理系统(源码+文档)
    Linux:管道命令与文本处理三剑客(grep、sed、awk)
    kenlm
    python 基础知识点(蓝桥杯python科目个人复习计划56)
    帆软FineReport本地部署springboot
    Jmeter性能监控
    Python 中浅拷贝(copy)和深拷贝(deepcopy)
    idea常用快捷键(mac版)
  • 原文地址:https://blog.csdn.net/q1594/article/details/126179356