LATTICE进阶篇DDR2--(2)详解IPUG35---基于官方例程

前言

本章主要讲述根据《DDR & DDR2 SDRAM Controller IP Cores User’s Guide 》数据手册,配合ddr2的demo仿真,学习DDR2的IP核时序控制。

器件:Lattice ECP3

环境:Win10 + Diamond3.13 + ModelSim SE-64 10.5

一、下载DDR2UG数据手册

方法1:通过Diamond联网下载

方法2:前往lattice官网下载数据手册IPUG35

《DDR & DDR2 SDRAM Controller IP Cores Users Guide

https://www.latticesemi.com/Search.aspx?&lcid=9&q=IPUG35&t=480

二、分析数据手册

接下来让我们开始研究《DDR & DDR2 SDRAM Controller IP Cores User’s Guide 》

2.1用户命令CMD

2.2DDR初始化

系统复位后,只初始化一次,在上电完成,时钟稳定后,

用户等待200us后产生一个init_start高电平信号给CORE,当CORE完成初始化时序,会发送一个时钟周期的init_done高电平信号,当init_done信号出现高电平,init_start信号拉低。

如果我们不对MR或者EMR寄存器进行配置,则CORE会按照默认配置进行初始化。

DEMO解析--DDR初始化代码

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

// Init_start generation

// - in simulation mode, wait for 128 clock cycles

// - in synthesis mode, wait for +200us from reset_n deassertion

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

always@(posedge k_clk or negedge reset_n) begin

    if (reset_n == 1'b0) begin

        init_cnt        <=  16'h0;

        init_srvcd      <=  1'b0;

        init_start_hit  <=  1'b0;

        init_start      <=  1'b0;

    end

    else begin

        init_cnt    <=  init_cnt + 1;

`ifdef RTL_SIM

        if (init_cnt[6] && !init_srvcd) begin       // to save the simulation run time

`else

        if (init_cnt[15] && init_cnt[13] && !init_srvcd) begin

`endif

            init_srvcd      <=  1'b1;

            init_start_hit  <=  1'b1;

        end

        else

            init_start_hit  <=  1'b0;

        if (init_start_hit)

            init_start      <=  1'b1;

        if (init_done)

            init_start      <=  1'b0;

    end

end

assign init_start = init_start_req && pll_lock && dll_lock;

2.3DDR的自刷新模式

该模式一般在IP核设置为使能,不需要写代码,直接使用,了解即可。

内存控制器自带自刷新模式,一旦使能,ext_auto_ref被用户拉高,来强制CORE产生一连串的刷新指令,当CORE产生刷新指令后,ext_auto_ref_acklag拉高一个时钟周期,当ext_auto_ref_acklag信号出现高电平,ext_auto_ref信号拉低。

2.4DDR的命令和地址控制

 一旦内存初始化完成,IP核就会等待用户命令来访问内存。用户需要向IP核提供命令和地址以及控制信号。命令和地址是按照以下描述的过程传递给IP核:

  1. IP核输出的cmd_rdy信号拉高一个时钟周期,代表其已准备好接收用户命令。
  2. IP核输出的cmd_rdy信号拉高时,如果用户逻辑也拉高了cmd_valid信号,IP核输就会将cmd输入作为有效的用户命令进行处理。

如果cmd_valid没有被拉高,cmd和addr输入将变为无效,IP核将忽略它们。

  1. 当cmd_rdy信号为低时,cmdaddrcmd_valid将变为无效,IP核将会忽略它们。
  2. cmd_rdy信号再次拉高,则准备执行下一个命令。

DEMO解析--DDR的命令和地址控制代码

1.在初始化完成后,IP核发出cmd_rdy信号。

2.在初始化完成后,一直拉高cmd_valid信号。

3.cmd_rdy拉低时,就应该准备好addr burst_count的信号。

4.每出现一次cmd_rdy,状态机就跳转一次。

PS:此处的CMD=6LOAD_MR)在实际的工程中是不需要我们去写的,一旦配置好DDR2IP核,就会自动产生,实际的工程中我们只需要去控制写命令和读命令,DEMO工程中并没有配置DDR2IP核,而是调用该IP的一些源文件,与实际工程有所不同。

// ==============================================================================

// state assignments & defines

// ==============================================================================

`define     IDLE            0

`define     CONF_MR         1

`define     CONF_EMR        2

`define     WRITE_CMD       3

`define     READ_CMD        4

 

// ==============================================================================

// Demo configuration generation

// ==============================================================================

assign  BL_MODE     =   switch[0];

assign  ODT_SEL     =   switch[2:1];

assign  CMD_BRST    =   switch[5:3];

assign  DATA_MODE   =   switch[6];      // 1: PRBS,     0: Sequential

assign  DEMO_MODE   =   switch[7];      // 1: Non-stop, 0: Single Wr/Rd

assign  MR_DATA     =   BL_MODE ? 16'h0643 : 16'h0642;  // 1: BL8, 0: BL4

assign  EMR_DATA    =   (ODT_SEL == 2'b11) ? 16'h2004 : // 75-ohm

                        (ODT_SEL == 2'b10) ? 16'h2040 : // 150-ohm

                        (ODT_SEL == 2'b01) ? 16'h2044 : // 50-ohm

                                             16'h2000 ; // disabled

assign  data_mask   =   {`DSIZE/8{1'b0}};

`ifdef BRST_CNT_EN  

 assign burst_count =   (CMD_BRST == 3'b100) ? 5'd16 :

                        (CMD_BRST == 3'b011) ? 5'd8  :

                        (CMD_BRST == 3'b010) ? 5'd4  :

                        (CMD_BRST == 3'b001) ? 5'd2  :

                        (CMD_BRST == 3'b000) ? 5'd1  :

                                               5'd0;    // 32-command burst in all other cases

`endif

 

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

//  Address and Command Generation

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

assign  cmd_gone    =   cmd_rdy && cmd_valid;

 

// ==============================================================================

// Command generation state machine

// ==============================================================================

always @(posedge k_clk or negedge reset_n) begin

    if (reset_n == 1'b0) begin

        cmdgen          <=  `IDLE;

        cmd             <=  4'h6;

        cmd_valid       <=  1'b0;

        addr            <=  {`ADDR_WIDTH{1'b0}};    

    end

    else begin

        case (cmdgen)

        `IDLE : begin           // :0

            if (init_done) begin

                cmdgen      <=  `CONF_MR;

                cmd_valid   <=  1'b1;  

            end

            else begin

                cmdgen      <=  `IDLE;

            end

        end

        `CONF_MR : begin        // :1

            cmd         <=  4'h6;               // LOAD_MR command for MR

            addr        <=  MR_DATA;

            if (cmd_gone) begin

                cmdgen      <=  `CONF_EMR;

            end

            else

                cmdgen      <=  `CONF_MR;

        end

        `CONF_EMR : begin       // :2

            addr        <=  EMR_DATA;           // LOAD_MR command for EMR

            if (cmd_gone) begin

                cmdgen      <=  `WRITE_CMD;

            end

            else

                cmdgen      <=  `CONF_EMR;

        end

        `WRITE_CMD : begin      // :3

            cmd         <=  4'h2;               // WRITE command

            addr        <=  addr_wr;

            if (cmd_gone) begin

                cmdgen      <=  `READ_CMD;

            end

            else begin

                cmdgen      <=  `WRITE_CMD;

            end

        end

        `READ_CMD : begin       // :4

            cmd         <=  4'h1;               // READ command    

            addr        <=  addr_rd;

            if (cmd_gone) begin

                if (DEMO_MODE) begin

                    cmdgen      <=  `WRITE_CMD;

                end

                else begin

                    cmdgen      <=  `IDLE;      // Run only one Write-Read cycle

                    cmd_valid   <=  1'b0;

                end

            end

            else begin

                cmdgen      <=  `READ_CMD;

            end

        end

        endcase

    end

end

 

 

2.5DDR的写数据控制

1.在IP核接收到写命令之后,当它准备好接收要写入内存的数据时,IP核会拉高data_rdy信号。

2.一旦data_rdy被拉高,在data_rdy信号拉高后的一到两个时钟周期内(由WrRqDDelay决定),写数据线上必须接收到有效数据。

实际的工程中,写数据延迟是通过IP核配置的。

DEMO解析--Write Data产生代码

 

1.当data_rdy为高时,就发送数据。(时序逻辑,会延后1拍)

// ==============================================================================

// state assignments & defines

// ==============================================================================

 

`define     WAIT_RDY        1

 

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

//

//  Data Generation and Result Chcker

//

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

always @(posedge k_clk or negedge reset_n) begin

    if (reset_n == 1'b0) begin

        datagen         <=  `IDLE;

        write_data      <=  {`DSIZE{1'b0}};

    end

    else begin

        case (datagen)

            `IDLE : begin

                if (init_done)

                    datagen     <= `WAIT_RDY;

                else

                    datagen     <= `IDLE;

            end

       

            `WAIT_RDY : begin

                if (data_rdy) begin

                    write_data  <=  curr_data;

                    datagen     <= `WAIT_RDY;

                end

                else begin

                    datagen     <= `WAIT_RDY;

                end

            end

        endcase

    end

end

assign  gen_data        =   (datagen == `WAIT_RDY) && data_rdy;

assign  idle_data       =   (datagen == `IDLE);

 

 

2.6DDR的读数据控制

1.当IP核接收读命令后,IP核就会产生read_data_valid信号,此时有效读取数据已经在read_data总线上。

与写数据不同,读数据是没有读数据延迟。

EMO解析--Read Data代码

1.read_data没什么好讲的,按照时序正常接收就行。

 

// ==============================================================================

// Sequential expected data generator

// ==============================================================================

always @(posedge k_clk or negedge reset_n) begin

    if (reset_n == 1'b0) begin

        chk_seq_data32          <=  32'h1;

        read_data_valid_d       <=  1'b0;

        read_data_valid_d2      <=  1'b0;

        read_data_valid_d3      <=  1'b0;

    end

    else begin

        read_data_valid_d       <=  read_data_valid;    

        read_data_valid_d2      <=  read_data_valid_d;

        read_data_valid_d3      <=  read_data_valid_d2;

        if (read_data_valid_d) begin

            chk_seq_data32      <=   chk_seq_data32 +1;

        end

    end

end

assign  expect_data =   (DATA_MODE == 1'b1) ?  chk_rndm_data : chk_seq_data;

always @(posedge k_clk or negedge reset_n) begin

    if (reset_n == 1'b0) begin

        read_data_d         <=  {`DSIZE{1'b0}};

        read_data_2d        <=  {`DSIZE{1'b0}};

        expect_data_d       <=  {`DSIZE{1'b0}};

    end

    else begin

        read_data_d         <=  read_data;

        read_data_2d        <=  read_data_d;

        expect_data_d       <=  expect_data;

    end

end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/292582.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【链表专题】(2. 两数相加 23. 合并 K 个升序链表 25. K 个一组翻转链表)

文章目录 2. 两数相加23. 合并 K 个升序链表25. K 个一组翻转链表 2. 两数相加 题目链接: leetcode2. 两数相加 class Solution {public ListNode addTwoNumbers(ListNode l1, ListNode l2) {ListNode cur1 l1,cur2 l2;ListNode newHead new ListNode(0);ListNode prev ne…

STM32的简介

内存 一般MCU包含的存储空间有FLASH和RAM,&#xff08;RAM和flash又有片上和片外的区别&#xff0c;片上表示mcu自带的&#xff0c;已经封装在MCU内部的&#xff0c;片外表示外挂的&#xff0c;当项目中需要做一些复杂的应用&#xff0c;会存在资源不足的情况&#xff0c;这时…

MIT最新研究成果 机器人能够从错误中纠偏 无需编程介入和重复演示

目前科学家们正在努力让机器人变得更加智能&#xff0c;教会他们完成诸如擦拭桌面&#xff0c;端盘子等复杂技能。以往机器人要在非结构化环境执行这样的任务&#xff0c;需要依靠固定编程进行&#xff0c;缺乏场景通用性&#xff0c;而现在机器人的学习过程主要在于模仿&#…

LeetCode 双指针专题

11.盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不…

数据结构——lesson13排序之计数排序

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

基于单片机锂电池电量检测数码管显示系统设计

**单片机设计介绍&#xff0c;基于单片机锂电池电量检测数码管显示系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机锂电池电量检测数码管显示系统设计的主要目标是实时、准确地检测锂电池的电量&#xff0c;并…

【python】常用函数汇总(持续更新……)

文章目录 【numpy.exp()】返回e的幂次方&#xff0c;e是一个常数为2.71828【np.dot()】矩阵相乘【np.linalg.inv()】矩阵求逆 【numpy.exp()】返回e的幂次方&#xff0c;e是一个常数为2.71828 举例&#xff1a;numpy.exp() 【np.dot()】矩阵相乘 【要点】 1、前者的列数后者…

浅谈Spring体系的理解

浅谈Spring知识体系 Spring Framework架构图Spring家族技术生态全景图XMind汇总 本文不涉及细节&#xff0c;主要回答两个问题&#xff1a; Spring家族技术生态全景图有哪些Spring Framework架构下每个模块有哪些东西&#xff0c;以及部分模块之间的关联关系 Spring Framework架…

iOS - Runtime - Class的结构

文章目录 iOS - Runtime - Class的结构前言1. Class的结构1.1 Class的结构1.1.1 objc_class1.1.2 class_rw_t1.1.3 class_ro_t 1.2 class_rw_t和class_ro_t的区别1.3 class_rw_t和class_ro_t的关系1.3.1 分析关系1.3.2 原因 1.4 method_t1.4.1 Type Encoding1.4.2 types说明1.4…

AJAX-项目优化(目录、基地址、token、请求拦截器)

目录管理 基地址存储 在utils/request.js配置axios请求基地址 作用&#xff1a;提取公共前缀地址&#xff0c;配置后axios请求时都会baseURLurl 填写API的公共前缀后&#xff0c;将js文件导入到html文件中 <script src"../../utils/request.js"></script&…

深度学习算法概念介绍

前言 深度学习算法是一类基于人工神经网络的机器学习方法&#xff0c;其核心思想是通过多层次的非线性变换&#xff0c;从数据中学习表示层次特征&#xff0c;从而实现对复杂模式的建模和学习。深度学习算法在图像识别、语音识别、自然语言处理等领域取得了巨大的成功&#xf…

STM32的IAP技术,BootLoader

来源 三种下载方式&#xff1a; 1、ICP&#xff1a;ST-Link, 2、ISP: FlyMcu, 3、IAP IAP简介 IAP技术的核心在于BootLoader程序的设计&#xff0c;这段程序预先烧录在单片机中&#xff0c;正常的APP程序可以使用BootLoader程序中的IAP功能写入&#xff0c;也可以两部分代码一…

docker使用教程

寒假用了docker 2个月没用 结果还重新安装docker 忘了怎么用 为了免得以后忘写下下面内容 # If you dont have a docker installed, youll need to install docker curl -s https://get.docker.com/ | sh # Use pip to install docker-compose pip install docker-compose…

排序第五篇 归并排序

一 简介 归并排序(Merge Sort) 的基本思想是&#xff1a; 首先将待排序文件看成 n n n 个长度为1的有序子文件&#xff0c; 把这些子文件两两归并&#xff0c; 得到 n 2 \frac{n}{2} 2n​ 个长度为 2 的有序子文件&#xff1b; 然后再把这 n 2 \frac{n}{2} 2n​ 个有序的子…

EI期刊和EI会议有哪些不同?别再傻傻分不清

EI工程索引是综合性检索机构&#xff0c;是三个著名学术检索系统之一&#xff0c;EI工程索引也分为EI期刊和EI会议&#xff0c;那么两者有哪些不同&#xff1f;作者又该如何选&#xff1f;本文系统分享一下相关的知识&#xff0c;仅供学术人员参考&#xff1a; 第一、文章质量不…

2014年认证杯SPSSPRO杯数学建模A题(第二阶段)轮胎的花纹全过程文档及程序

2014年认证杯SPSSPRO杯数学建模 A题 轮胎的花纹 原题再现&#xff1a; 轮胎被广泛使用在多种陆地交通工具上。根据性能的需要&#xff0c;轮胎表面常会加工出不同形状的花纹。在设计轮胎时&#xff0c;往往要针对其使用环境&#xff0c;设计出相应的花纹形状。   第二阶段问…

南京观海微电子---Vitis HLS的工作机制——Vitis HLS教程

1. 前言 Vitis HLS&#xff08;原VivadoHLS&#xff09;是一个高级综合工具。用户可以通过该工具直接将C、 C编写的函数翻译成HDL硬件描述语言&#xff0c;最终再映射成FPGA内部的LUT、DSP资源以及RAM资源等。 用户通过Vitis HLS&#xff0c;使用C/C代码来开发RTL IP核&#x…

前端优化gzip

gzip是GNUzip的缩写&#xff0c;是一种文件的压缩格式&#xff08;也可以说是若干种文件压缩程序&#xff09;&#xff0c;类似的压缩格式还有compress&#xff08;webpack&#xff09;&#xff0c;deflate等 主要用于组件的压缩 压缩的话主要分为两种&#xff0c; 服务器在…

TCP网络协议栈和Posix网络部分API总结

文章目录 Posix网络部分API综述TCP协议栈通信过程TCP三次握手和四次挥手&#xff08;看下图&#xff09;三次握手常见问题&#xff1f;为什么是三次握手而不是两次&#xff1f;三次握手和哪些函数有关&#xff1f;TCP的生命周期是从什么时候开始的&#xff1f; 四次挥手通信状态…

强化基础-Java-泛型基础

什么是泛型&#xff1f; 泛型其实就参数化类型&#xff0c;也就是说这个类型类似一个变量是可变的。 为什么会有泛型&#xff1f; 在没有泛型之前&#xff0c;java中是通过Object来实现泛型的功能。但是这样做有下面两个缺陷&#xff1a; 1 获取值的时候必须进行强转 2 没有…