一、加入fifo
在某些特殊的时刻,有些读或写会被忽略掉,不能连续对数据流进行缓存,只能间歇式的读或写 SDRAM 数据,会出现数据存储或读取的遗漏问题。下面针对这个问题设计的 SDRAM 控制器模块进行优化:
这个地方时钟是三路的,一路读SDRAM时钟,读出数据给tft等显示屏,始终为显示屏相同的时钟。着重点为两路,相位差为180度的100M的SDRAM的时钟,这一部分之前看的时序图理解有偏差,参考其他的资料,给出解释:
数据只能在上升沿进行操作,SDRAM本身的时钟上升沿用于进行数据的计时,状态机切换等,SDRAM_clk为写时钟,与本身时钟反向,他的上升沿正处于数据中心,读数更加准确。
首先,设置引入fifo:
根据设计的模块电路图将各个部分端口连线
第二部分是读写数据的地址推进:
//写SDRAM数据的地址,数据写完一次增加一次突发长度
always@(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
wr_sdram_addr <= Wr_addr; //写SDRAM的地址写入写数据起始地址
else if(Wr_load == 1'b1) //写FIFO清零信号
wr_sdram_addr <= Wr_addr;
else if(sd_wdata_done == 1'b1)begin //一次写突发完成标识位
if(wr_sdram_addr == Wr_max_addr-SC_BL) //写数据的地址为写数据最大地址减去一个突发长度(写完最后一个地址了)
wr_sdram_addr <= Wr_addr; //回到写数据起始地址
else
wr_sdram_addr <= wr_sdram_addr + SC_BL; //以突发长度步进
end
else
wr_sdram_addr <= wr_sdram_addr; //维持
end
第三部分设置SDRAM请求信号与使能
//写SDRAM请求信号
assign sd_wr_req = (fifo_rduse >= SC_BL)?1'b1:1'b0; //写FIFO模块可读数据量多余突发长度时,写SDRAM请求
这样写能读出数据,但数据有些不连续,因为根据FIFO存储量判断的,读信号产生有歧义,后面在纠正。
//读SDRAM使能
always@(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
sd_rd <=1'b0;
else if(sd_rd_req) //读SDRAM请求
sd_rd <= 1'b1; //读fifo模块的写使能
else
sd_rd <= 1'b0;
end
其中,将SDRAM的地址{8:0列,21:9行,23:22bank}这样一个24位的输入完成行、列、bank地址输入
二,对加入FIFO后的设计进行再次仿真
initial
begin
Rst_n = 0;
Wr_load = 1;
Rd_load = 1;
Wr_data = 0;
Wr_en = 0;
Rd_en = 0;
#(`CLK100_PERIOD*200+1) //初始化
Rst_n = 1;
Wr_load = 0;
Rd_load = 0; //开始使能
@(posedge sdram_control_top.sdram_control.init_done)
#2000;
//读写数据
Wr_en = 1;
Rd_en = 1;
repeat(2000)
begin
#(`WCLK_PERIOD);
Wr_data = Wr_data + 1;
end
#(`CLK100_PERIOD*2)
Wr_en = 1'b0; //关闭写使能
#50000;
Rd_en = 1'b0; //关闭读使能
#5000;
$stop;
end
仿真结果
看到写入与读取数据一致,设计完成。
本次设计只是能够完成基础性功能,其中部分知识,自己掌握学习的还远远不够,还需要多多对比下其他的教程的设计,拓宽思路,加深理解。