当前位置:网站首页>02-SDRAM:自动刷新
02-SDRAM:自动刷新
2022-07-29 20:47:00 【刘颜儿】
SDRAM自动刷新模块
- cnt_7: 自动刷新是周期性的,因此需要时钟去重复计数,计满后就可以发出自动刷新请求信号给仲裁模块(依赖 init_end,计满清零)
- auto_ref_req: 传给仲裁模块的自动刷新请求信号,计数器加满拉高,得到内部应答后拉低(依赖计数器 cnt_7、auto_ref_ack)
- auto_ref_en:
- auto_ref_ack: 当状态跳转到预充电 ATREF_PRE,内部产生应答信号(依赖 ATREF_PRE)
- state
- cnt_cmd: 计数器,用来给2个等待时间计数 (依赖 cnt_cmd_reset)
- cnt_cmd_reset: 上一个计数器的清零信号 (依赖计满信号:trp_end、trfc_end)
- trp_end、trfc_end: 自家延时结束的信号(依赖 状态)
- cnt_ref: 自动刷新的次数,至少需要2次自动刷新(依赖状态 ATREF_AR 、 ATREF_IDLE)
设计文件
// SDRAM自动刷新模块
// 1. cnt_7: 自动刷新是周期性的,因此需要时钟去重复计数,计满后就可以发出自动刷新请求信号给仲裁模块(依赖 init_end,计满清零)
// 2. auto_ref_req: 传给仲裁模块的自动刷新请求信号,计数器加满拉高,得到内部应答后拉低(依赖计数器 cnt_7、auto_ref_ack)
// 3. auto_ref_en:
// 4. auto_ref_ack: 当状态跳转到预充电 ATREF_PRE,内部产生应答信号(依赖 ATREF_PRE)
// 5. state
// 6. cnt_cmd: 计数器,用来给2个等待时间计数 (依赖 cnt_cmd_reset)
// 7. cnt_cmd_reset: 上一个计数器的清零信号 (依赖计满信号:trp_end、trfc_end)
// 8. trp_end、trfc_end: 自家延时结束的信号(依赖 状态)
// 9. cnt_ref: 自动刷新的次数,至少需要2次自动刷新(依赖状态 ATREF_AR 、 ATREF_IDLE)
module sdram_auto_ref(
input clk,
input rst_n,
input init_end,//初始化模块传入
input auto_ref_en,//仲裁模块传入,仲裁模块用来判断当前SDRAM是否可以自动刷新
output reg auto_ref_req,//传给仲裁模块(要得到仲裁模块传来的刷新使能信号auto_ref_en才能开始自动刷新)
output reg [3:0] auto_ref_cmd,//SDRAM命令,组成{CS#,RAS#,CAS#,WE#}
output [1:0] auto_ref_bank,//BANK地址,共4个BANK
output [12:0] auto_ref_addr,//SDRAM地址总线
output auto_ref_end//初始化完成信号,初始化完成后拉高,其他时间保持低电平
);
//==========================================parameter===========================================================
//状态机
localparam ATREF_IDLE = 3'b000, //自动刷新初始状态
ATREF_PRE = 3'b001, //预充电状态
ATREF_TRP = 3'b011, //预充电等待状态
ATREF_AR = 3'b010, //自动刷新状态
ATREF_TRFC = 3'b110, //自动刷新等待状态
ATREF_END = 3'b111; //自动刷新结束状态
parameter MAX_CNT_700 = 12'd700; //计算出来是 7812ns,但是仲裁模块需要时间去给出auto_ref_en,需要花费时间,因此这里使用7000ns
parameter MAX_REF_TIME = 2'd2;
//等待时间参数定义
localparam TRP = 3'd2 , //发送预充电指令后进行下一个操作需要等待的时间
TRFC = 3'd7 ; //发送自动刷新指令后进行下一个操作需要等待的时间
//命令指令参数
localparam PRECHARGE = 4'b0010 , //预充电指令
AT_REF = 4'b0001 , //自动刷新指令
NOP = 4'b0111 ; //空操作指令
//==========================================reg=================================================================
reg [5:0] state;
reg [5:0] next_state;
reg [3:0] cnt_cmd;
reg [11:0] cnt_7;//64_000/2^13=7.8125us,于是需要10ns的时钟计数7_00次
reg [1:0] cnt_ref;
//==========================================wire=================================================================
wire auto_ref_ack;
wire trp_end;
wire trfc_end;
wire cnt_cmd_reset;
//==========================================assign=================================================================
// 内部应答信号
assign auto_ref_ack = (state == ATREF_PRE) ? 1'd1:1'd0;
assign trp_end = ((state == ATREF_TRP) && (cnt_cmd == TRP-1)) ? 1'd1:1'd0;
assign trfc_end = ((state == ATREF_TRFC) && (cnt_cmd == TRFC-1))? 1'd1:1'd0;
assign cnt_cmd_reset = ((state == ATREF_IDLE) || (state == ATREF_END) || trp_end || trfc_end) ? 1'd1:1'd0;
assign auto_ref_bank = 2'd11;
assign auto_ref_addr = 13'h1fff;
assign auto_ref_end = (state == ATREF_END)?1'd1:1'd0;
//==========================================always=================================================================
// 自动刷新周期计数器
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n )begin
cnt_7 <= 12'd0;
end
else if(init_end)// 初始化成功后,才开始计数
if(cnt_7 == MAX_CNT_700)begin
cnt_7 <= 12'd0;
end
else
cnt_7 <= cnt_7 + 12'd1;
else
cnt_7 <= cnt_7;
end
// 请求信号
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n )begin
auto_ref_req <= 1'd0;
end
else if(cnt_7 == MAX_CNT_700 - 1)begin
auto_ref_req <= 1'd1;
end
else if(auto_ref_ack)
auto_ref_req <= 1'd0;
else
auto_ref_req <= auto_ref_req;
end
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n )begin
cnt_cmd <= 4'd0;
end
else if(cnt_cmd_reset)begin
cnt_cmd <= 4'd0;
end
else
cnt_cmd <= cnt_cmd + 4'd1;
end
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n )begin
cnt_ref <= 2'd0;
end
else if(state == ATREF_AR)begin
cnt_ref <= cnt_ref + 2'd1;
end
else if(state == ATREF_IDLE)
cnt_ref <= 2'd0;
else
cnt_ref <= cnt_ref ;
end
//==========================================状态机=================================================================
// 第一段
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n )begin
state <= ATREF_IDLE;
end
else
state <= next_state;
end
//第二段
[email protected](*)begin
case(state)
ATREF_IDLE:
if(init_end && auto_ref_en)//auto_ref_ack
next_state = ATREF_PRE;
else
next_state = ATREF_IDLE;
ATREF_PRE :next_state = ATREF_TRP;
ATREF_TRP :
if(trp_end)
next_state = ATREF_AR;
else
next_state = ATREF_TRP;
ATREF_AR :next_state = ATREF_TRFC;
ATREF_TRFC:
if(trfc_end)
if(cnt_ref == MAX_REF_TIME)
next_state = ATREF_END;
else
next_state = ATREF_AR;
else
next_state = ATREF_TRFC;
ATREF_END :next_state = ATREF_IDLE;
default:next_state = ATREF_IDLE;
endcase
end
// 第三段
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n )begin
auto_ref_cmd <= NOP;
end
else
case(state)
ATREF_IDLE : auto_ref_cmd <= NOP;
ATREF_PRE : auto_ref_cmd <= PRECHARGE;
ATREF_TRP : auto_ref_cmd <= NOP;
ATREF_AR : auto_ref_cmd <= AT_REF;
ATREF_TRFC : auto_ref_cmd <= NOP;
ATREF_END : auto_ref_cmd <= NOP;
default:auto_ref_cmd <= NOP;
endcase
end
endmodule
测试文件
`timescale 1ns/1ns
// Author : EmbedFire
// Create Date : 2019/08/25
// Module Name : tb_sdram_init
// Project Name : uart_sdram
// Target Devices: Altera EP4CE10F17C8N
// Tool Versions : Quartus 13.0
// Description : SDRAM初始化模块仿真
//
// Revision : V1.0
// Additional Comments:
//
// 实验平台: 野火_征途Pro_FPGA开发板
// 公司 : http://www.embedfire.com
// 论坛 : http://www.firebbs.cn
// 淘宝 : https://fire-stm32.taobao.com
module tb_sdram_auto_ref();
//********************************************************************//
//****************** Internal Signal and Defparam ********************//
//********************************************************************//
//wire define
//clk_gen
wire clk_50m ; //PLL输出50M时钟
wire clk_100m ; //PLL输出100M时钟
wire clk_100m_shift ; //PLL输出100M时钟,相位偏移-30deg
wire locked ; //PLL时钟锁定信号
wire rst_n ; //复位信号,低有效
//sdram_init
wire [3:0] init_cmd ; //初始化阶段指令
wire [1:0] init_ba ; //初始化阶段L-Bank地址
wire [12:0] init_addr ; //初始化阶段地址总线
wire init_end ; //初始化完成信号
wire auto_ref_req ;
wire [3:0] auto_ref_cmd ;
wire [1:0] auto_ref_bank;
wire [12:0] auto_ref_addr;
wire auto_ref_end ;
//sdram
wire [3:0] sdram_cmd ; //SDRAM操作指令
wire [1:0] sdram_bank ; //SDRAM L-Bank地址
wire [12:0] sdram_addr ; //SDRAM地址总线
//reg define
reg clk_c1 ; //系统时钟
reg sys_rst_n ; //复位信号
reg auto_ref_en;
//defparam
//重定义仿真模型中的相关参数
defparam sdram_model_plus_inst.addr_bits = 13; //地址位宽
defparam sdram_model_plus_inst.data_bits = 16; //数据位宽
defparam sdram_model_plus_inst.col_bits = 9; //列地址位宽
defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024; //L-Bank容量
//********************************************************************//
//**************************** Clk And Rst ***************************//
//********************************************************************//
//时钟、复位信号
initial
begin
clk_c1 = 1'b1 ;
sys_rst_n <= 1'b0 ;
#200
sys_rst_n <= 1'b1 ;
end
always #10 clk_c1 = ~clk_c1;
//rst_n:复位信号
assign rst_n = sys_rst_n & locked;
//atref_en:自动刷新使能
[email protected](posedge clk_100m or negedge rst_n)begin
if(rst_n == 1'b0)
auto_ref_en <= 1'b0;
else if((init_end == 1'b1) && (auto_ref_req == 1'b1))
auto_ref_en <= 1'b1;
else if(auto_ref_end == 1'b1)
auto_ref_en <= 1'b0;
end
//sdram_cmd,sdram_ba,sdram_addr
assign sdram_cmd = (init_end == 1'b1) ? auto_ref_cmd : init_cmd;
assign sdram_bank = (init_end == 1'b1) ? auto_ref_bank : init_ba;
assign sdram_addr = (init_end == 1'b1) ? auto_ref_addr : init_addr;
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------- clk_gen_inst -------------
clk_gen clk_gen_inst (
.inclk0 (clk_c1 ),
.areset (~sys_rst_n ),
.c0 (clk_50m ),
.c1 (clk_100m ),
.c2 (clk_100m_shift ),
.locked (locked )
);
//------------- sdram_init_inst -------------
sdram_initial sdram_initial_inst(
.clk (clk_100m ),
.rst_n (rst_n ),
.init_cmd (init_cmd ),
.init_bank (init_ba ),
.init_addr (init_addr ),
.init_end (init_end )
);
sdram_auto_ref sdram_auto_ref_inst(
.clk (clk_100m ),
.rst_n (rst_n ),
.init_end (init_end ),
.auto_ref_en (auto_ref_en),
.auto_ref_req (auto_ref_req ),
.auto_ref_cmd (auto_ref_cmd ),
.auto_ref_bank (auto_ref_bank ),
.auto_ref_addr (auto_ref_addr ),
.auto_ref_end (auto_ref_end )
);
//-------------sdram_model_plus_inst-------------
sdram_model_plus sdram_model_plus_inst(
.Dq ( ),
.Addr (sdram_addr ),
.Ba (sdram_bank ),
.Clk (clk_100m_shift ),
.Cke (1'b1 ),
.Cs_n (sdram_cmd[3] ),
.Ras_n (sdram_cmd[2] ),
.Cas_n (sdram_cmd[1] ),
.We_n (sdram_cmd[0] ),
.Dqm (2'b0 ),
.Debug (1'b1 )
);
//------------------------------------------------
//-- 状态机名称查看器
//------------------------------------------------
reg [79:0] name_state_cur; //每字符8位宽,这里取最多10个字符80位宽
always @(*) begin
case(sdram_auto_ref_inst.state)
3'b000: name_state_cur = "ATREF_IDLE";
3'b001: name_state_cur = "ATREF_PRE ";
3'b011: name_state_cur = "ATREF_TRP ";
3'b010: name_state_cur = "ATREF_AR ";
3'b110: name_state_cur = "ATREF_TRFC";
3'b111: name_state_cur = "ATREF_END ";
default: name_state_cur = "ATREF_IDLE";
endcase
end
endmodule
窗口打印信息
边栏推荐
- The sword refers to Offer II 097. Number of subsequences
- C#笔记 之 Oracle.ManagedDataAccess包的安装及配置
- 高通WLAN框架学习(31)-- Power save
- 怎么实现您的个人知识库?
- 《张卫国的夏天》欢乐来袭,黄磊、刘奕君携手演绎“冤种”兄弟
- 南华早报 | 助力亚洲最具公信力报章实现AD域自动化管理
- 回归——岭回归
- 容器网络硬核技术内幕 (26) 知微知彰,知柔知刚 (下)
- Fully automated machine learning modeling!The effect hangs the primary alchemist!
- 240. 搜索二维矩阵 II
猜你喜欢
A dish hold up valuations billions of mt. Pickled fish, can move beyond the edge food safety?
R language for airbnb data nlp text mining, geography, word cloud visualization, regression GAM model, cross-validation analysis
第3章业务功能开发(线索关联市场活动,插入数据并查询)
The difference between analog, digital and switching
336. 回文对
2022了你还不会『低代码』?数据科学也能玩转Low-Code啦!
高通WLAN框架学习(31)-- Power save
促进二十一世纪创客教育的新发展
.NET 6.0中使用Identity框架实现JWT身份认证与授权
1. Promise usage in JS, 2. The concept and usage of closures, 3. The difference between the four methods and areas of object creation, 4. How to declare a class
随机推荐
微博账号奇葩逻辑产品设计
Panorama Tutorial丨How to shoot sunrise and sunset scenes in VR panoramic shooting?
GET_ENTITYSET Method Implementation Guide for SAP ABAP OData Service Data Provider Class
微信小程序 31 分包机制
分布式之基石: 可靠性——What a tangled web we weave
MySQL - Design game user information table
240. 搜索二维矩阵 II
Huawei laptop keyboard locked (how does the laptop keyboard light up)
怎么实现您的个人知识库?
容器网络硬核技术内幕 (小结-下)
根据昵称首字母生成头像
Use the PostgreSQL GRANT command to modify permissions on various database objects
Bug fix: Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255]
LeetCode 593 有效的正方形[数学] HERODING的LeetCode之路
基于PaddleSpeech搭建个人语音听写服务
Second Best PyTorch Beginner Course; Thesis Writing Guide; Using µGo to Develop a Mini Compiler; Super Efficient Use of Transformer's Extension Library; Frontier Papers | ShowMeAI News Daily
WPF 实现抽屉菜单
Break the rules!MongoDB introduces SQL?
指定宽度截取字符串
MySQL数据查询 - 简单查询