SDRAM设计之代码设计(四)

SDRAM设计之代码设计(四)

       使用FPGA进行SDRAM的接口设计,首先需要明确我们接口模块的功能,结合之前几篇文章中对SDRAM的基本介绍,将设计功能明确如下:

  • 该接口模块需完成对SDRAM芯片的初始化,模式寄存器设置;
  • 该接口模块需定时完成对SDRAM芯片的刷新操作;
  • 完成最基本的读、写SDRAM的操作;

       根据功能要求可以看出,SDRAM接口设计的几个核心功能就是:

  • 初始化(INIT)
  • 刷新(AUTO_REFRESH)
  • 读(READ)
  • 写(WRTIE)

       首先来说,上述这几个功能是必不可少的,那么就将这几个功能分别封装成一个模块,这样就可以了吗,显然是不行的,首先我们先考虑下,这几个模块之间有没有时序上的冲突在我们要对SDRAM芯片进行读或者是写的时候,很显然的,初始化模块(INIT)是我们在SDRAM芯片上电完成后首先要进行的操作,初始化完成后,需要定时对SDRAM进行刷新(AUTO_REFRESH)操作,剩下的时间,我们才可以进行读、写操作。
       那自然而然的,就会出现这样一些问题:

  • 当处于刷新期间时,我们要进行读写操作,该怎么办;
  • 当我们处于读写期间时,刚好刷新时间到了,该怎么办;

       在这里需要明确是关于读、写操作之间会不会冲突,这个我们可以通过设计避免掉,当我们操作这样一个SDRAM接口的时候,就要保证不要同时发出读、写请求,要等写完才能发出读命令,要等读完才能发出写命令;

       说了这么多,其实还是一头雾水,到底该怎么设计这样一个接口模块呢,先来看下结构框图:
程序结构框图
       我将初始化(INIT)、刷新(AUTO_REFRESH)、读(READ)、写(WRTIE)分别封装成了单个的模块,但是不同的操作只是通过SDRAM芯片相同的一些引脚,不同的高低电平来实现的,所以设计了一个SDRAM_PIN_SEL模块,其实本质就是一个多路选择器,需要进行不同的操作的时候就将对应的模块输出接到SDRAM芯片上。
       还设计了两个FIFO,读FIFO和写FIFO,主要用作速率的匹配,因为SDRAM的突发读写是有固定长度的,比如我们模式寄存器设置成了一次突发写八个16bit的数,但是我们数据的来源可能是固定或者不固定的一个个的进来,这就需要FIFO进行下缓存同步;当然用FIFO也可以更加灵活的进行跨时钟域的数据操作。

       最重要的就是这个CONTRL模块的设计,可以将他理解成一个大脑一样的存在,用于调度各个模块的有序执行,上述的一些问题全靠这个模块来解决,从图中可以看出,这个模块既连接着上级用户,也连接着底层的具体各种操作(是不是感觉到压力巨大)。

       为了实现我们需要的功能,每个模块都输出这样一个信号,STATE状态指示信号,用于表示本模块正处于的状态,比如说,当User_app想进行写操作的时候,这时候先看下SDRAM模块处于什么状态,如果SDRAM接口模块正处于上一次的写状态或者是处于读状态时,便不要马上给出写请求信号,一直到状态指示信号为空闲了,再发送写请求。
       这里要说明的是,作为使用这个SDRAM接口模块的User_app,我当然希望我能够用最简单的控制时序去操作它,所以最初我以一个相对直接的想法去定义的这个SDRAM接口模块的功能,就是说作为User_app我不管你SDRAM接口模块是否在刷新,只要你不处于读状态或者写状态,我都可以给你发送读/写命令;
       那么就造成这样一个问题,对于SDRAM接口模块来说,读写请求是一个异步信号,我不知道啥时候会突然来一个读/写请求,那么这个读/写请求就有可能刚好会落在刷新时间内,这是问题一;
       还有一个问题,那读/写请求落在刷新时间以外就保证没问题了吗,仔细想想,也不会完全没问题,由于刷新的频率是固定的,每隔一定的时间,就固定需要进行一次刷新(也有的设计者可能为了避开读写与刷新的冲突,选择将刷新后延,但作为强迫症的我,延后刷新无疑使我的刷新频率不再“完美”,于是我选择延后读写),而完成一次读/写也是需要一定时间的,就会出现这样的现象,读/写请求来临的的时候,刷新模块的状态指示其并没有在进行刷新,然后我们就开始进行读/写操作,但是还没完成读/写操作呢,要进行刷新了,这就会产生冲突,这便是问题二;

       那么如何解决呢,我选择了后延读/写,User_app给出的是读/写请求(REQ)信号,给到CONTRL模块后,靠这个模块去仲裁,何时给出读/写使能(EN)信号到读/写模块,这样读/写模块只是收读/写使能(EN)信号后就马上开始干活,不用管那些复杂的事,因为这些在CONTRL模块中都已经调度好了。

       以写过程为例,用这样一张时序图来简单的说明一下:
写请求发生在刷新期间
       从图中可以看出,REF_STATE信号指示的就是刷新状态,为低的时候表示处于刷新状态,我们将其之前的T时间也让出来,因为在T时间内完成不了一次读或者写操作(这个时间需要根据突发的模式自己去算),由此我组成了一个新的信号flag_wr,只要我的读/写请求落在了flag_wr为低期间,我们都需要在它拉高之后去给出WR_EN信号。

       以上便是我对于SDRAM这个接口模块的设计架构,以及关键模块调度机制的介绍,我一直认为,一个好的FPGA设计,一定是从架构开始设计,自顶向下,逐级明确各个模块的功能,这样的设计方法或者说思想,可以使自己的思路时刻都清晰,这样才能达到行云流水的状态,减少代码的书写时间,减少仿真阶段和板级测试阶段的重复迭代的过程,我在学习之初便是这样,仿真哪里不对了,改改代码,再仿真,改这里又影响到别处了,再改,最终功能虽然得以实现,但是时间用了不少,程序乱七八糟,各种中间变量,各种标志信号,等我过几天再看,基本自己也理不清了,代码的可维护性大大降低。
       以上便是自己的一些个人理解,也欢迎大家来留言,共同进步,我会将这个模块的代码上传,以供参考和学习。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值