社区导航

 

搜索
查看: 1789|回复: 7

[经验] 最近重新看了一下SDRAM的编程,有些体会写一下

[复制链接]

2187

TA的帖子

0

TA的资源

裸片初长成(初级)

Rank: 10Rank: 10Rank: 10

荣誉会员勋章

发表于 2018-9-9 00:55 | 显示全部楼层 |阅读模式
之前,有人说过,如果可以单独将SDRAM写出来,基本可以确定算FPGA编程已经是初级水平了。我不讨论这个话到底对不对,但是之前一直觉得SDRAM用FPGA驱起来很难,后来也没有坚持,就放了很长时间。最近有在朋友那儿看到AX309这块板子(我不是做广告,如果有比较关心的,自己晚上搜搜)上相关历程都会涉及到这个东西,所以就想参考别人的历程,将自己的经验写一下。
如果有不对的地方,还请指正。

SDRAM数据手册,网上可以找到的就是镁光和韩国的两个企业所提供的。韩国人提供的材料很简单,我也没时间去他们的官网或者别的途径获取更详细的资料。
所以就看镁光的芯片,因为他们的datasheet相对比较全。
SDRAM一般分为两个阶段,初始化阶段和正常工作阶段。先说初始化阶段,从网上搜到的资料显示初始化过程如下:





根据镁光提供的初始化时序图和上图有两点差异:
1、输入稳定期为100us;
2、第3个状态是2个周期。
具体如下:


先以镁光的时序图为准。
SDRAM有一个时钟范围的要求,外部时钟为50M,通过FPGA内部倍频,可以输出100Mhz的时钟。一个时钟周期为10ns。
在看这个时序图时,有3点应该注意的:
1、状态过程是什么样的。我见到的所有关于Verilog的书上,都会讲到状态机,这个相当于是设计的主心骨,最起码在可综合的设计中是主心骨。
2、对应的控制字的变化,如CMD、DQM、ADDR、BA。他在每个状态不通时钟周期的值是什么。
3、DQ的值。

一般的设计将上面3个点分3个文件实现,这个就会涉及到共同的参数的问题。为了解决这个问题,可以将多个文件中用到的相同参数均编写在一个文件中,然后通过 `include调用这个文件。例如:
parameter                TRP_CLK                = 9'd4,//1,        //TRP=18ns预充电有效周期
                                TRFC_CLK              = 9'd6,//3,        //TRC=60ns自动预刷新周期
                                TMRD_CLK            = 9'd6,//2,        //模式寄存器设置等待时钟周期
                                TRCD_CLK             = 9'd2,//1,        //TRCD=18ns行选通周期



后边的等写的差不多了再续!
此帖出自FPGA/CPLD论坛
2018-09-09_005345.png
2018-09-09_005415.png


回复

使用道具 举报

82

TA的帖子

0

TA的资源

版主

Rank: 6Rank: 6

发表于 2018-9-9 08:53 | 显示全部楼层
感觉不错,帮顶以下


回复

使用道具 举报

2187

TA的帖子

0

TA的资源

裸片初长成(初级)

Rank: 10Rank: 10Rank: 10

荣誉会员勋章

 楼主| 发表于 2018-9-12 00:00 | 显示全部楼层
这两天事情比较多,有些耽误了。
先说一下初始化时,输入稳定期的设置。
使用两个always,一个是系统状态机,一个是计数器。
当使能后,计数器开始计数,当记到10000-1时,状态机从输入稳定态,转到预充电状态。
在这个过程中,控制信号和数据均无动作。


回复

使用道具 举报

2187

TA的帖子

0

TA的资源

裸片初长成(初级)

Rank: 10Rank: 10Rank: 10

荣誉会员勋章

 楼主| 发表于 2018-9-24 00:12 | 显示全部楼层
从时序图上看,初始化分为上电等待、预充电、预充电等待、第一次自刷新、第一次自刷新等待、第二次自刷新、第二次自刷新等待、寄存器设置。
初始化时,设置一个时钟计数器,当自刷新使能有效时,开始计数,到计数状态后,保持。
初始化状态的代码见下文,可能我这个代码编写方式和一般的有差异,但是我这样写仿真没有问题,另外这个是之前在网上买的一个人的开发板推荐的写法,我现在也比较接受。听说是某公司的规定书写方式。大家仁者见仁。
always@(posedge SYSCLK or negedge RST_N) begin
        if(!RST_N)
                        INIT_CNT <= 15'd0;
        else
                        INIT_CNT <= INIT_CNT_F;
end

always@(*) begin
        if(INIT_EN == 1'b0)            //或者系统上电自动开始计数
                        INIT_CNT_F = 15'd0;
        else if(INI_CNT == 15'd19999)
                        INIT_CNT_F = INIT_CNT;
        else
                        INIT_CNT_F = INIT_CNT + 15'd1;
end

然后我们需要一个时钟计数器。因为我们看到时序图中,根据时钟的计数情况切换状态的。
always@(posedge SYSCLK or negedge RST_N) begin
        if(!RST_N)
                        CLK_CNT <= 8'd0;     //数据具体位宽根据进展调节
        else
                        CLK_CNT <= CLK_CNT_F;
end

always@(*) begin
        if(INIT_CS != INIT_NS)        //INIT_CS为目前状态,INIT_NS 为下一个状态   
                        CLK_CNT_F = 8'd0;
        else
                        CLK_CNT_F = CLK_CNT + 8'd1;
end

在看一下状态机的实现:

always @ (*)begin
                case (INIT_CS)
                                `I_NOP:         INIT_NS <= done_200us ? `I_PRE:`I_NOP;                //上电复位后200us结束则进入下一状态
                                `I_PRE:         INIT_NS <= `I_TRP;                //预充电状态
                                `I_TRP:         INIT_NS <= (`end_trp) ? `I_AR1:`I_TRP;                        //预充电等待TRP_CLK个时钟周期
                                `I_AR1:         INIT_NS <= `I_TRF1;        //第1次自刷新
                                `I_TRF1:        INIT_NS <= (`end_trfc) ? `I_AR2:`I_TRF1;                        //等待第1次自刷新结束,TRFC_CLK个时钟周期
                                `I_AR2:         INIT_NS <= `I_TRF2;         //第2次自刷新       
                                `I_TRF2:        INIT_NS <= (`end_trfc) ? `I_MRS:`I_TRF2;                 //等待第2次自刷新结束,TRFC_CLK个时钟周期
                                `I_MRS:                INIT_NS <= `I_TMRD;//模式寄存器设置(MRS)       
                                `I_TMRD:        INIT_NS <= (`end_tmrd) ? `I_DONE:`I_TMRD;                //等待模式寄存器设置完成,TMRD_CLK个时钟周期
                                `I_DONE:        INIT_NS <= `I_DONE;                // SDRAM的初始化设置完成标志
                                default:         INIT_NS <= `I_NOP;
                                endcase                       
end

其中end_trp、end_trfc、end_tmrd就是在上文中提到的单独定义的时钟计数参数。
例如可以这样表达:`define  end_trp = 3;


回复

使用道具 举报

2187

TA的帖子

0

TA的资源

裸片初长成(初级)

Rank: 10Rank: 10Rank: 10

荣誉会员勋章

 楼主| 发表于 2018-9-24 00:12 | 显示全部楼层
初始化就说到这里。不知道有什么纰漏没有,大家一起讨论。


回复

使用道具 举报

2187

TA的帖子

0

TA的资源

裸片初长成(初级)

Rank: 10Rank: 10Rank: 10

荣誉会员勋章

 楼主| 发表于 2018-11-5 09:01 | 显示全部楼层
数据收发部分的这几天就发上来。

sdram_cmd.v

3.74 KB, 下载次数: 2

sdram_ctrl.v

5.91 KB, 下载次数: 2

sdram_para.v

2.24 KB, 下载次数: 2

点评

谢谢分享!  详情 回复 发表于 2020-2-14 14:01


回复

使用道具 举报

23

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2018-11-7 14:51 | 显示全部楼层
赞一个。有时间看看


回复

使用道具 举报

385

TA的帖子

0

TA的资源

一粒金砂(高级)

Rank: 3Rank: 3

发表于 2020-2-14 14:01 | 显示全部楼层
heningbo 发表于 2018-11-5 09:01 数据收发部分的这几天就发上来。

谢谢分享!



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐上一条 1/5 下一条

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2020-3-31 21:02 , Processed in 0.255812 second(s), 19 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表