Spartan6 FPGA DDR3 IP核调试及程序示例

2024-06-07 06:58

本文主要是介绍Spartan6 FPGA DDR3 IP核调试及程序示例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Spartan6 FPGA芯片中集成了MCB硬核,它可以支持到DDR3。在ISE中提供了MIG IP核,可以用它来生成 DDR3 控制器,并通过 MIG 的 GUI 图形界面完成相关配置。可以参照其官方datasheet查看其用法--UG388
MCB模块信号和架构框图如图3所示,了解内部框图有助于梳理IP核的逻辑架构,更好的完成用户端的逻辑设计。IP核将Memory的控制已经做好并封装起来,提供了FIFO接口给用户端控制,用户只要完成指令FIFO和数据FIFO的读写操作,就能顺利完成对DDR3物理芯片的控制,非常方便。 

                                                                  图3 MCB信号和内部架构框图 


二、IP核生成步骤 
图4-图17是在ISE14.7环境下生成DDR3 IP核的步骤,按照图中设置一步一步点到最后即可生成: 


                                                                图4 选择MIG 



                                                                图5 MIG初始界面 


                                                                图6 IP核命名 



                                                                图7 兼容型号选择 



                                                                图8 存储器类型选择 



                                                                图9 存储器型号参数设置 


                                                                图10 终端匹配设置 



                                                                图11 用户端口设置 



                                                                图12 用户端口操作顺序设置 


                                                                图13 时钟类型、终端电阻设置 



                                                                图14 已设置信息 



                                                                图15 仿真模型选择 



                                                                图16 PCB设计参考文档推荐 


                                                                图17 生成IP核 


点击生成后会在相应的路径下产生三个新的文件夹如图18所示,其中docs为MCB的使用指南文档,example_design是IP核做好的测试范例,生成随机数写入到DDR3里面再读回来比较是否正确,可以用来测试DDR3是否工作正常,也有仿真激励,方便用户学习IP核相关信号的时序。user_design就是用户设计使用的逻辑代码,用户可根据IP核提供的用户端口信号时序进行写、读数据,完成对DDR3的操作。 
 
图18 生成的IP核文件夹 


user_design包含的文件夹如图19,包括自动生成的ucf文件,rtl代码及仿真文件等。 
 
                                           图19 user_design内容介绍 


三、MCB时序分析 
DDR3 IP核提供了端口给用户操作,以FIFO的形式与MCB交互数据,时序简单容易操作。在生成IP核时有一步是选择用户端口模式,提供了5种端口模式供用户选择,不同模式仅与端口个数和位宽有关,操作时序和流程都是一致的,我们所要了解的就是根据时序按照流程完成对端口的操作,如图20所示: 
(1)模式1:两路双向32位端口,四路单向32位端口(可配置为读或写,需读和写为一组)。 
(2)模式2:四路双向32位端口。 
(3)模式3:一路64位双向端口,两路32位双向端口。 
(4)模式4:两路64位双向端口。 
(5)模式5:一路128位双向端口。 


 
                                                                图20 用户端口模式 


每一路端口都有一组FIFO,包括指令FIFO,写数据FIFO和读数据FIFO,具体定义如下。 
(1)指令FIFO,时序如图21所示。 

 
                                                                图21 指令FIFO时序

pX_cmd_clk:指令FIFO同步时钟; 
pX_cmd_en:MCB指令使能信号,高电平有效; 
pX_cmd_instr[2:0]:MCB控制指令,一般为读或者写指令; 
pX_cmd_bl[5:0]: MCB读或写一次的深度,最大为64; 
pX_cmd_byte_addr[29:0]:DDR3的地址空间; 
pX_cmd_empty:指令FIFO空标志,该FIFO最多可以缓冲3个指令; 
pX_cmd_full:指令FIFO满标志,缓冲3个指令即满, 
上图为指令FIFO的时序,以pX_cmd_clk为同步时钟,当pX_cmd_en(p0_cmd_en代表p0端口的指令使能信号,本文中设置使用一个端口p0,并且选择128bit的最大位宽)高电平有效一个pX_cmd_clk时钟周期,就能进行一条写或读指令。指令的具体形式是通过pX_cmd_instr来设置,一般常用的是读和写指令。当指令有效后,MCB就可以和DDR3物理芯片进行数据的交互。pX_cmd_bl是当前一次读写的深度,若pX_cmd_bl=63,此时MCB的位宽设置为128bit,那么每发送一条读或写指令,可以从DDR3中读或往DDR3中写128bitX64=1KB大小的数据。pX_cmd_byte_addr为此次数据的读或写的起始地址,完成一次操作后地址会自动增加。比如一次写128bitX64的数据,并且本次操作的起始地址 pX_cmd_byte_addr为0,那么读或写完后,结束地址则为1023,下次的读或写地址应当从 1024开始,可以看出地址空间是以Byte(8bit)的形式来计算的。pX_cmd_empty和pX_cmd_full则是指令FIFO的空和满的状态指示信号,最多可以缓冲3条指令。 
(2)写数据FIFO,时序如图22所示。 

 
                                                                图22 写数据FIFO时序 


pX_wr_clk:写数据FIFO同步时钟; 
pX_wr_en:写使能信号,高电平有效期间,每一个时钟的上升沿写入一个数据到FIFO; 
pX_wr_mask[3:0]:数据屏蔽; 


pX_wr_empy: FIFO空指示; 
pX_wr_full:FIFO满指示; 
pX_wr_underrun:FIFO溢出指示; 
pX_wr_count[6:0]:写入FIFO的数据个数,计数器为异步信号,不准确,只能做参考。 
通过MCB操作DDR3芯片,数据并不是直接发送给DDR3,我们先要把数据写入MCB的写数据FIFO中,然后DDR3的控制器再将数据从FIFO中读出,依照DDR3的指令写入到DDR3物理芯片中。 
在pX_wr_en高电平期间,每个pX_wr_clk的上升沿写入一个数据到写数据FIFO中。当FIFO没有数据的时候,pX_wr_empy为高电平,当FIFO满的时候则pX_wr_full为高电平,在实际应用中应该避免 pX_wr_full信号有效,当pX_wr_underrun有效时就说明FIFO已经溢出了。pX_wr_count指示当前写入到FIFO的数据个数,由于pX_wr_count也是异步操作,并不能真实反映当前写入的数据个数,但可以作大概评估。比如当我们设置一次写入FIFO数据为64时,并不需要等FIFO写满才发送写指令,可以在pX_wr_count为32的时候就发写指令,能够提高内存的使用效率。 
(3)读数据FIFO,时序如图23所示。 

 
                                                                图23 读数据FIFO时序 


pX_rd_clk:读数据FIFO同步时钟。 
pX_rd_en:读使能信号,高电平有效期间,每一个时钟的上升沿从FIFO中读一个数据。 
pX_rd_empy:FIFO空指示。 
pX_rd_full:FIFO满指示。 
pX_rd_underrun:FIFO空时仍然读的溢出指示信号。 
pX_rd_count[6:0]:FIFO中可供读取的数据个数,不准确,只能做参考。 
同样,如果需要从DDR3芯片中读取数据,也不能直接读取到,必须经过MCB的读数据FIFO。读取FIFO的数据之前,先要进行通过指令FIFO发送一次读 DDR3的指令,由MCB将数据从DDR3物理芯片搬运到读数据 FIFO中,用户再从FIFO中将数据读走。 
当 pX_rd_empy 为低电平的时候,表示FIFO非空,则此时可以从FIFO中读取数据,当pX_rd_empy为高电平,表示FIFO为空,此时不能读FIFO。pX_rd_en高电平时,每一个pX_rd_clk的上升沿,可以从FIFO中读取一个数据。pX_rd_full表示FIFO数据满。pX_rd_underrun表示FIFO没有数据时还读出数据的错误指示。pX_rd_count也是异步操作信号,可用来大致评估FIFO中数据个数,当检测到 pX_rd_count大于32的时候,开始从FIFO中读取数据,便于提高利用效率。 
四、应用实例 
对MCB核有了一定的了解后,下一步就是进行实践操作了。本次工程设计了一个单端口128位模式下,对DDR3全地址空间写数据再读回来对比的测试,按照用户端口的操作流程,先写一个128bit数据到写数据FIFO中,再将写指令写到指令FIFO中,写指令发送完成后将数据和地址递增,直到写满整个地址空间。写完成后开始进行读数据操作,先发送读指令到指令FIFO中,然后等待读数据FIFO非空时将数据读走,将地址递增,直到读完整个地址空间。每读一个数据对比一次,如果不对,则将error信号置为1。 
逻辑设计完后,将生成的位流文件烧写到板上验证,并且使用chipscope观测信号波形是否与时序一致,可以看到写操作波形如图24所示: 


                                                                图24 写数据操作波形 


用chipscope观测到的读操作波形如图25所示: 



                                                                图25 读数据操作波形

以上操作完毕后开始修改代码

1. 首先打开上面生成的user_design文件夹里的par文件夹,找到里面的UCF文件,因为我的VCC AUX电压是2.5V所以不用修改,要是用的3.3就要修改为3.3V

2. 把39行的NET "c?_pll_lock" TIG注释掉,这句不用

3. 修改系统时钟输入的周期为 20ns,  这需要跟你板子上的输入时钟频率一致,如果DDR的输入时钟是FPGA上PLL产生的就把下面这两句屏蔽了就行

4. 如下两个信号的电平标准及引脚约束根据情况设置,如果DDR的输入时钟是FPGA上PLL产生的就把下面这四句屏蔽了就行5. 

5. 下面的这些状态信号的电平标准需要修改,我没有用他们,直接屏蔽也行

打开上面生成的user_design文件夹里的rtl文件夹,打开主程序ddr3_demo.v(这个是你新建IP时命名的DDR3的名字),做如下修改

1. 首先设置复位信号是高电平复位还是低电平复位,根据板子情况修改

2. 由于板上的时钟输入为 50Mhz,  因为 DDR3 是上下沿采样,这样 FPGA 内部的 DDR3控制器的时钟需要625MHz ,所以这里需要倍频25,再分频2,得到625Mhz的CLKOUT0和 CLKOUT1,再分频 8 分别得到 user interface 的时钟CLKOUT2和 calibration 的时钟 CLKOUT3都设置为78.125Mhz。当然CLKOUT2可以设置为其他的时钟频率,但是calibration 的时钟 CLKOUT3一般设置为50M-100M之间,

设置完毕,下面是具体的读写例程,有时间再补上

………………………………………………

参考链接:https://blog.csdn.net/zhyl558/article/details/82018271

 

这篇关于Spartan6 FPGA DDR3 IP核调试及程序示例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1038465

相关文章

SpringBoot线程池配置使用示例详解

《SpringBoot线程池配置使用示例详解》SpringBoot集成@Async注解,支持线程池参数配置(核心数、队列容量、拒绝策略等)及生命周期管理,结合监控与任务装饰器,提升异步处理效率与系统... 目录一、核心特性二、添加依赖三、参数详解四、配置线程池五、应用实践代码说明拒绝策略(Rejected

SQL中如何添加数据(常见方法及示例)

《SQL中如何添加数据(常见方法及示例)》SQL全称为StructuredQueryLanguage,是一种用于管理关系数据库的标准编程语言,下面给大家介绍SQL中如何添加数据,感兴趣的朋友一起看看吧... 目录在mysql中,有多种方法可以添加数据。以下是一些常见的方法及其示例。1. 使用INSERT I

使用Docker构建Python Flask程序的详细教程

《使用Docker构建PythonFlask程序的详细教程》在当今的软件开发领域,容器化技术正变得越来越流行,而Docker无疑是其中的佼佼者,本文我们就来聊聊如何使用Docker构建一个简单的Py... 目录引言一、准备工作二、创建 Flask 应用程序三、创建 dockerfile四、构建 Docker

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具

MySQL 定时新增分区的实现示例

《MySQL定时新增分区的实现示例》本文主要介绍了通过存储过程和定时任务实现MySQL分区的自动创建,解决大数据量下手动维护的繁琐问题,具有一定的参考价值,感兴趣的可以了解一下... mysql创建好分区之后,有时候会需要自动创建分区。比如,一些表数据量非常大,有些数据是热点数据,按照日期分区MululbU

Python函数作用域示例详解

《Python函数作用域示例详解》本文介绍了Python中的LEGB作用域规则,详细解析了变量查找的四个层级,通过具体代码示例,展示了各层级的变量访问规则和特性,对python函数作用域相关知识感兴趣... 目录一、LEGB 规则二、作用域实例2.1 局部作用域(Local)2.2 闭包作用域(Enclos

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C