本(běn)文(wén)为(wèi)明(míng)德揚原創录(lù)用(yòng)文(wén)章(zhāng),轉(zhuǎn)载請注明(míng)出(chū)处!
SDRAM控制器設計(jì)的(de)主(zhǔ)要(yào)功能(néng)是(shì)能(néng)对(duì)SDRAM進(jìn)行读(dú)写操作,本(běn)工程实現(xiàn)了(le)SDRAM的(de)初始化(huà)和(hé)自(zì)動(dòng)刷新两(liǎng)个(gè)功能(néng)。
初始化(huà)功能(néng)在(zài)前(qián)一(yī)章(zhāng)的(de)分(fēn)享中(zhōng)已經(jīng)進(jìn)行了(le)比較詳细(xì)的(de)描述,感(gǎn)興趣的(de)同(tóng)学可(kě)以(yǐ)搜索学習下(xià),文(wén)後(hòu)曆史文(wén)章(zhāng)里(lǐ)有(yǒu)鍊(liàn)接。今天(tiān)我(wǒ)们(men)主(zhǔ)要(yào)讨論SDRAM的(de)自(zì)動(dòng)刷新的(de)功能(néng)以(yǐ)及(jí)实現(xiàn)。
一(yī)、原理功能(néng)
1、为(wèi)什麼(me)刷新
我(wǒ)们(men)都知道(dào)SDRAM是(shì)使用(yòng)電(diàn)容保存信(xìn)息的(de),随着使用(yòng)时(shí)間(jiān)的(de)增长,電(diàn)容的(de)電(diàn)量(liàng)会(huì)有(yǒu)損失,因(yīn)此(cǐ)在(zài)操作SDRAM时(shí)要(yào)進(jìn)行刷新。SDRAM的(de)刷新分(fēn)为(wèi)两(liǎng)種(zhǒng),分(fēn)别是(shì)Auto Refresh和(hé)Self Refresh。本(běn)次(cì)实验(yàn)采用(yòng)的(de)是(shì)Auto Refresh。
2、刷新間(jiān)隔
查詢器件(jiàn)手(shǒu)册得到(dào)(64ms, 8192-cycle (commercial and industrial)),对(duì)8192行全(quán)部(bù)進(jìn)行一(yī)次(cì)刷新时(shí)間(jiān)是(shì)64ms。一(yī)次(cì)刷新操作是(shì)对(duì)4个(gè)bank的(de)同(tóng)一(yī)行進(jìn)行刷新,所(suǒ)以(yǐ)一(yī)次(cì)刷新間(jiān)隔是(shì)64ms/8192=7.813us。但是(shì)當刷新时(shí)間(jiān)到(dào)来(lái)时(shí),SDRAM可(kě)能(néng)正(zhèng)在(zài)進(jìn)行读(dú)写,那(nà)麼(me)需要(yào)本(běn)次(cì)读(dú)突發(fà)或(huò)者(zhě)写突發(fà)完成(chéng)之後(hòu)才能(néng)進(jìn)行刷新操作;那(nà)麼(me)一(yī)次(cì)读(dú)突發(fà)为(wèi)7拍,写突發(fà)为(wèi)6拍,时(shí)間(jiān)是(shì)60ns或(huò)者(zhě)70ns (SDRAM工作时(shí)鐘(zhōng)是(shì)100MHz,1拍是(shì)10ns),同(tóng)时(shí)考慮到(dào)读(dú)写命令都是(shì)仲裁模块(kuài)發(fà)出(chū),会(huì)有(yǒu)一(yī)定(dìng)的(de)延时(shí),所(suǒ)以(yǐ)本(běn)次(cì)实验(yàn)刷新間(jiān)隔設为(wèi)7.5us,留出(chū)足够的(de)时(shí)間(jiān)。
3、刷新时(shí)序

刷新时(shí)序如(rú)上(shàng)图(tú)所(suǒ)示。这(zhè)里(lǐ)需要(yào)注意(yì),此(cǐ)时(shí)序图(tú)發(fà)了(le)两(liǎng)次(cì)Auto Refresh命令,这(zhè)種(zhǒng)被(bèi)稱为(wèi)背靠背技術(shù);但其实背靠背技術(shù)并不(bù)是(shì)必須的(de),可(kě)以(yǐ)只(zhī)發(fà)一(yī)次(cì)命令。
二(èr)、FPGA实現(xiàn)
1、模块(kuài)架構

2、信(xìn)号(hào)说(shuō)明(míng)
|
信(xìn)号(hào) |
说(shuō)明(míng) |
|
clk |
刷新模块(kuài)工作时(shí)鐘(zhōng)(100MHz) |
|
rst_n |
複位信(xìn)号(hào) |
|
ref_en |
刷新使能(néng)信(xìn)号(hào),由(yóu)仲裁模块(kuài)發(fà)出(chū) |
|
ref_done |
刷新完成(chéng)信(xìn)号(hào) |
|
ref_bus |
刷新數據(jù)總(zǒng)線(xiàn),由(yóu)SDRAM信(xìn)号(hào)組成(chéng) |
|
rt_flag |
計(jì)數到(dào)最(zuì)大值信(xìn)号(hào) |
|
rt_clear |
rt_flag清(qīng)除信(xìn)号(hào) |
|
rt_en |
計(jì)數器使能(néng)信(xìn)号(hào) |
|
init_done |
初始化(huà)完成(chéng)信(xìn)号(hào) |
|
sel_sm |
選擇SDRAM輸出(chū)信(xìn)号(hào) |
|
ref_en |
刷新使能(néng)信(xìn)号(hào) |
|
sdr_bus |
頂层模块(kuài)數據(jù)總(zǒng)線(xiàn) |
|
sdr_clk |
SDRAM工作时(shí)鐘(zhōng) |
|
sdr_cke |
时(shí)鐘(zhōng)使能(néng) |
|
sdr_cs_n |
片(piàn)選信(xìn)号(hào) |
|
sdr_cas_n |
行選通(tòng) |
|
sdr_ras_n |
列選通(tòng) |
|
sdr_we_n |
写使能(néng) |
|
sdr_ba |
bank地(dì)址 |
|
sdr_a |
SDRAM地(dì)址總(zǒng)線(xiàn) |
module sdram_top(
clk ,
sys_rst_n ,
//其它(tā)信(xìn)号(hào),舉例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 rt_flag;
wire rt_clear;
wire rt_en;
wire ref_en;
wire ref_done;
wire sel_sm;
wire [19:0] sdr_bus;
wire [19:0] init_bus;
wire [19:0] ref_bus;
assign {sdr_cke, sdr_cs_n, sdr_ras_n, sdr_cas_n, sdr_we_n, sdr_ba, sdr_a} = sdr_bus;
assign sdr_dqm = 2'b00;
sdram_init sdram_init_inst(
.clk (phy_clk) ,
.rst_n (rst_n) ,
//其它(tā)信(xìn)号(hào),舉例dout
.init_done (init_done) ,
.init_bus (init_bus)
);
arbitrate arbitrate_inst(
.clk(phy_clk),
.rst_n(rst_n),
.rt_en(rt_en),
.rt_flag(rt_flag),
.init_done(init_done),
.ref_done(ref_done),
.ref_en(ref_en),
.sel_sm(sel_sm),
.rt_clear(rt_clear)
);
ref_timer ref_timer_inst(
.clk(phy_clk),
.rst_n(rst_n),
.rt_en(rt_en),
.rt_clear(rt_clear),
.rt_flag(rt_flag)
);
sdram_ref sdram_ref_inst(
.clk(phy_clk),
.rst_n(rst_n),
.ref_en(ref_en),
.ref_done(ref_done),
.ref_bus(ref_bus)
);
sdram_mux sdram_mux_inst(
.clk(phy_clk),
.rst_n(rst_n),
.init_bus(init_bus),
.ref_bus(ref_bus),
.sdr_bus(sdr_bus),
.sel_sm(sel_sm)
);
my_pll PLL(
.areset (~sys_rst_n) ,
.inclk0 (clk) ,
.c0 (phy_clk) ,
.c1 (sdr_clk) ,
.locked (rst_n)
);
endmodule
my_pll模块(kuài)産生(shēng)SDRAM和(hé)控制器工作时(shí)鐘(zhōng)。
輸入(rù)的(de)50M时(shí)鐘(zhōng),經(jīng)过(guò)PLL模块(kuài)後(hòu),会(huì)産生(shēng)两(liǎng)个(gè)100M、相位相差180度(dù)的(de)时(shí)鐘(zhōng)。其中(zhōng)一(yī)个(gè)用(yòng)于(yú)輸出(chū)給(gěi)外(wài)部(bù)SDRAM,另(lìng)一(yī)个(gè)用(yòng)于(yú)其它(tā)模块(kuài)的(de)工作时(shí)鐘(zhōng)。關(guān)于(yú)此(cǐ)模块(kuài)的(de)原理,可(kě)以(yǐ)參考《基于(yú)FPGA的(de)SDRAM控制器設計(jì)—初始化(huà)設計(jì)》中(zhōng)的(de)“SDRAM中(zhōng)心(xīn)对(duì)齊原則”部(bù)分(fēn)進(jìn)行学習。
另(lìng)外(wài),本(běn)模块(kuài)鎖定(dìng)輸入(rù)时(shí)鐘(zhōng)後(hòu),将産生(shēng)LOCK指示信(xìn)号(hào),此(cǐ)信(xìn)号(hào)用(yòng)于(yú)其它(tā)模块(kuài)的(de)複位信(xìn)号(hào)。我(wǒ)们(men)可(kě)以(yǐ)理解(jiě)为(wèi),在(zài)时(shí)鐘(zhōng)稳定(dìng)之前(qián),其它(tā)模块(kuài)都处于(yú)複位狀态。
當初始化(huà)完成(chéng)之後(hòu)仲裁模块(kuài)發(fà)出(chū)rt_en信(xìn)号(hào),當仲裁模块(kuài)收(shōu)刷新定(dìng)时(shí)器計(jì)时(shí)到(dào)最(zuì)大值时(shí)的(de)标(biāo)志信(xìn)号(hào)rt_flag後(hòu),發(fà)出(chū)刷新使能(néng)信(xìn)号(hào)ref_en,并發(fà)出(chū)rt_clear信(xìn)号(hào)。
其代(dài)碼如(rú)下(xià)所(suǒ)示:
module arbitrate(clk, rst_n, rt_en, rt_flag, init_done, ref_done, ref_en, sel_sm, rt_clear);
input clk;
input rst_n;
input rt_flag;
input init_done;
input ref_done;
output reg rt_en;
output reg ref_en;
output reg sel_sm;
output reg rt_clear;
localparam SM_INIT = 1'b0;
localparam SM_REF = 1'b1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
rt_en <= 1'b0;
end
else if(init_done)begin
rt_en <= 1'b1;
end
else begin
rt_en <= rt_en;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
ref_en <= 1'b0;
end
else if(rt_flag)begin
ref_en <= 1'b1;
end
else if(ref_done)begin
ref_en <= 1'b0;
end
else begin
ref_en <= ref_en;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sel_sm <= SM_INIT;
end
else if(init_done)begin
sel_sm <= SM_REF;
end
else begin
sel_sm <= sel_sm;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
rt_clear <= 1'b0;
end
else if(rt_flag)begin
rt_clear <= 1'b1;
end
else begin
rt_clear <= 1'b0;
end
end
endmodule
(3)刷新定(dìng)时(shí)器模块(kuài)
ref_timer即刷新定(dìng)时(shí)器模块(kuài),主(zhǔ)要(yào)是(shì)計(jì)數刷新間(jiān)隔时(shí)間(jiān),當計(jì)數到(dào)最(zuì)大值时(shí)拉高(gāo)rt_flag信(xìn)号(hào)。當收(shōu)到(dào)rt_clear信(xìn)号(hào)时(shí)将rt_flag信(xìn)号(hào)拉低。
代(dài)碼如(rú)下(xià)所(suǒ)示:
module ref_timer(clk, rst_n, rt_en, rt_clear, rt_flag);
input clk;
input rst_n;
input rt_en;
input rt_clear;
output reg rt_flag;
parameter CNT_MAX = 750;
reg [9:0] cnt;
wire add_cnt;
wire end_cnt;
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 = rt_en;
assign end_cnt = add_cnt && cnt==CNT_MAX - 1 ;
always @(posedge clk or negedge rst_n)begin
if (!rst_n)
rt_flag <= 0;
else if (add_cnt && cnt == CNT_MAX - 1)
rt_flag <= 1;
else if (rt_clear)
rt_flag <= 0;
else
rt_flag <= rt_flag;
end
endmodule
module sdram_ref(clk, rst_n, ref_en, ref_done, ref_bus);
input clk;
input rst_n;
input ref_en;
output reg ref_done;
output [19:0] ref_bus;
parameter CNT_MAX = 9;
// parameter TRP = 2;
// parameter TRFC = 7;
parameter NOP = 4'b0111;
parameter PRE = 4'b0010;
parameter REF = 4'b0001;
reg [3:0] cnt;
reg [3:0] sdr_cmd;
reg [1:0] sdr_ba;
reg [12:0] sdr_a;
wire add_cnt;
wire end_cnt;
assign sdr_cke = 1'b1;
assign ref_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 = ref_en;
assign end_cnt = add_cnt && cnt==CNT_MAX - 1 ;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sdr_cmd <= NOP;
end
else if(ref_en && add_cnt && cnt == 0)begin
sdr_cmd <= PRE;
end
else if(add_cnt && cnt == 2 - 1)begin
sdr_cmd <= REF;
end
else begin
sdr_cmd <= NOP;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sdr_a <= 13'd0;
end
else if(ref_en && add_cnt && cnt == 0)begin
sdr_a[10] <= 1'b1;
end
else begin
sdr_a <= 13'd0;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
ref_done <= 1'b0;
end
else if(add_cnt && cnt == CNT_MAX - 1)begin
ref_done <= 1'b1;
end
else begin
ref_done <= 1'b0;
end
end
endmodule
6、選擇模块(kuài)
sdr_mux模块(kuài),由(yóu)于(yú)初始化(huà)模块(kuài)和(hé)刷新模块(kuài)都会(huì)發(fà)出(chū)SDRAM的(de)信(xìn)号(hào),所(suǒ)以(yǐ)需要(yào)一(yī)个(gè)多(duō)路(lù)器来(lái)進(jìn)行選擇。由(yóu)仲裁模块(kuài)的(de)sel_sm来(lái)控制輸出(chū)init_bus信(xìn)号(hào)還(huán)是(shì)ref_bus;當初始化(huà)沒(méi)完成(chéng)时(shí)輸出(chū)init_bus,初始化(huà)完成(chéng)时(shí)輸出(chū)ref_bus。
代(dài)碼如(rú)下(xià)所(suǒ)示:
module sdram_mux(clk, rst_n, init_bus, ref_bus, sdr_bus, sel_sm);
input clk;
input rst_n;
input [19:0] init_bus;
input [19:0] ref_bus;
output reg [19:0] sdr_bus;
input sel_sm;
localparam SM_INIT = 1'b0;
localparam SM_REF = 1'b1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sdr_bus <= init_bus;
end
else if(sel_sm == SM_INIT)begin
sdr_bus <= init_bus;
end
else if(sel_sm == SM_REF)begin
sdr_bus <= ref_bus;
end
else begin
sdr_bus <= sdr_bus;
end
end
endmodule
三(sān)、仿真(zhēn)测試
最(zuì)後(hòu)对(duì)代(dài)碼進(jìn)行仿真(zhēn),仿真(zhēn)文(wén)件(jiàn)參考:sdram_top_tb.v。
modelsim生(shēng)成(chéng)的(de)報告如(rú)下(xià)所(suǒ)示,出(chū)現(xiàn)如(rú)下(xià)LOG信(xìn)息,说(shuō)明(míng)成(chéng)功。

以(yǐ)上(shàng)就(jiù)是(shì)SDRAM控制器的(de)完整設計(jì),更(gèng)多(duō)FPGA資料,關(guān)注明(míng)德揚















