• SDRAM学习笔记(MT48LC16M16A2,w9812g6kh)


    一、基本知识

    SDRAM : 即同步动态随机存储器(Synchronous Dynamic Random Access Memory), 同步是指其时钟频率与对应控制器(CPU/FPGA)的系统时钟频率相同,并且内部命令 的发送与数据传输都是以该时钟为基准;动态是指存储阵列需要不断的刷新来保证数据不丢失;随机指数据的读取和写入可以随机指定地址,而不是必须按照严格的线性次序变化。

    SDRAM 使用电容的电荷存储特性存储数据,而 SRAM使用CMOS晶体管存储数据,这决定了SDRAM的运行功耗要远远低于SRAM。由于使用晶体管存储数据,要能够正确的存储一位数据,需要最少6个晶体管。因此,从芯片面积上来说,单片SRAM芯片的容量不可能做到很高。

    通常情况下,SDRAM 是拥有四个 BANK 的动态刷新存储器,存储器工作在 3.3V 的电 压下,拥有一个同步接口,SDRAM 的所有信号都在时钟信号的上升沿被寄存。对于 SDRAM 的读写是以突发的方式进行的,对 sdram 的获取(读或者写)是从一个指定的地址开始,并按照编程好的数量(长度)的地址,以编程好的数据顺序读写数据。

    教程:

    SDR SDRAM: SDRAM设计教程之SDRAM结构深入剖析 altera (b站小梅哥教程)

    DDR:小梅哥Xilinx ACX720 FPGA开发板自学教程V2.2.4 xilinx

    DDR2:小梅哥DDR2简明教程V1.1  altera (b站小梅哥教程)

    DDR3:blibli-小梅哥Xilinx FPGA基础入门到项目应用培训教程 xilinx

    存取原理:先通过行地址打开行地址线,后通过列地址线打开列地址,便实现把电容与数据线连通,实现读/写操作。

       打开行地址需要tRCD时间,后才能打开列地址。tRCD可查手册,计算需要多少个对应频率的时钟的延迟,进行设计。

       打开列地址后,如果是读操作,需要CL(CAS READ LATENCY)个时钟周期才会出数据,如果是写操作,则数据需要同时送出,不用CL。

      不同型号的sdram:命令、时序参数有区别

    二、型号MT48LC16M16A2的sdram

    引脚:

    对于sdram的控制,通过CS_N、RAS_N、CAS_N、WE_N四个引脚来控制,故记这四个引脚组成的状态为控制命令cmd。

    通过这个表来设置cmd。

    1.时序设计

    控制sdram只需要结合时序图和命令表,通过线性序列机和状态机来设计就可以。

    1.上电初始化:通过计数器使sdram处于nop状态 不少于100us后,发出一个precharge命令,经过tRP时间(一直处于nop,下同),发出一个autorefresh命令,经过tRFC时间,再autorefresh一次,经过tRFC时间,便可发出load mode register命令配置模式寄存器。

    通常都需要通过配置模式寄存器来设计突发类型(Burst type:即有两种模式);突发长度(burst length:即每次读或写的数据长度),输出周期间隔(CAS:即发出命令后经过几个周期开始出数据)具体模式如下图解释:

    模式寄存器设置规则如下:

    2.读/写命令:

           器件手册给出了包括读/写在内的多种命令的时序图,根据时序图进行设计即可,比如常用的:

    2.代码设计

           类似IIC协议和SPI协议,依旧是状态机加线性序列机的形式来是实现。最底层用状态机实现每种状态需要的操作,中间层用线性序列机实现一个完整的读/写/其他操作需要经过几种状态的跳转。故先定义状态和命令cmd。

           注意,设计时仍然需要注意时钟问题,给sdram的时钟是在上升沿读取数据,所以输出的数据在上升沿应该是稳定的,具体可以通过设计与读写两个时钟的移相来实现。

    1. module sdram_driver(
    2. input clk ,
    3. input rst_n ,
    4. input write_sig ,
    5. input read_sig ,
    6. input initial_sig ,
    7. input [12:0]write_addr ,
    8. input [1:0]write_bank ,
    9. input [12:0]read_addr ,
    10. input [1:0]read_bank ,
    11. output reg [3:0]cmd ,
    12. output reg [1:0]bank ,
    13. output reg [12:0]addr ,
    14. output reg [11:0]mode ,
    15. output reg cke_ctrl ,
    16. output reg [1:0]dqm_ctrl ,
    17. output reg initial_done ,
    18. output reg [15:0]read_data ,
    19. output reg trans_done ,
    20. inout [15:0]DQ
    21. );
    22. //状态参数
    23. localparam nop1 = 4'b1000 ; //空闲态:禁止命令
    24. localparam nop2 = 4'b0111 ; //空闲态:空命令
    25. localparam active = 4'b0011 ; //选bank与行
    26. localparam read = 4'b0101 ; //选bank和列,启动突发读 ,最后一位为屏蔽位
    27. localparam write = 4'b0100 ; //选bank和列,启动突发读 ,最后一位为屏蔽位
    28. localparam burst_terminate = 4'b0110 ; //突发中止
    29. localparam precharge = 4'b0010 ; //关闭行,预充电
    30. localparam refresh = 4'b0001 ; //刷新
    31. localparam load_mode_register = 4'b0000 ; //a0 - a11 tmrd
    32. // mode register
    33. localparam M9_BL_mode = 1'b0 ; //length
    34. localparam M9_SL_mode = 1'b1 ; //single
    35. localparam M87_SO_mode = 2'b00 ;
    36. localparam M654_CAS_2 = 3'b010 ;//CL
    37. localparam M654_CAS_3 = 3'b011 ;//CL
    38. localparam M3_seq = 1'b0 ;
    39. localparam M3_intl = 1'b1 ;
    40. localparam M210_BL_1 = 3'b000 ;//be able to replace single read/write (M9)
    41. localparam M210_BL_2 = 3'b001 ;
    42. localparam M210_BL_4 = 3'b010 ;
    43. localparam M210_BL_8 = 3'b011 ;
    44. localparam M210_BL_full = 3'b111 ;
    45. // read with auto precharge ?
    46. localparam auto_precharge = 1 ;
    47. wire rd_with_auto , wr_with_auto ;
    48. assign rd_with_auto = auto_precharge ;
    49. assign wr_with_auto = auto_precharge ;
    50. reg [15:0]cmd_cnt ;
    51. always@( posedge clk or negedge rst_n )
    52. if(!rst_n)
    53. begin
    54. cmd_cnt <= 0 ;
    55. cmd <= nop2 ;
    56. bank <= 0 ;
    57. addr <= 0 ;
    58. mode <= 0 ;
    59. cke_ctrl <= 0 ;
    60. dqm_ctrl <= 0 ;
    61. trans_done <= 0 ;
    62. initial_done<= 0 ;
    63. read_data <= 0 ;
    64. end
    65. else if(initial_sig)
    66. begin
    67. cmd_cnt <= cmd_cnt + 1 ;
    68. case(cmd_cnt)
    69. 1:cmd <= nop2 ;//delay > 100 us
    70. 10005: begin cke_ctrl <= 1 ; end
    71. 10010: begin cmd <= precharge ; addr[10] = 1 ; end //precharge all banks : tRP >= 20ns (2T)
    72. 10011: begin cmd <= nop2 ; end
    73. 10015: begin cmd <= refresh ; cke_ctrl <= 1 ; end //auto refresh : >= 2T(RFC) ; T(RFC) >= 66ns 1T(auto)(256Mb) = 8192
    74. 10016: begin cmd <= nop2 ; end
    75. 10026: begin cmd <= refresh ; cke_ctrl <= 1 ; end //
    76. 10027: begin cmd <= nop2 ; end //
    77. 10040: begin cmd <= load_mode_register ; bank <= 0 ; mode <= { 2'b00 , M9_BL_mode , M87_SO_mode , M654_CAS_3 , M3_seq , M210_BL_4 } ;end //set mode :t(mrd) = 2t(ck) = 2*6 = 12 ns
    78. 10041: begin cmd <= nop2 ; end
    79. 10045: begin initial_done <= 1 ; end
    80. 10046: begin cmd_cnt <= 0 ; end
    81. default:cmd <= nop2 ;
    82. endcase
    83. end
    84. else if(initial_done)
    85. begin
    86. if(write_sig)
    87. begin
    88. if(wr_with_auto)
    89. begin
    90. cmd_cnt <= cmd_cnt + 1 ;
    91. case(cmd_cnt)
    92. 1:begin cmd <= active ; bank <= write_bank ; addr <= write_addr ; end
    93. 4:begin cmd <= write ; bank <= write_bank ; addr <= {write_addr[12:11],1'b1,write_addr[9:0]}; end
    94. 10:begin trans_done <= 1 ; cmd_cnt <= 0 ;end
    95. default:cmd<=nop2;
    96. endcase
    97. end
    98. else if(~wr_with_auto)
    99. begin
    100. cmd_cnt <= cmd_cnt + 1 ;
    101. case(cmd_cnt)
    102. 1:begin cmd <= active ; bank <= write_bank ; addr <= write_addr ; end
    103. 4:begin cmd <= write ; bank <= write_bank ; addr <= {write_addr[12:11],1'b1,write_addr[9:0]}; end
    104. 9:begin cmd <= precharge ; addr[10] = 1 ;end
    105. 12:begin trans_done <= 1 ; cmd_cnt <= 0 ;end
    106. default:cmd<=nop2;
    107. endcase
    108. end
    109. end
    110. else if(read_sig)
    111. begin
    112. if( rd_with_auto )
    113. begin
    114. cmd_cnt <= cmd_cnt + 1 ;
    115. case(cmd_cnt)
    116. 1:begin cmd <= active ; bank <= read_bank ; addr <= read_addr ; end
    117. 4:begin cmd <= read ; bank <= read_bank ; addr <= {read_addr[12:11],1'b1,read_addr[9:0]}; end //addr10 control auto charge
    118. 9:begin read_data <= DQ ; end
    119. 10:begin read_data <= DQ ; end
    120. 11:begin read_data <= DQ ; end
    121. 12:begin read_data <= DQ ; end
    122. 13:begin trans_done<= 1 ; cmd_cnt <= 0 ; end
    123. default:begin cmd <= nop2 ;read_data <= DQ ;end
    124. endcase
    125. end
    126. else if( ~rd_with_auto )
    127. begin
    128. cmd_cnt <= cmd_cnt + 1 ;
    129. case(cmd_cnt)
    130. 1:begin cmd <= active ; bank <= read_bank ; addr <= read_addr ; end
    131. 4:begin cmd <= read ; bank <= read_bank ; addr <= {read_addr[12:11],1'b0,read_addr[9:0]}; end //addr10: control auto charge
    132. 9:begin read_data <= DQ ; end
    133. 10:begin read_data <= DQ ; end
    134. 11:begin read_data <= DQ ; cmd <= precharge ; addr[10] = 1 ; end //precharge
    135. 12:begin read_data <= DQ ; end
    136. 14:begin trans_done<= 1 ; cmd_cnt <= 0 ; end
    137. default:cmd <= nop2 ;
    138. endcase
    139. end
    140. end
    141. else
    142. begin
    143. cmd <= nop2 ;
    144. cmd_cnt <= 0 ;
    145. trans_done<= 0 ;
    146. end
    147. end
    148. else
    149. begin
    150. cmd_cnt <= 0 ;
    151. end
    152. endmodule
    1. //-75 100MHz CL = 2 setup = 1.5 hold = 0.8 上升沿读写数据//
    2. // 100MHz : T = 10ns //
    3. // tRP >= 20ns ; T(RFC) >= 66ns ; t(mrd) = 12 ns
    4. // 这里实现 普通的写和读 ;有特殊要求的根据手册进行cmd修改即可
    5. module sdram_ctrl(
    6. input fpga_clk ,
    7. input rst_n ,
    8. input write_sig ,
    9. input read_sig ,
    10. input [12:0]write_addr ,
    11. input [1:0]write_bank ,
    12. input [15:0]write_data ,
    13. input [12:0]read_addr ,
    14. input [1:0]read_bank ,
    15. output trans_done ,
    16. output [15:0]read_data ,
    17. output sclk ,
    18. output CKE ,
    19. output CS_N ,
    20. output RAS_N ,
    21. output CAS_N ,
    22. output WE_N ,
    23. output [1:0]DQM ,//高电平时屏蔽
    24. output [12:0]SA ,//A12 - A0
    25. output [1:0]BA ,
    26. inout [15:0]DQ
    27. );
    28. wire clk_100m;
    29. wire clk_100m_90shift ;
    30. pll pll_inst(
    31. .inclk0(fpga_clk),
    32. .c0(clk_100m),
    33. .c1(clk_100m_90shift)
    34. );
    35. assign sclk = clk_100m_90shift ;
    36. //read / write signal catch
    37. reg write_sig_reg ;
    38. always@(posedge fpga_clk or negedge rst_n)
    39. if(!rst_n)
    40. write_sig_reg <= 0 ;
    41. else
    42. write_sig_reg <= write_sig ;
    43. reg read_sig_reg ;
    44. always@(posedge fpga_clk or negedge rst_n)
    45. if(!rst_n)
    46. read_sig_reg <= 0 ;
    47. else
    48. read_sig_reg <= read_sig ;
    49. reg write_signal ;
    50. reg read_signal ;
    51. always@(posedge fpga_clk or negedge rst_n)
    52. if(!rst_n)
    53. write_signal <= 0 ;
    54. else if( write_sig & (!write_sig_reg ) )
    55. write_signal <= 1 ;
    56. else if(trans_done)
    57. write_signal <= 0 ;
    58. always@(posedge fpga_clk or negedge rst_n)
    59. if(!rst_n)
    60. read_signal <= 0 ;
    61. else if( read_sig & (!read_sig_reg ) )
    62. read_signal <= 1 ;
    63. else if(trans_done)
    64. read_signal <= 0 ;
    65. // initial sdram
    66. reg [5:0]initial_cnt ;
    67. wire initial_done ;
    68. always@(posedge clk_100m or negedge rst_n)
    69. if(!rst_n)
    70. initial_cnt <= 0 ;
    71. else if( initial_cnt < 50 )
    72. initial_cnt <= initial_cnt + 1 ;
    73. else
    74. initial_cnt <= initial_cnt ;
    75. reg initial_sig ;
    76. always@(posedge clk_100m or negedge rst_n)
    77. if(!rst_n)
    78. initial_sig <= 0 ;
    79. else if(initial_cnt == 48)
    80. initial_sig <= 1 ;
    81. else if(initial_done)
    82. initial_sig <= 0 ;
    83. wire [3:0]cmd ;
    84. wire [1:0]bank ;
    85. wire [12:0]addr ;
    86. wire [11:0]mode ;
    87. wire cke_ctrl ;
    88. wire [1:0]dqm_ctrl ;
    89. sdram_driver sdram_driver_inst(
    90. .clk(clk_100m) ,
    91. .rst_n(rst_n) ,
    92. .write_sig(write_signal) ,
    93. .read_sig(read_signal) ,
    94. .initial_sig(initial_sig),
    95. .write_addr(write_addr) ,
    96. .write_bank(write_bank) ,
    97. .read_addr(read_addr) ,
    98. .read_bank(read_bank) ,
    99. .cmd(cmd) ,
    100. .bank(bank) ,
    101. .addr(addr) ,
    102. .mode(mode) ,
    103. .cke_ctrl(cke_ctrl) ,
    104. .dqm_ctrl(dqm_ctrl) ,
    105. .initial_done(initial_done),
    106. .read_data(read_data) ,
    107. .trans_done(trans_done) ,
    108. .DQ(DQ)
    109. );
    110. sdram_underlying_logic sdram_underlying_logic_inst(
    111. .clk(clk_100m) ,
    112. .rst_n(rst_n) ,
    113. .mode(mode),//A11 -A0
    114. .cmd(cmd) ,
    115. .cke_ctrl(cke_ctrl) ,
    116. .bank(bank) ,
    117. .addr(addr) ,
    118. .write_data(write_data) ,
    119. .dqm_ctrl(dqm_ctrl),
    120. .CKE(CKE) ,
    121. .CS_N(CS_N) ,
    122. .RAS_N(RAS_N) ,
    123. .CAS_N(CAS_N) ,
    124. .WE_N(WE_N) ,
    125. .DQM(DQM) ,//高电平时屏蔽
    126. .SA(SA) ,//A12 - A0
    127. .BA(BA) ,
    128. .DQ(DQ)
    129. );
    130. endmodule
    1. module sdram_underlying_logic(
    2. input clk ,
    3. input rst_n ,
    4. input [11:0]mode,//A11 -A0
    5. input [3:0]cmd ,
    6. input cke_ctrl ,
    7. input [1:0]bank ,
    8. input [12:0]addr ,
    9. input [15:0]write_data ,
    10. input [1:0]dqm_ctrl,
    11. output reg CKE ,
    12. output reg CS_N ,
    13. output reg RAS_N ,
    14. output reg CAS_N ,
    15. output reg WE_N ,
    16. output reg[1:0]DQM ,//高电平时屏蔽
    17. output reg[12:0]SA ,//A12 - A0
    18. output reg [1:0]BA ,
    19. inout [15:0]DQ
    20. );
    21. reg DQ_ctrl ;
    22. reg [15:0]DQ_out ;
    23. assign DQ = (DQ_ctrl ? DQ_out : 16'hzzzz) ;///
    24. //状态参数
    25. localparam nop1 = 10'b1000000000 ; //空闲态:禁止命令
    26. localparam nop2 = 10'b0100000000 ; //空闲态:空命令
    27. localparam active = 10'b0010000000 ; //选bank与行
    28. localparam read = 10'b0001000000 ; //选bank和列,启动突发读 ,最后一位为屏蔽位
    29. localparam write = 10'b0000100000 ; //选bank和列,启动突发读 ,最后一位为屏蔽位
    30. localparam burst_terminate = 10'b0000010000 ; //突发中止
    31. localparam precharge = 10'b0000001000 ; //关闭行,预充电
    32. localparam auto_refresh = 10'b0000000100 ; //自动刷新
    33. localparam self_refresh = 10'b0000000010 ; //自刷新
    34. localparam load_mode_register = 10'b0000000001 ; //加载模式寄存器
    35. reg [9:0]state ;//状态机
    36. always@(posedge clk or negedge rst_n)
    37. if(!rst_n)
    38. state <= nop2 ;
    39. else if( cmd[3] )
    40. state <= nop1 ;
    41. else if( cmd == 4'b0111 )
    42. state <= nop2 ;
    43. else if( cmd == 4'b0011 )
    44. state <= active ;
    45. else if( cmd == 4'b0101 )
    46. state <= read ;
    47. else if( cmd == 4'b0100 )
    48. state <= write ;
    49. else if( cmd == 4'b0110 )
    50. state <= burst_terminate ;
    51. else if( cmd == 4'b0010 )
    52. state <= precharge ;
    53. else if( cmd == 4'b0001 )
    54. begin
    55. if(cke_ctrl)
    56. state <= auto_refresh ;
    57. else
    58. state <= self_refresh ;
    59. end
    60. else if( cmd == 4'b0000 )
    61. state <= load_mode_register ;
    62. reg [7:0]state_cnt ;
    63. always@(posedge clk or negedge rst_n)
    64. if(!rst_n)
    65. begin
    66. state_cnt <= 0 ;
    67. CKE <= 1 ;
    68. CS_N <= 1 ;
    69. RAS_N <= 1 ;
    70. CAS_N <= 1 ;
    71. WE_N <= 1 ;
    72. BA <= 0 ;
    73. SA <= 0 ;
    74. DQM <= 0 ;
    75. DQ_ctrl <= 1 ;//获取数据线的控制权
    76. DQ_out <= 0 ;
    77. end
    78. else
    79. begin
    80. case(state)
    81. nop1 : begin CS_N <= 1 ; end
    82. nop2 : begin CS_N <= 0 ; RAS_N <= 1 ; CAS_N <= 1 ; WE_N <= 1 ; DQ_out <= write_data ;end
    83. active: begin CS_N <= 0 ; RAS_N <= 0 ; CAS_N <= 1 ; WE_N <= 1 ; SA <= addr ; BA <= bank ;end
    84. read : begin CS_N <= 0 ; RAS_N <= 1 ; CAS_N <= 0 ; WE_N <= 1 ; SA <= addr ; BA <= bank ; DQM <= dqm_ctrl ; DQ_ctrl <= 0 ; end
    85. write : begin CS_N <= 0 ; RAS_N <= 1 ; CAS_N <= 0 ; WE_N <= 0 ; SA <= addr ; BA <= bank ; DQM <= dqm_ctrl ; DQ_out <= write_data ;end
    86. precharge : begin CS_N <= 0 ; RAS_N <= 0 ; CAS_N <= 1 ; WE_N <= 0 ; SA[10] <= addr[10] ; BA <= bank ;DQ_ctrl <= 1 ; end//sa[10] = 1 :对所有bank预充电 ; sa[10] = 0 : 对ba1 ba0 选中的bank预充电
    87. auto_refresh : begin CS_N <= 0 ; RAS_N <= 0 ; CAS_N <= 0 ; WE_N <= 1 ; CKE <= 1 ; end
    88. self_refresh : begin CS_N <= 0 ; RAS_N <= 0 ; CAS_N <= 0 ; WE_N <= 1 ; CKE <= 0 ; end
    89. load_mode_register : begin CS_N <= 0 ; RAS_N <= 0 ; CAS_N <= 0 ; WE_N <= 0 ; SA <= { 1'b0 , mode } ; end
    90. default:;
    91. endcase
    92. end
    93. endmodule
    1. `timescale 1ns/1ns
    2. module sdram_ctrl_tb();
    3. reg fpga_clk ;
    4. reg rst_n ;
    5. reg write_sig ;
    6. reg read_sig ;
    7. reg [12:0]write_addr ;
    8. reg [1:0] write_bank ;
    9. reg [15:0]write_data ;
    10. reg [12:0]read_addr ;
    11. reg [1:0] read_bank ;
    12. wire sclk ;
    13. wire CKE ;
    14. wire CS_N ;
    15. wire RAS_N ;
    16. wire CAS_N ;
    17. wire WE_N ;
    18. wire [1:0]DQM ;//高电平时屏蔽
    19. wire [12:0]SA ;//A12 - A0
    20. wire [1:0]BA ;
    21. wire [15:0]DQ;
    22. wire [15:0]read_data;
    23. wire trans_done;
    24. wire [3:0]cmd_state ;
    25. sdram_ctrl sdram_ctrl_inst(
    26. .fpga_clk(fpga_clk) ,
    27. .rst_n(rst_n) ,
    28. .write_sig(write_sig) ,
    29. .read_sig(read_sig) ,
    30. .write_addr(write_addr) ,
    31. .write_bank(write_bank) ,
    32. .write_data(write_data) ,
    33. .read_addr(read_addr) ,
    34. .read_bank(read_bank) ,
    35. .trans_done(trans_done) ,
    36. .read_data(read_data) ,
    37. .sclk(sclk) ,
    38. .CKE(CKE) ,
    39. .CS_N(CS_N) ,
    40. .RAS_N(RAS_N) ,
    41. .CAS_N(CAS_N) ,
    42. .WE_N(WE_N) ,
    43. .DQM(DQM) ,
    44. .SA(SA) ,
    45. .BA(BA) ,
    46. .DQ(DQ)
    47. );
    48. mt48lc16m16a2 mt48lc16m16a2_inst(
    49. .Dq(DQ),
    50. .Addr(SA),
    51. .Ba(BA),
    52. .Clk(sclk),
    53. .Cke(CKE),
    54. .Cs_n(CS_N),
    55. .Ras_n(RAS_N),
    56. .Cas_n(CAS_N),
    57. .We_n(WE_N),
    58. .Dqm(DQM)
    59. );
    60. pulldown(DQ[15]);
    61. pulldown(DQ[14]);
    62. pulldown(DQ[13]);
    63. pulldown(DQ[12]);
    64. pulldown(DQ[11]);
    65. pulldown(DQ[10]);
    66. pulldown(DQ[9]);
    67. pulldown(DQ[8]);
    68. pulldown(DQ[7]);
    69. pulldown(DQ[6]);
    70. pulldown(DQ[5]);
    71. pulldown(DQ[4]);
    72. pulldown(DQ[3]);
    73. pulldown(DQ[2]);
    74. pulldown(DQ[1]);
    75. pulldown(DQ[0]);
    76. assign cmd_state = {CS_N,RAS_N,CAS_N,WE_N} ;
    77. initial fpga_clk = 0 ;
    78. always #10 fpga_clk = !fpga_clk ;
    79. initial begin
    80. rst_n = 0 ;
    81. write_sig = 0 ;
    82. read_sig = 0 ;
    83. write_addr = 0 ;
    84. write_bank = 0 ;
    85. write_data = 0 ;
    86. read_addr = 0 ;
    87. read_bank = 0 ;
    88. #201 ;
    89. rst_n = 1 ;
    90. #102000;
    91. #200 ;
    92. write_addr = 13'd2 ;
    93. write_bank = 2'd1;
    94. write_data = 16'h5a5a ;
    95. write_sig = 1;
    96. #70;
    97. write_data = 16'h5a5b ;
    98. #10;
    99. write_data = 16'h5a5c ;
    100. #10;
    101. write_data = 16'h5a5d ;
    102. #200 ;
    103. write_sig = 0;
    104. #5000;
    105. read_addr = 13'd2 ;
    106. read_bank = 2'd1;
    107. read_sig = 1 ;
    108. #200 ;
    109. read_sig = 0 ;
    110. #10000;
    111. $stop ;
    112. end
    113. endmodule

    3.仿真

    1.上点初始化

    2.写数据(带自动预充电)

    3.读数据(带自动预充电)

    读出来的数据,DQ的最后一个数据只有7.6ns,不知道是什么原因。

    但是移相适当仍然可以读取。

    接下来对AC609板载的SDRAM:w9812g6kh进行设计,并进行板级验证。

    三、型号w9812g6kh的sdram

            通过查看w9812g6kh芯片的器件手册,发现它的读/写/充电/等命令设置均与MT48LC16M16A2的规则相同,只是这两个芯片容量不一样,w9812g6kh为128M,只有12个地址引脚,而MT48LC16M16A2为256M,有13个地址引脚。所以程序上只需要修改地址引脚即可。

            为了上板验证程序的可行性,仿照IIC协议的测试方法,用uart-sdram联合测试,通过上位机发送读写数据来控制FPGA对w9812g6kh进行读写,此处仍需要建立通信帧,规则与IIC协议笔记差不多,如下:

    //***************** ******************//
    //        串口波特率:115200           //
    //            通信帧格式:             //
    //      AA AA HA LA RW DA DA 55      //
    //    其中,AA AA 为帧头;55为帧尾;   //
    //   HA、LA为存储器地址  //
    //   RW为读写控制,读:5A ;写:A5      //
    //   DA为要写入的数据,读的时候可为任意值 //
    // ********************************* //

    sdram的控制程序设置为BL=1的模式,(使用其他BL只需修改对应的线性序列机和模式寄存器即可)

    1.代码设计

    1. //***************** ******************//
    2. // 串口波特率:115200 //
    3. // 通信帧格式: //
    4. // AA AA HA LA RW DA DA 55 //
    5. // 其中,AA AA 为帧头;55为帧尾; //
    6. // HA、LA为存储器地址 //
    7. // RW为读写控制,读:5A ;写:A5 //
    8. // DA为要写入的数据,读的时候可为任意值 //
    9. // ********************************* //
    10. module uart_sdram(
    11. input fpga_clk ,
    12. input rst_n ,
    13. input uart_rx ,
    14. output rx_done ,
    15. output uart_tx ,
    16. output sclk ,
    17. output CKE ,
    18. output CS_N ,
    19. output RAS_N ,
    20. output CAS_N ,
    21. output WE_N ,
    22. output [1:0]DQM ,//高电平时屏蔽
    23. output [11:0]SA ,//A12 - A0
    24. output [1:0]BA ,
    25. inout [15:0]DQ
    26. );
    27. //receive uart data
    28. //wire rx_done ;
    29. wire [7:0]rx_data ;
    30. uart_receive uart_rec_inst(
    31. .clk(fpga_clk) ,
    32. .reset(rst_n) ,
    33. .baud_rate('d5) ,//115200
    34. .uart_rx(uart_rx),
    35. .data(rx_data) ,
    36. .rx_done(rx_done)
    37. );
    38. //Shift register
    39. reg [7:0]rec_shift_reg[7:0] ;
    40. reg rw_flag ;
    41. wire trans_done ;
    42. always@(posedge fpga_clk or negedge rst_n)
    43. if(!rst_n)
    44. begin
    45. rec_shift_reg[0] <= 0 ;
    46. rec_shift_reg[1] <= 0 ;
    47. rec_shift_reg[2] <= 0 ;
    48. rec_shift_reg[3] <= 0 ;
    49. rec_shift_reg[4] <= 0 ;
    50. rec_shift_reg[5] <= 0 ;
    51. rec_shift_reg[6] <= 0 ;
    52. rec_shift_reg[7] <= 0 ;
    53. rw_flag <= 0 ;
    54. end
    55. else if(rx_done)
    56. begin
    57. rec_shift_reg[0] <= rec_shift_reg[1] ;
    58. rec_shift_reg[1] <= rec_shift_reg[2] ;
    59. rec_shift_reg[2] <= rec_shift_reg[3] ;
    60. rec_shift_reg[3] <= rec_shift_reg[4] ;
    61. rec_shift_reg[4] <= rec_shift_reg[5] ;
    62. rec_shift_reg[5] <= rec_shift_reg[6] ;
    63. rec_shift_reg[6] <= rec_shift_reg[7] ;
    64. rec_shift_reg[7] <= rx_data ;
    65. rw_flag <= 1 ;
    66. end
    67. else if(trans_done)
    68. rw_flag <= 0 ;
    69. reg [15:0]write_addr ;
    70. reg [15:0]read_addr ;
    71. reg [15:0]write_data ;
    72. reg [15:0]read_data ;
    73. wire [15:0]rd_data ;
    74. reg write_pulse ;
    75. reg read_pulse ;
    76. sdram_ctrl sdram_ctrl_inst(
    77. .fpga_clk(fpga_clk) ,
    78. .rst_n(rst_n) ,
    79. .write_sig(write_pulse) ,
    80. .read_sig(read_pulse) ,
    81. .write_addr(write_addr[11:0]) ,
    82. .write_bank(write_addr[15:14]) ,
    83. .write_data(write_data) ,
    84. .read_addr(read_addr[11:0]) ,
    85. .read_bank(read_addr[15:14]) ,
    86. .trans_done(trans_done) ,
    87. .read_data(rd_data) ,
    88. .sclk(sclk) ,
    89. .CKE(CKE) ,
    90. .CS_N(CS_N) ,
    91. .RAS_N(RAS_N) ,
    92. .CAS_N(CAS_N) ,
    93. .WE_N(WE_N) ,
    94. .DQM(DQM) ,//高电平时屏蔽
    95. .SA(SA) ,//A12 - A0
    96. .BA(BA) ,
    97. .DQ(DQ)
    98. );
    99. wire uart_send_done ;
    100. reg uart_send_en ;
    101. uart_send uart_send(
    102. .clk(fpga_clk),
    103. .reset(rst_n),
    104. .data(read_data[7:0]),
    105. .send_en(uart_send_en),
    106. .baud_rate(5),//115200
    107. .uart_tx(uart_tx),
    108. .tx_done(uart_send_done)
    109. );
    110. //Parsing frames
    111. localparam frames_header = 8'hAA ;
    112. localparam frames_tail = 8'h55 ;
    113. localparam read_option = 8'h5A ;
    114. localparam write_option = 8'hA5 ;
    115. reg [15:0]wr_cnt ;
    116. reg [15:0]rd_cnt ;
    117. always@(posedge fpga_clk or negedge rst_n)
    118. if(!rst_n)
    119. begin
    120. write_addr <= 0 ;
    121. read_addr <= 0 ;
    122. write_data <= 0;
    123. read_data <= 0 ;
    124. write_pulse <= 0 ;
    125. read_pulse <= 0 ;
    126. wr_cnt <= 0 ;
    127. rd_cnt <= 0 ;
    128. end
    129. else if( rw_flag )
    130. begin
    131. if ( (rec_shift_reg[0] == frames_header) && (rec_shift_reg[1] == frames_header) && (rec_shift_reg[7] == frames_tail) )
    132. begin
    133. if(rec_shift_reg[4] == write_option )
    134. begin
    135. write_addr <= { rec_shift_reg[2] , rec_shift_reg[3] } ;
    136. write_data <= {rec_shift_reg[5],rec_shift_reg[6]} ;
    137. wr_cnt <= wr_cnt + 1 ;
    138. //write signal
    139. if( wr_cnt < 3 )
    140. write_pulse <= 1 ;
    141. else if(trans_done)
    142. begin
    143. wr_cnt <= 0 ;
    144. end
    145. else
    146. write_pulse <= 0 ;
    147. end
    148. else if ( rec_shift_reg[4] == read_option )
    149. begin
    150. read_addr <= { rec_shift_reg[2] , rec_shift_reg[3] } ;
    151. //read signal
    152. rd_cnt <= rd_cnt + 1 ;
    153. if(trans_done)
    154. begin
    155. read_data <= rd_data ;
    156. read_pulse <= 0 ;
    157. rd_cnt <= 0 ;
    158. end
    159. else if(rd_cnt <3)
    160. read_pulse <= 1 ;
    161. else
    162. read_pulse <= 0 ;
    163. end
    164. end
    165. end
    166. else
    167. begin
    168. write_pulse <= 0 ;
    169. read_pulse <= 0 ;
    170. wr_cnt <= 0 ;
    171. rd_cnt <= 0 ;
    172. end
    173. always@(posedge fpga_clk or negedge rst_n)
    174. if(!rst_n)
    175. uart_send_en <= 0 ;
    176. else if(trans_done && (rec_shift_reg[4] == read_option) )
    177. uart_send_en <= 1 ;
    178. else if(uart_send_done)
    179. uart_send_en <= 0 ;
    180. endmodule

    2.板级验证

            fpga向sdram芯片写入数据16‘h1234,并返回低位8’h34。

  • 相关阅读:
    吴恩达机器学习课程笔记3-4
    RTP和RTCP详解
    MVC架构和DDD架构的区别?
    Python | GUI | tinker不完全总结
    电商新趋势:Starday拿下黑色星期五的制胜法宝是物流速度
    YBTOJ 期望分数【第31章 期望问题】
    【idea】解决idea 执行maven build总下载 Downloading maven-metadata.xml文件
    ValueError: unsupported format character ‘;‘ (0x3b) at index 625
    经典算法之冒泡排序
    .NET 实现启动时重定向程序运行路径及 Windows 服务运行模式部署
  • 原文地址:https://blog.csdn.net/qq_44366923/article/details/134063833