SRRAM驱动(一)
0赞SDRAM驱动流程:
(一) 初始化:
图一
SDRAM初次上电时,需要对内部的逻辑控制单元进行初始化。如图一所示,初始化的具体流程如下:
1、 延时200us。
2、 对所有L-Bank进行预充电。具体操作:拉高所有rBA,rA地址,发送PR(预充电)命令。
3、 延时TRP。
4、 进行自刷新,发送AR(自刷新)命令。
5、 延时TRRC。
6、 重复步骤4和5。
7、 发送LMR(设置命令)命令与相关设置内容。详细设置见SDRAM模式寄存器设置。
8、 延时TMRD。
具体代码如下(参考:Verilog 那些事儿,驱动篇I):
//Initial
case (i)
0: //Dealy 200US
begin
if(C1 == T200US -1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
end
end
1: //Set Precharg Command
begin
rCMD <= _PR;
rBA <= 2'b11;
rA <= 13'h1fff;
i <= i + 1'b1;
end
2://Delay TRP 20ns
begin
if(C1 == TRP -1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
3://Set Auto Refresh command
begin
rCMD <= _AR;
i <= i + 1'b1;
end
4://delay tRRC 63ns
begin
if(C1 == TRRC -1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
5://Set Auto Refresh Command
begin
rCMD <= _AR;
i <= i + 1'b1;
end
6://delay tRRC 63ns
begin
if(C1 == TRRC -1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
7://Set LMR Command:burst Read and Write, A6A5A4=011 means CAS latecy = 3, Sequential, 1 burst length
begin
rCMD <= _LMR;
rBA <= 2'b11;
rA <= {3'd0, 1'b0, 2'd0, 3'b011, 1'b0, 3'b000};
i <= i + 1'b1;
end
8://Set 2 nop CLK for tMRD
begin
if(C1 == TMRD -1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
9://Generate done signal
begin
isDone = 1'b1;
i <= i + 1'b1;
end
10:
begin
isDone = 1'b0;
i <= 4'd0;
end
endcase
(二)自刷新:
SDRAM需要不断刷新才能保留住数据,目前公认的标准是存储体数据有效保存期上限是64ms,即每一行刷新的循环周期是64ms。对于整个SDRAM,需要每隔行数量/64ms就要进行一次刷新。发送AR(自刷新)命令时不需要外部提供行地址信息,行地址由SDRAM的内部行地址生成器自动依次生成。刷新是针对一行中所有的存储体进行,所以无需进行列寻址。自刷新的具体流程如下(操作相当于简化后的初始化):
1、发送PR(预充电)命令。
2、延时TRP。
3、进行自刷新,发送AR(自刷新)命令。
4、延时TRRC。
5、重复步骤3和4。
具体代码如下(参考:Verilog 那些事儿,驱动篇I):
//Auto Refresh
case(i)
0: //Set Precharg Command
begin
rCMD <= _PR;
i <= i + 1'b1;
end
1://Delay TRP 20ns
begin
if(C1 == TRP -1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
2://Set Auto Refresh Command
begin
rCMD <= _AR;
i <= i + 1'b1;
end
3://delay tRRC 63ns
begin
if(C1 == TRRC -1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
4://Set Auto Refresh Command
begin
rCMD <= _AR;
i <= i + 1'b1;
end
5://delay tRRC 63ns
begin
if(C1 == TRRC -1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
6://Generate done signal
begin
isDone = 1'b1;
i <= i + 1'b1;
end
7:
begin
isDone = 1'b0;
i <= 4'd0;
end
endcase
(三)数据写(单字节):
SDRAM数据读写按照L-BANK->行->列寻址。在写入数据后,还要执行预充电命令。预充电的目的是释放L-BANK地址,行地址,列地址。方便对同一个L-BANK的其他行地址进行操作。数据写的具体流程为:
图二
图三
2、延时TRCD。
3、发送WR(写)命令,发送L-BANK,列地址。同时A10需要拉高进行预充电。写数据。
4、延时TWR。
5、延时TRP。
具体代码如下(参考:Verilog 那些事儿,驱动篇I):
//Data Write
case(i)
0://Set IO to Output State
begin
IsOut = 1;
i <= i + 1'b1;
end
1: //Send Active Command with Bank and Row address
begin
rCMD <= _ACT;
rBA <= iAddr[23:22];
rA <= iAddr[21:9];
i <= i + 1'b1;
end
2: //Wait TRCD 20ns
begin
if(C1 == TRCD - 1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
3: // Send Write cmd with row address, pull up A10 1 clk to PR
begin
rCMD <= _WR;
rBA <= iAddr[23:22];
rA <= {4'b0010, iAddr[8:0] };
i <= i + 1'b1;
rDA <= rData; //Write data
end
4: //Wait TWR 2 CLK
begin
if(C1 == TWR - 1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
5://Delay TRP 20ns
begin
if(C1 == TRP -1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
6://Generate done signal
begin
isDone = 1'b1;
i <= i + 1'b1;
end
7:
begin
isDone = 1'b0;
i <= 4'd0;
end
endcase
数据写(多字节):
以BL=4为例,需要在模式寄存器中设置BL=4,即A2~A0 = 3‘b010。具体流程为:
1、发送ACT(激活)命令,发送L-BANK,行地址。
2、延时TRCD。
3、发送WR(写)命令,发送L-BANK,列地址。同时A10需要拉高进行预充电。写第一字节数据。
4、写第一字节数据。
5、写第二字节数据。
6、写第三字节数据。
7、写第四字节数据。
8、延时TWR。
9、延时TRP。
具体代码如下(参考:Verilog 那些事儿,驱动篇I):
//Data Write
case(i)
0://Set IO to Output State
begin
IsOut = 1;
i <= i + 1'b1;
end
1: //Send Active Command with Bank and Row address
begin
rCMD <= _ACT;
rBA <= iAddr[23:22];
rA <= iAddr[21:9];
i <= i + 1'b1;
end
2: //Wait TRCD 20ns
begin
if(C1 == TRCD - 1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
3: // Send Write cmd with row address, pull up A10 1 clk to PR
begin
rCMD <= _WR;
rBA <= iAddr[23:22];
rA <= {4'b0010, iAddr[8:0] };
D1 <= iData[63:48];
i <= i + 1'b1;
end
4:
begin
rCMD <= _NOP;
D1 <= iData[47:32];
i <= i + 1'b1;
end
5:
begin
rCMD <= _NOP;
D1 <= iData[31:16];
i <= i + 1'b1;
end
6:
begin
rCMD <= _NOP;
D1 <= iData[15:0];
i <= i + 1'b1;
end
7: //Wait TWR 2 CLK
begin
if(C1 == TWR - 1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
8://Delay TRP 20ns
begin
if(C1 == TRP -1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
9://Generate done signal
begin
isDone = 1'b1;
i <= i + 1'b1;
end
10:
begin
isDone = 1'b0;
i <= 4'd0;
end
endcase
(四)数据读(单字节):
SDRAM数据读取与数据写入大同小异。数据读写按照L-BANK->行->列寻址。在读入数据后,还要执行预充电命令。发出数据读取命令后需要满足CAS延时。具体流程为:
图四
1、发送ACT(激活)命令,发送L-BANK,行地址。
2、延时TRCD。
3、发送RD(读)命令,发送L-BANK,列地址。同时A10需要拉高进行预充电。
4、延时,满足CAS Latency。
5、读取数据。
6、延时TRP。
具体代码如下(参考:Verilog 那些事儿,驱动篇I):
//Data Read
case(i)
0://Set IO to Input State
begin
IsOut = 0;
i <= i + 1'b1;
end
1: //Send Active Command with Bank and Row address
begin
rCMD <= _ACT;
rBA <= iAddr[23:22];
rA <= iAddr[21:9];
i <= i + 1'b1;
end
2: //Wait TRCD 20ns
begin
if(C1 == TRCD - 1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
3: // Send Read cmd with row address, pull up A10 1 clk to PR
begin
rCMD <= _RD;
rBA <= iAddr[23:22];
rA <= {4'b0010,iAddr[8:0] };
i <= i + 1'b1;
end
4: //Wait CL 3 CLK
begin
if(C1 == CL - 1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
5: //Read data
begin
D1 <= S_DQ;
i <= i + 1'b1;
end
6://Delay TRP 20ns
begin
if(C1 == TRP -1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
7://Generate done signal
begin
isDone = 1'b1;
i <= i + 1'b1;
end
8:
begin
isDone = 1'b0;
i <= 4'd0;
end
endcase
(四)数据读(多字节):
以BL=4为例,需要在模式寄存器中设置BL=4,即A2~A0 = 3‘b010。具体流程为:
1、发送ACT(激活)命令,发送L-BANK,行地址。
2、延时TRCD。
3、发送RD(读)命令,发送L-BANK,列地址。同时A10需要拉高进行预充电。
4、延时,满足CAS Latency。
5、读取第一个字节。
6、读取第二个字节。
7、读取第三个字节。
8、读取第四个字节。
9、延时TRP。
具体代码如下(参考:Verilog 那些事儿,驱动篇I):
//Data Read
case(i)
0://Set IO to Input State
begin
IsOut = 0;
i <= i + 1'b1;
D1 <= 16'd0;
end
1: //Send Active Command with Bank and Row address
begin
rCMD <= _ACT;
rBA <= iAddr[23:22];
rA <= iAddr[21:9];
i <= i + 1'b1;
end
2: //Wait TRCD 20ns
begin
if(C1 == TRCD - 1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
3: // Send Read cmd with row address, pull up A10 1 clk to PR
begin
rCMD <= _RD;
rBA <= iAddr[23:22];
rA <= {4'b0010,iAddr[8:0] };
i <= i + 1'b1;
end
4: //Wait CL 3 CLK
begin
if(C1 == CL - 1)
begin
i <= i + 1'b1;
C1 <= 14'd0;
end
else
begin
C1 <= C1 + 1'b1;
rCMD <= _NOP;
end
end
5: //Read data
begin
T[63:48] <= S_DQ;
i <= i + 1'b1;
end
6: //Read data
begin
T[47:32] <= S_DQ;
i <= i + 1'b1;
end
7: //Read data
begin
T[31:16] <= S_DQ;
i <= i + 1'b1;
end
8: //Read data
begin
T[15:0] <= S_DQ;
i <= i + 1'b1;
end
9:
begin
rCMD <= _NOP;
isDone = 1'b1;
i <= i + 1'b1;
end
10:
begin
isDone = 1'b0;
i <= 4'd0;
end
endcase
SDRAM模式寄存器控制
在前文说过,在SDRAM初始化时,需要设置模式寄存器。模式寄存器的参数设置是通过设置地址线的0/1信号实现的。地址线各个位对应的寄存器设置加下图:
图五
BA1~BA0,A11~A7:设置操作模式。
A6~A4:CAS潜伏期,读操作中的CL参数,发出读命令后存储芯片到IO口输出真正数据需要的延时。
A3:突发传输方式。1—顺序传输,按照地址依次进行数据寻址。每次数据读写需要发送读写命令和读写地址。0—突发传输,数据读写前只需要指定首地址和突发长度,发送一次读写命令后便可以进行连续数据读写。
A2~A0:连续数据读写长度设置。设置BL的值后,可以在sdram读写程序中读写相应的长度。每次数据读写各需要一个时钟周期。