目录
2. FIFO与SDRAM的读写请求的处理?FIFO什么时候读,什么时候写?
3. FIFO与SDRAM的时钟处理?即FIFO的读写时钟如何设置?
用FPGA对SDRAM的控制,存在一个主要缺点:对于数据流只能间歇性的读写,不能连续对数据流进行缓存。在某些特殊的情况,读写请求可能会被忽略,造成数据遗漏。因此在以数据流的形式访问SDRAM时,一般配合FIFO使用。
问题点及分析:(下面对问题的解析限于个人理解,可能不全或者有误的地方,路过的大神还请帮忙指出!感谢~~~)
1. FIFO深度的确定?
需要根据FIFO连续写入的时钟、数据量和速以及读取的时钟进行估计FIFO深度。可以参考:FIFO深度如何确定_赤橙黄绿蓝_新浪博客 (sina.com.cn)
在一般的应用场景中,读写FIFO可能时随机的,即并不是确定的连续一段时间内写入确定的数据量以及有确定的读的速率。因此,在这种场景下,要确定FIFO的深度,需要估计出最大的写入速率以及最小的读出速率,这样才能计算出在写完的时刻,会有多少数据剩余没有读出。
2. FIFO与SDRAM的读写请求的处理?FIFO什么时候读,什么时候写?
FIFO写(FIFO往SDRAM中写),在FIFO的存放数量大于等于burst长度,就拉高写使能;
FIFO读(FIFO从SDRAM中读),当FIFO的存放数量小于所能存放数量的一半时,拉高读使能;
在往FIFO中写以及从FIFO中读取数据时,需要判断FIFO的满、空标志位。
//只要FIFO不在清空阶段,且目前FIFO中数据量大于突发长度,FIFO就可以继续往SDRAM中写入数据
assign sd_wr_req=(!wr_load)&&(fifo_rduse>=SC_BL)? 1'b1:1'b0;
//只要FIFO不在清空阶段,且目前FIFO中数据量小于FIFO一般的存储量,FIFO就可以继续从SDRAM中读取数据
assign sd_rd_req=(!rd_load)&&(fifo_wruse[7]==1'b0)? 1'b1:1'b0;
3. FIFO与SDRAM的时钟处理?即FIFO的读写时钟如何设置?
FIFO主要应用于跨时钟处理,以及数据缓存。FIFO的写入时钟一般取决于连接的模块的时钟,而读时钟可以根据SDRAM的需求时钟以及写时钟确定。
当FIFO读写时钟差别很大,可以参考:今天华为面试题:异步FIFO读时钟是写时钟的100倍,或者写是读的100倍会出现什么问题? - 第2页 - FPGA/ASIC/IC前端设计 - EETOP 创芯网论坛 (原名:电子顶级开发网) ,觉得挺有意思的。建议自己动手试试。
4. SDRAM的读写数据和地址如何处理?
对于数据流的存取,主控制器只需要提供存取在SDRAM的起始地址和最大地址即可。FPGA代码设计根据SDRAM的burst length来自动生成每次读写SDRAM的地址。然后再在其基础上,生成SDRAM模块需要的行、列、BANK地址。代码中,只要往SDRAM中读写一个突发长度的数据完成,地址就自动+SC_BL。
以下代码实现对SDRAM顺序读写数据。
//写SDRAM的地址,写完一次增加一个突发长度
always @(posedge clk or negedge rst_n)
begin
if(~rst_n) wr_sdram_addr<=wr_addr; //写起始地址
else if(wr_load) wr_sdram_addr<=wr_addr; //对wr_fifo清零后,重新开始写
else if(sd_wrdata_done) //SDRAM一次突发写完毕
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的地址,读完一次增加一个突发长度
always @(posedge clk or negedge rst_n)
begin
if(~rst_n) rd_sdram_addr<=rd_addr; //读起始地址
else if(rd_load) rd_sdram_addr<=rd_addr; //对rd_fifo清零后,重新开始读
else if(sd_rddata_done) //SDRAM一次突发读完毕
begin
if(rd_sdram_addr==rd_max_addr-SC_BL) rd_sdram_addr<=rd_addr;
else rd_sdram_addr<=rd_sdram_addr+SC_BL;
end
else rd_sdram_addr<=rd_sdram_addr;
end
//SDRAM的行地址
always @(posedge clk or negedge rst_n)
begin
if(~rst_n) sd_raddr<=13'd0;
else if (sd_wr_req) sd_raddr<=wr_sdram_addr[21:9];
else if (sd_rd_req) sd_raddr<=rd_sdram_addr[21:9];
else sd_raddr<=sd_raddr;
end
//SDRAM的列地址
always @(posedge clk or negedge rst_n)
begin
if(~rst_n) sd_caddr<=13'd0;
else if (sd_wr_req) sd_caddr<=wr_sdram_addr[8:0];
else if (sd_rd_req) sd_caddr<=rd_sdram_addr[8:0];
else sd_caddr<=sd_caddr;
end
//SDRAM的bank地址
always @(posedge clk or negedge rst_n)
begin
if(~rst_n) sd_baddr<=13'd0;
else if (sd_wr_req) sd_baddr<=wr_sdram_addr[23:22];
else if (sd_wr_req) sd_baddr<=rd_sdram_addr[23:22];
else sd_baddr<=sd_baddr;
end
代码的仿真及调试情况,下篇文章继续总结。