官方论坛
官方淘宝
官方博客
微信公众号
点击联系吴工 点击联系周老师
您的当前位置:主页-old > 新闻中心 > FPGA技术教程 > SDRAM和DDR >

【文章】基于FPGA的SDRAM控制器_初始化设计

发布时间:2021-07-01   作者:小周 浏览量:


本文为明德扬原创及录用文章,转载请注明出处

1.1 SDRAM简介

SDRAM即同步动态随机存储器,英文为Synchronous Dynamic Random Access Memory;具有容量大、读写速度快、价格相对便宜等优点,但同时控制逻辑比较复杂。

 

1.1.1 SDRAM示意图

其管脚图如下所示:

 

1.1.2 信号说明

信号名

信号说明

clk

SDRAM工作时钟

cke

时钟使能信号

cs_n

用于屏蔽和使能所有输入端口,但不包括CLKCKEDQM,低电平有效

cas_n

列地址选通

ras_na

行地址选通

we_n

写使能,该信号为低时,使能写操作和预充电

ba

bank地址

a

地址总线

dqm

数据掩码

dq

数据总线

 

 

1.1.3 SDRAM中心对齐原则

SDRAM的命令与时钟上升沿是中心对齐的,本设计采用锁相环生成SDRAM工作时钟,SDRAM与初始化模块工作时钟相差180°。这样FPGA产生的信号到SDRAM正好中心对齐,如下图所示:

null

 

 

1.1.4 SDRAM初始化时序

null

SDRAM初始化时序如上图所示,sdr_cmd命令由sdr_cs_n, sdr_ras_n, sdr_cas_n, sdr_we_n组合而成;复位后要延时最少100us后才能工作;当A10为高时可以对所有bank进行操作;当到达Tp+3时需要将init_done拉高。

 

 

null

其模式寄存器配置如上图所示,主要参数设置如下:

a.       模式寄存器的配置是确定SDRAM的工作模式

b.       A2A1A0用作设置突发长度,本项目设置为4

c.       A3用作设置突发类型,本项目设置为Sequential顺序类型

d.       A6A5A4用作设置列选通潜伏期,本项目设置为3

e.       A8A7设置操作模式,一般为00

f.        A9设置写突发模式,本项目为0

g.       A12A11A10设置为0

 

1.2 顶层模块设计

1.2.1 SDRAM顶层模块管脚图

null

 

1.2.2 信号说明

 

信号

说明

local_addr

本地地址由行地址列地址bank地址组合而成

local_data

写入数据

local_q

读出数据

local_rdreq

读请求

local_wrreq

写请求

local_reday

可以进行读写信号

local_rdata_valid

读数据有效信号

init_done

初始化完成信号

clk

输入时钟

rst_n

系统复位

sdr_dq

SDRAM数据总线,双向端口

sdr_clk

SDRAM工作时钟

sdr_cke

SDRAM时钟使能

sdr_cs_n

片选信号

sdr_cas_n

列地址选通

sdr_ras_n

行地址选通

sdr_we_n

写使能,该信号为低时,使能写操作和预充电

sdr_ba

SDRAM bank地址

sdr_a

SDRAM地址总线

sdr_dqm

数据掩码

 

1.2.3 参考代码

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

module sdram_top(

    clk    ,

    sys_rst_n  ,

    //其他信号,举例dout

    local_addr,

    local_data,

    local_q,

    local_rdreq,

    local_wrreq,

    local_reday,

    local_rdata_vaild,

    init_done,

    sdr_cke,

    sdr_cs_n,

    sdr_ras_n,

    sdr_cas_n,

    sdr_we_n,

    sdr_ba,

    sdr_a,

    sdr_dq,

    sdr_dqm,

    sdr_clk

    );

       

         input clk;

         input sys_rst_n;

         input [24:0] local_addr;

         input [63:0] local_data;

         output [63:0] local_q;

         input local_rdreq;

         input local_wrreq;

         output local_reday;

         output local_rdata_vaild;

         output init_done;

         output sdr_cke;

         output sdr_cs_n;

         output sdr_ras_n;

         output sdr_cas_n;

         output sdr_we_n;

         output [1:0] sdr_ba;

         output [12:0] sdr_a;

         output [15:0] sdr_dq;

         output [1:0] sdr_dqm;

         output sdr_clk;

       

         wire phy_clk;

         wire rst_n;

         wire [19:0] init_bus;

       

         assign {sdr_cke, sdr_cs_n, sdr_ras_n, sdr_cas_n, sdr_we_n, sdr_ba, sdr_a} = init_bus;

         assign sdr_dqm = 2'b00;

                

    sdram_init sdram_init_inst(

        .clk            (phy_clk)       ,

        .rst_n          (rst_n)       ,

        //其他信号,举例dout

        .init_done      (init_done)       ,

        .init_bus       (init_bus)

    );

       

                 my_pll PLL(

                         .areset             (~sys_rst_n)            ,

                         .inclk0              (clk)                          ,

                         .c0                    (phy_clk)                  ,

                         .c1                    (sdr_clk)                   ,

                         .locked             (rst_n)

                 );

 

    endmodule

 

 

 

1.3 初始化模块设计

1.3.1 SDRAM出计划模块管脚图

 

null

 

1.3.2 信号说明

 

信号

说明

clk

初始化模块工作时钟(100MHz

rst_n

复位

init_done

初始化完成信号

init_bus

SDRAM信号组成

 

 

1.3.3 参考代码

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

module sdram_init(

    clk    ,

    rst_n  ,

    //其他信号,举例dout

    init_done,

    init_bus

    );

 

    //参数定义

    parameter      DATA_W    =      20      ;

    parameter      T100us    =      10_000  ;

    parameter      TRP       =      2       ;

    parameter      TRFC      =      7       ;

    parameter      TMRD      =      2       ;

        parameter      NOP       =      4'b0111       ;

        parameter      PRE       =      4'b0010       ;

        parameter      REF       =      4'b0001       ;

        parameter      LMR       =      4'b0000       ;

        parameter      CODE      =      13'b000_000_011_0010       ;

        parameter      CNT_MAX   =      10_021    ;

 

    //输入信号定义

    input               clk    ;

    input               rst_n  ;

 

    //输出信号定义

    output              init_done  ;

    output[DATA_W-1:0]  init_bus   ;

 

    //输出信号reg定义

    reg                 init_done  ;

    wire  [DATA_W-1:0]  init_bus   ;

 

    //中间信号定义

    reg   [20:0]        cnt        ;

    reg                 sdr_cke    ;

    reg   [3:0]         sdr_cmd    ;

    reg   [1:0]         sdr_ba     ;

    reg   [12:0]        sdr_a      ;

       

        wire                                           add_cnt           ;

        wire                                         end_cnt           ;

 

    assign init_bus = {sdr_cke, sdr_cmd, sdr_ba, sdr_a};

 

    always @(posedge clk or negedge rst_n)begin

        if(!rst_n)begin

            cnt <= 0;

        end

        else if(add_cnt)begin

            if(end_cnt)

                cnt <= 0;

            else

                cnt <= cnt + 1;

        end

    end

 

    assign add_cnt = init_done == 0;      

    assign end_cnt = add_cnt && cnt==CNT_MAX - 1 ;

 

        always @(posedge clk or negedge rst_n)begin

                 if(rst_n==1'b0)begin

                         sdr_cke <= 1'b0;

                 end

                 else if(add_cnt&&cnt==10_000-1)begin

                         sdr_cke <= 1'b1;

                 end

                 else

                         sdr_cke <= sdr_cke;

        end

       

        always @(posedge clk or negedge rst_n)begin

                 if(rst_n==1'b0)begin

                         sdr_cmd <= NOP;

                 end

                 else if(add_cnt&&cnt==10_001-1)begin

                         sdr_cmd <= PRE;

                 end

                 else if(add_cnt&&cnt==10_003-1)begin

                         sdr_cmd <= REF;

                 end

                 else if(add_cnt&&cnt==10_012-1)begin

                         sdr_cmd <= REF;

                 end

                 else if(add_cnt&&cnt==10_019-1)begin

                         sdr_cmd <= LMR;

                 end

                 else if(add_cnt&&cnt==10_020-1)begin

                         sdr_cmd <= NOP;

                 end

                 else begin

                         sdr_cmd <= NOP;

                 end

        end

       

        always @(posedge clk or negedge rst_n)begin

                 if(rst_n==1'b0)begin

                         sdr_a <= 13'd0;

                 end

                 else if(add_cnt&&cnt==10_001-1)begin

                         sdr_a[10] <= 1'b1;

                 end

                 else if(add_cnt&&cnt==10_019-1)begin

                         sdr_a <= CODE;

                 end

                 else begin

                         sdr_a <= 13'd0;

                 end

        end

                

        always @(posedge clk or negedge rst_n)begin

                 if(rst_n==1'b0)begin

                         init_done <= 1'b0;

                 end

                 else if(add_cnt&&cnt==10_021-1)begin

                         init_done <= 1'b1;

                 end

                else begin

                         init_done <= init_done;

                 end

        end

       

endmodule

 

 

1.4 PLL设置   

最后对代码进行仿真,modelsim生成的报告如下所示,说明初始化设置成功。

null

 

null

 

 

以上就是SDRAM控制器初始化设计的思考步骤以及相关代码,更多FPGA资料可以进入明德扬论坛进行学习交流(http://www.fpgabbs.cn/),明德扬专注FPGA设计研究,对FPGA学习感兴趣的朋友快快联系我们吧!

   拓展阅读