zoukankan      html  css  js  c++  java
  • 【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验二十:SDRAM模块③ — 页读写 α

    实验二十:SDRAM模块③ — 页读写 α

    完成单字读写与多字读写以后,接下来我们要实验页读写。丑话当前,实验二十的页读写只是实验性质的东西,其中不存在任何实用价值,笔者希望读者可以把它当成页读写的热身运动。

    表示20.1 Mode Register的内容。

    Mode Register

    A12

    A11

    A10

    A9

    A8

    A7

    A6

    A5

    A4

    A3

    A2

    A1

    A0

    0

    0

    OP Code

    0

    0

    CAS Latency

    BT

    Burst Length

    A3

    Burst Type

    0

    Sequential

    1

    Interleave

     

    Burst Length

    A2

    A1

    A0

    A3 = 0

    A3 = 1

    0

    0

    0

    1

    1

    0

    0

    1

    2

    2

    0

    1

    0

    4

    4

    0

    1

    1

    8

    8

    1

    1

    1

    Full Page

    Reserved

    A9

    Write Mode

    0

    Burst Read and Burst Write

    1

    Burst Read and Single Write

    A6

    A5

    A4

    CAS Latency

    0

    1

    0

    2

    0

    1

    1

    3

    所谓页读写就是全列读写,而且表20.1告诉我们,页读写必须将 A2~A0设置为3’b111。然而,Verilog的描述结果如代码20.1所示:

     7: // Send LMR Cmd. Burst Read & Write,  3'b010 mean CAS latecy = 3, Sequential,Full Page
     begin rCMD <= _LMR; rBA <= 2'b11; rA <= { 3'd0, 1'b0, 2'd0, 3'b011, 1'b0, 3'b111 }; i <= i + 1'b1; end

    代码20.1

    如果我们一页一页的叫,基本上“一页”的定义是非常暧昧的,因为“一页”所指定的范围会随着该存储器的容量而有所改变。举例HY57V2562GTR 这只SDRAM,地址的指定范围有 BA1~BA0,R12~R0,C8~C0,其中“一页”是全列,亦即C8~C0。根据计算,C8~C0等价29 = 512,或者说页读写有512的地址偏移量。

    页写操作:

    clip_image002

    图20.1 页写操作的理想时序图。

    图20.1是笔者自定义的页写操作的理想时序图,其中C1是为了控制读写的次数。页读写相较字读写,前者好比一只不会停下冲锋的山猪。一旦读写开始,SDRAM内部的计数器就会从0开始计数,计数结果为511又会从0重新计数。因为如此,页读写需要利用BSTP命令禁止山猪继续冲锋。

    此外,自动预充对页读写来说是无效的东西,因此A10拉不拉高都没有关系,而且页写操作也不需要满足 TWR/TDPL与TPR。图20.1大致的时序过程如下:

    l T1,发送ACT命令,BANK地址与行地址;

    l T1半周期,SDRAM读取;

    l T2,满足TRCD;

    l T3,发送WR命令,BANK地址与列地址,还有第0数据;

    l T3半周期,SDRAM读取

    l T4,发送第1~511数据,然后发送BSTP命令结束页写。

    Verilog则可以这样描述,结果如代码20.2所示:

    1.    1: // Send Active Command with Bank and Row address
    2.    begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
    3.                         
    4.    2: // wait TRCD 20ns
    5.    if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    6.    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end             
    7.                    
    8.    3: // Send Write command with row address 
    9.    begin rCMD <= _WR; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0] }; D1 <= iData; i <= i + 1'b1; end
    10.                         
    11.     4: // continue write until end and send BSTP 
    12.     if( C1 == 512 -1 ) begin rCMD <= _BSTP; C1 <= 14'd0; i <= i + 1'b1 ;end
    13.     else begin rCMD <= _NOP; C1 <= C1 + 1'b1; D1 <= D1 + 1'b1; end 

    代码20.2

    如代码20.2所示,步骤3写第0数据,步骤4则写入第1~511数据并且发送 BSTP命令。

    页读操作:

    clip_image004

    图20.2 页读操作的理想时序图。

    图20.2也是笔者自定义的理想时序图。同样,页读操也是一只不断冲锋的山猪,因此它需要BSTP这支停下的告示牌。除此之外,页读也没有自行预充电的必要,而且TPR也不用满足。实验二十要实验的页读比较单纯,我们读取第0数据以后立即发送BSTP命令来结束也操作。图20.2大致的时序过程如下:

    l T1,发送ACT命令,BANK地址与行地址;

    l T1半周期,SDRAM读取;

    l T2,满足TRCD;

    l T3,发送RD命令,BANK地址与列地址;

    l T3半周期,SDRAM读取命令。

    l T4,满足 CAS Latency。

    l T5,读取第0数据,然后发送BSTP命令。

    Verilog则可以这样描述,结果如代码20.3所示:

    1.    1: // Send Active command with Bank and Row address
    2.    begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
    3.                         
    4.    2: // wait TRCD 20ns
    5.    if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    6.    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
    7.                    
    8.    3: // Send Read command and column address
    9.    begin rCMD <= _RD; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0]}; i <= i + 1'b1; end
    10.    
    11.    4: // wait CL 3 clock
    12.    if( C1 == CL -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    13.    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
    14.                    
    15.    5: // Read Data
    16.    begin D1 <= S_DQ; rCMD <= _BSTP; i <= i + 1'b1; end

    代码20.3

    如代码20.3所示,步骤5读取数据以后立即发送 BSTP命令以示结束页读操作。理解完毕以后我们便可以开始建模了。

    clip_image006

    图20.3 SDRAM基础模块的建模图。

    图20.3是SDRAM基础模块的建模图,外表上和实验十八差不多,不过SDRAM功能模块的内容却有一些改变。

    sdram_funcmod.v
    1.    module sdram_funcmod
    2.    (
    3.         input CLOCK,
    4.         input RESET,
    5.         
    6.         output S_CKE, S_NCS, S_NRAS, S_NCAS, S_NWE,
    7.         output [1:0]S_BA,  
    8.         output [12:0]S_A,  
    9.         output [1:0]S_DQM,
    10.         inout [15:0]S_DQ,
    11.         
    12.         input [3:0]iCall,
    13.         output oDone,
    14.         input [23:0]iAddr,  // [23:22]BA,[21:9]Row,[8:0]Column
    15.         input [15:0]iData,
    16.         output [15:0]oData
    17.    );

    第3~16行是相关的输入端声明。

    18.        parameter T100US = 14'd13300;
    19.        // tRP 20ns, tRRC 63ns, tRCD 20ns, tMRD 2CLK, tWR/tDPL 2CLK, CAS Latency 3CLK
    20.        parameter TRP = 14'd3, TRRC = 14'd9, TMRD = 14'd2, TRCD = 14'd3, TWR = 14'd2, CL = 14'd3;
    21.        parameter _INIT = 5'b01111, _NOP = 5'b10111, _ACT = 5'b10011, _RD = 5'b10101, _WR = 5'b10100,
    22.                _BSTP = 5'b10110, _PR = 5'b10010, _AR = 5'b10001, _LMR = 5'b10000;
    23.         

    第18~22行是相关的常量声明。

    24.        reg [4:0]i;
    25.        reg [13:0]C1;
    26.        reg [15:0]D1;
    27.        reg [4:0]rCMD;
    28.        reg [1:0]rBA;
    29.        reg [12:0]rA;
    30.        reg [1:0]rDQM;
    31.        reg isOut;
    32.        reg isDone;
    33.    
    34.        always @ ( posedge CLOCK or negedge RESET )
    35.            if( !RESET )
    36.                begin
    37.                    i <= 4'd0;
    38.                   C1 <= 14'd0;
    39.                   D1 <= 16'd0;
    40.                    rCMD <= _NOP;
    41.                    rBA <= 2'b11;
    42.                    rA <= 13'h1fff;
    43.                    rDQM <= 2'b00;
    44.                    isOut <= 1'b1;
    45.                   isDone <= 1'b0;
    46.                end

    第24~46行是相关的寄存器声明与复位操作。

    47.              else if( iCall[3] )
    48.                case( i )
    49.                    
    50.                    0: // Set IO to output State
    51.                    begin isOut <= 1'b1; i <= i + 1'b1; end
    52.                       
    53.                    1: // Send Active Command with Bank and Row address
    54.                    begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
    55.                         
    56.                   2: // wait TRCD 20ns
    57.                   if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    58.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end             
    59.                    
    60.                    /*********************************************/
    61.                    
    62.                    3: // Send Write command with row address
    63.                    begin rCMD <= _WR; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0] }; D1 <= iData; i <= i + 1'b1; end
    64.                         
    65.                    4: // continue write until end and send BSTP 
    66.                   if( C1 == 512 -1 ) begin rCMD <= _BSTP; C1 <= 14'd0; i <= i + 1'b1 ;end
    67.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; D1 <= D1 + 1'b1; end 
    68.                     
    69.                    /**********************************************/
    70.                         
    71.                    5: // Generate done signal
    72.                    begin rCMD <= _NOP; isDone <= 1'b1; i <= i + 1'b1; end
    73.                        
    74.                   6:
    75.                   begin isDone <= 1'b0; i <= 4'd0; end
    76.                    
    77.                endcase

    以上内容为页写操作,注意步骤3写入第0数据,步骤4则写入第1~511数据并且发送BSTP命令。

     
    78.            else if( iCall[2] )
    79.                case( i )
    80.                    
    81.                    0:
    82.                    begin isOut <= 1'b0; D1 <= 16'd0; i <= i + 1'b1; end
    83.    
    84.                    1: // Send Active command with Bank and Row address
    85.                    begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
    86.                         
    87.                    2: // wait TRCD 20ns
    88.                    if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    89.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
    90.                
    91.                    /********************/
    92.                    
    93.                    3: // Send Read command and column address
    94.                    begin rCMD <= _RD; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0]}; i <= i + 1'b1; end
    95.    
    96.                    4: // wait CL 3 clock
    97.                    if( C1 == CL -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    98.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
    99.                                       
    100.                    /********************/ 
    101.                    
    102.                    5: // Read Data
    103.                    begin D1 <= S_DQ; rCMD <= _BSTP; i <= i + 1'b1; end
    104.                    
    105.                    /********************/
    106.                
    107.                    6: // Generate done signal
    108.                    begin rCMD <= _NOP; isDone <= 1'b1; i <= i + 1'b1; end
    109.                        
    110.                    7:
    111.                    begin isDone <= 1'b0; i <= 4'd0; end
    112.    
    113.                endcase

    以上内容为页读操作,注意步骤5是读取第0数据并且发送 BSTP命令。

    114.              else if( iCall[1] )
    115.                case( i )
    116.                    
    117.                    0: // Send Precharge Command
    118.                    begin rCMD <= _PR; i <= i + 1'b1; end
    119.                         
    120.                    1: // wait TRP 20ns
    121.                    if( C1 == TRP -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    122.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    123.                         
    124.                    2: // Send Auto Refresh Command
    125.                    begin rCMD <= _AR; i <= i + 1'b1; end
    126.                   
    127.                    3: // wait TRRC 63ns
    128.                   if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    129.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    130.                         
    131.                   4: // Send Auto Refresh Command
    132.                    begin rCMD <= _AR; i <= i + 1'b1; end
    133.                   
    134.                    5: // wait TRRC 63ns
    135.                    if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    136.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    137.                    
    138.                    /********************/
    139.                    
    140.                    6: // Generate done signal
    141.                    begin isDone <= 1'b1; i <= i + 1'b1; end
    142.                        
    143.                   7:
    144.                   begin isDone <= 1'b0; i <= 4'd0; end
    145.    
    146.                endcase

    以上内容是刷新操作。

     
    147.              else if( iCall[0] )
    148.                case( i )
    149.                    
    150.                   0:  // delay 100us
    151.                   if( C1 == T100US -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    152.                   else begin C1 <= C1 + 1'b1; end 
    153.                   
    154.                   /********************/
    155.                   
    156.                   1: // Send Precharge Command
    157.                   begin rCMD <= _PR; { rBA, rA } <= 15'h3fff; i <= i + 1'b1; end
    158.                        
    159.                   2: // wait TRP 20ns
    160.                  if( C1 == TRP -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    161.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    162.                   
    163.                   3: // Send Auto Refresh Command
    164.                   begin rCMD <= _AR; i <= i + 1'b1; end
    165.                   
    166.                   4: // wait TRRC 63ns
    167.                  if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    168.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    169.                        
    170.                   5: // Send Auto Refresh Command
    171.                   begin rCMD <= _AR; i <= i + 1'b1; end
    172.                   
    173.                   6: // wait TRRC 63ns
    174.                  if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    175.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    176.                
    177.                   /********************/
    178.                   
    179.                   7: // Send LMR Cmd. Burst Read & Write,  3'b010 mean CAS latecy = 3, Sequential,Full Page
    180.                   begin rCMD <= _LMR; rBA <= 2'b11; rA <= { 3'd0, 1'b0, 2'd0, 3'b011, 1'b0, 3'b111 }; i <= i + 1'b1; end
    181.                        
    182.                   8: // Send 2 nop CLK for tMRD
    183.                   if( C1 == TMRD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    184.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    185.                   
    186.                   /********************/
    187.                   
    188.                   9: // Generate done signal
    189.                   begin isDone <= 1'b1; i <= i + 1'b1; end
    190.                        
    191.                   10:
    192.                   begin isDone <= 1'b0; i <= 4'd0; end
    193.                   
    194.                endcase
    195.      

    以上内容是初始化,注意步骤7的Mode Register 内容,Busrt Length 为 3’b111。

    196.         assign { S_CKE, S_NCS, S_NRAS, S_NCAS, S_NWE } = rCMD;
    197.         assign { S_BA, S_A } = { rBA, rA };
    198.         assign S_DQM = rDQM;
    199.         assign S_DQ  = isOut ? D1 : 16'hzzzz;
    200.         assign oDone = isDone;
    201.         assign oData = D1;
    202.    
    203.    endmodule

    第196~201行是相关的输出驱动。

    sdram_ctrlmod.v

    该控制模块的内容与实验十八一致。

    sdram_basemod.v

    该组合模块的内容也与实验十八一致

    sdram_demo.v

    clip_image008

    图20.4 实验二十的建模图。

    图20.4是实验二十的建模图,外观上与实验十八一样,不过核心操作的内容却有所不同,具体内容我们还是来看代码吧。

    1.    module sdram_demo
    2.    (
    3.        input CLOCK,
    4.        input RESET,
    5.        output S_CLK,
    6.        output S_CKE, S_NCS, S_NRAS, S_NCAS, S_NWE,
    7.        output [12:0]S_A, 
    8.        output [1:0]S_BA,
    9.        output [1:0]S_DQM,
    10.        inout [15:0]S_DQ,
    11.        output TXD
    12.    ); 

    以上内容为相关的出入端声明。

    13.         wire CLOCK1,CLOCK2;
    14.         
    15.         pll_module U1
    16.         (
    17.                .inclk0 ( CLOCK ), // 50Mhz
    18.                .c0 ( CLOCK1 ),  // 133Mhz -210 degree phase
    19.                .c1 ( CLOCK2 )   // 133Mhz 
    20.         );
    21.         

    以上内容为PLL模块的实例化。

    22.         wire [1:0]DoneU2;
    23.         wire [15:0]DataU2;
    24.         
    25.         sdram_basemod U2
    26.         (
    27.              .CLOCK( CLOCK1 ),
    28.              .RESET( RESET ),
    29.              .S_CKE( S_CKE ),
    30.              .S_NCS( S_NCS ),
    31.              .S_NRAS( S_NRAS ),
    32.              .S_NCAS( S_NCAS ),
    33.              .S_NWE( S_NWE ),
    34.              .S_A( S_A ),
    35.              .S_BA( S_BA ),
    36.              .S_DQM( S_DQM ),
    37.              .S_DQ( S_DQ ),
    38.              .iCall( isCall ),
    39.              .oDone( DoneU2 ),
    40.              .iAddr( D1 ),
    41.              .iData( D2 ),
    42.              .oData( DataU2 )
    43.         );
    44.         

    以上内容为SDRAM基础模块的实例化。

    45.         parameter B115K2 = 11'd1157, TXFUNC = 6'd16;
    46.         
    47.         reg [5:0]i,Go;
    48.         reg [10:0]C1;
    49.         reg [23:0]D1;
    50.         reg [15:0]D2,D3;
    51.         reg [10:0]T;
    52.         reg [1:0]isCall;
    53.         reg rTXD;
    54.         
    55.         always @ ( posedge CLOCK1 or negedge RESET )
    56.             if( !RESET )
    57.                 begin
    58.                     i <= 6'd0;
    59.                    Go <= 6'd0;
    60.                    C1 <= 11'd0;
    61.                     D1 <= 24'd0;
    62.                    D2 <= 16'd0;
    63.                    D3 <= 16'd0;
    64.                    T <= 11'd0;
    65.                    isCall <= 2'b00;
    66.                    rTXD <= 1'b1;
    67.                 end
    68.             else 

    以上内容为相关的寄存器声明还有复位操作。第45行是波特率还有伪函数入口的常量声明。

    69.                 case( i )
    70.                        
    71.                         0:
    72.                         if( DoneU2[1] ) begin isCall[1] <= 1'b0; i <= i + 1'b1; end
    73.                         else begin isCall[1] <= 1'b1; D1 <= 24'd0; D2 <= 16'hA000; end
    74.                         
    75.                         1:
    76.                         if( DoneU2[0] ) begin D3 <= DataU2; isCall[0] <= 1'b0; i <= i + 1'b1; end
    77.                         else begin isCall[0] <= 1'b1; end
    78.                         
    79.                         2:
    80.                         begin T <= { 2'b11, D3[15:8], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
    81.                         
    82.                         3:
    83.                         begin T <= { 2'b11, D3[7:0], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
    84.                         
    85.                         4:
    86.                         if( D1 == 24'd511 ) i <= i + 1'b1;
    87.                         else begin D1 <= D1 + 1'b1; i <= 6'd1; end
    88.     
    89.                          5:
    90.                          i <= i;
    91.                         
    92.                         /******************************/
    93.                     

    以上内容为部分核心操作。步骤0将数据 16’hA×××从地址0写至地址511,其中×××会经由页写而自行递增。换句话说,数据16’hA000~16’hA1FF从地址0写至地址511。

    步骤1则用来读取数据,步骤2~3将读出的数据一一发送出去。步骤4用来递增地址,从0~511,然后返回步骤1,直至人为页读结束。

    94.                          16,17,18,19,20,21,22,23,24,25,26:
    95.                         if( C1 == B115K2 -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
    96.                         else begin rTXD <= T[i - 16]; C1 <= C1 + 1'b1; end
    97.                         
    98.                         27:
    99.                         i <= Go;
    100.                         
    101.                endcase
    102.    
    103.         assign S_CLK = CLOCK2;
    104.         assign TXD = rTXD;
    105.    
    106.    endmodule

    以上内容为部分核心操作。步骤16~27是发送一帧数据的伪函数。第103~104行则是相关的输出驱动。综合完毕并且下载程序,如果串口调试软件出现数据 A000~A1FF表示实验成功。

  • 相关阅读:
    【Azure 应用服务】在Azure App Service多实例的情况下,如何在应用中通过代码获取到实例名(Instance ID)呢?
    【Azure 应用服务】App Service For Windows 中如何设置代理实现前端静态文件和后端Java Spring Boot Jar包
    【Azure Developer】使用Azure Key Vault 的Key签名后,离线验证的一些参考资料
    【Azure Function】调试 VS Code Javascript Function本地不能运行,报错 Value cannot be null. (Parameter 'provider')问题
    【Azure 应用服务】App Service 使用Tomcat运行Java应用,如何设置前端网页缓存的相应参数呢(Xms512m Xmx1204m)?
    【Azure API 管理】APIM添加Logtoeventhub的策略后,一些相关APIM与Event Hub的问题
    【Azure API 管理】为调用APIM的请求启用Trace 调试APIM Policy的利器
    【Azure 事件中心】China Azure上是否有Kafka服务简答
    【Azure 应用服务】探索在Azure上设置禁止任何人访问App Service的默认域名(Default URL)
    【Azure 微服务】记一次错误的更新Service Fabric 证书而引发的集群崩溃而只能重建
  • 原文地址:https://www.cnblogs.com/alinx/p/4413839.html
Copyright © 2011-2022 走看看