【FPGA】FPGA sdram读写实现
文章目录
- 一、状态机设计
- 二、代码部分
- 1.==sdram_interface.v==
- 2.==sdram_control==
- 3.==top.v==
- 3.其他模块
- 三、仿真验证
- 四、上板验证
- 五、总结
想看我之前关于sdram的看我之前的博客
【FPGA】sdram接口实现
一、状态机设计
控制模块的状态机也就idle,read,write,done这几个基本的状态
我发现现在写这些模块,没有状态机不舒服
二、代码部分
1.sdram_interface.v
【FPGA】sdram接口实现
2.sdram_control
module sdram_control(input clk,input clk_100m,input rst_n,//sdram接口和controlinput [15:0] din,// 从sdram来的数据input din_vld,output [15:0] dout,// 给sdram的数据output [23:0] brc_address,// bank row col 地址 2+13+9output reg rd_req,// 读请求output reg wr_req,// 写请求input busy,// 接口busyinput ack,// 接口回应//sdram control和用户接口 串口input rd_en,input [7:0] rx_byte,input rx_byte_vld,output [7:0] tx_byte,output tx_byte_vld,input tx_busy
);parameter BURST_MAX_LENGTH = 24'h1fffff,BURST_LENGTH = 8;localparam IDLE = 4'b0001,READ = 4'b0010,WRITE = 4'b0100,DONE = 4'b1000;reg [3:0] state_c;
reg [3:0] state_n;wire idle2read ;
wire idle2write;
wire read2done ;
wire write2done;
wire done2idle ;// 读地址计数器
reg [23:0] cnt_rdadd;
wire add_cnt_rdadd;
wire end_cnt_rdadd;// 写地址计数器
reg [23:0] cnt_wradd;
wire add_cnt_wradd;
wire end_cnt_wradd;// 读写标志
// 0代表写,1代表读
reg rw_flag;// 寄存接口响应ack 打一拍
reg ack_r;// 检测ack的下降沿
wire ack_nedge;// 写fifo
wire wrfifo_rdreq ;
wire wrfifo_wrreq ;
wire [15:0] wrfifo_qout ;
wire wrfifo_rdempty;
wire wrfifo_rdfull ;
wire [11:0] wrfifo_rdusedw;
wire wrfifo_wrempty;
wire wrfifo_wrfull ;
wire [12:0] wrfifo_wrusedw; // 读fifo
wire rdfifo_rdreq ;
wire rdfifo_wrreq ;
wire [7:0] rdfifo_qout ;
wire rdfifo_rdempty;
wire rdfifo_rdfull ;
wire [13:0] rdfifo_rdusedw;
wire rdfifo_wrempty;
wire rdfifo_wrfull ;
wire [12:0] rdfifo_wrusedw;always @(posedge clk or negedge rst_n)begin if(!rst_n)beginstate_c <= IDLE; end else beginstate_c <= state_n;end
endalways @(*)begin case (state_c)IDLE :begin if(idle2read)beginstate_n = READ;endelse if(idle2write)beginstate_n = WRITE;endelse beginstate_n = state_c;end endREAD :begin if(read2done)beginstate_n = DONE;endelse beginstate_n = state_c;end endWRITE :begin if(write2done)beginstate_n = DONE;endelse beginstate_n = state_c;end endDONE :begin if(done2idle)beginstate_n = IDLE;endelse beginstate_n = state_c;end enddefault: state_n = IDLE;endcase
endassign idle2read = state_c == IDLE && (~busy) && (rd_en);
assign idle2write = state_c == IDLE && (~busy) && (wrfifo_rdusedw >= BURST_LENGTH);
assign read2done = state_c == READ && (ack_nedge);
assign write2done = state_c == WRITE && (ack_nedge);
assign done2idle = state_c == DONE && (1'b1);// rw_flag读写标志
// 写一次读一次
// 0代表写,1代表读
// always @(posedge clk or negedge rst_n)begin
// if(!rst_n)begin
// rw_flag <= 1'b0;
// end
// else if(idle2write)begin
// rw_flag <= 1'b0;
// end
// else if(write2done)begin
// rw_flag <= 1'b1;
// end
// else if(idle2read)begin
// rw_flag <= 1'b1;
// end
// else if(read2done)begin
// rw_flag <= 1'b0;
// end
// end// 接口响应ack 打一拍
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginack_r <= 0;end else begin ack_r <= ack;end
end// 检测ack的下降沿
assign ack_nedge = ~ack & ack_r;// 读地址计数器
always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_rdadd <= 0;end else if(add_cnt_rdadd)begin if(end_cnt_rdadd)begin cnt_rdadd <= 0;endelse begin cnt_rdadd <= cnt_rdadd + BURST_LENGTH;end endelse begincnt_rdadd <= cnt_rdadd;end
end assign add_cnt_rdadd = read2done;
assign end_cnt_rdadd = add_cnt_rdadd && cnt_rdadd == BURST_MAX_LENGTH - BURST_LENGTH;// 写地址计数器
always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_wradd <= 0;end else if(add_cnt_wradd)begin if(end_cnt_wradd)begin cnt_wradd <= 0;endelse begin cnt_wradd <= cnt_wradd + BURST_LENGTH;end endelse begincnt_wradd <= cnt_wradd;end
end assign add_cnt_wradd = write2done;
assign end_cnt_wradd = add_cnt_wradd && cnt_wradd == BURST_MAX_LENGTH - BURST_LENGTH;// 读写请求
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginrd_req <= 0;wr_req <= 0;end else if(idle2write)begin wr_req <= 1'b1;end else if(idle2read)begin rd_req <= 1'b1;end else beginwr_req <= 1'b0;rd_req <= 1'b0;end
end// 写fifo
// 从串口接收数据发给sdram
wrfifo wrfifo_inst (.data ( rx_byte ),.rdclk ( clk_100m ),.rdreq ( wrfifo_rdreq ),.wrclk ( clk ),.wrreq ( wrfifo_wrreq ),.q ( wrfifo_qout ),.rdempty( wrfifo_rdempty ),.rdfull ( wrfifo_rdfull ),.rdusedw( wrfifo_rdusedw ),.wrempty( wrfifo_wrempty ),.wrfull ( wrfifo_wrfull ),.wrusedw( wrfifo_wrusedw ));assign wrfifo_rdreq = (~wrfifo_rdempty) && ack && (state_c == WRITE);
assign wrfifo_wrreq = (~wrfifo_wrfull) && rx_byte_vld;
assign dout = wrfifo_qout;// 读fifo
// 从sdram接收数据发给串口
rdfifo rdfifo_inst (.data ( din ),.rdclk ( clk ),.rdreq ( rdfifo_rdreq ),.wrclk ( clk_100m ),.wrreq ( rdfifo_wrreq ),.q ( rdfifo_qout ),.rdempty( rdfifo_rdempty ),.rdfull ( rdfifo_rdfull ),.rdusedw( rdfifo_rdusedw ),.wrempty( rdfifo_wrempty ),.wrfull ( rdfifo_wrfull ),.wrusedw( rdfifo_wrusedw ));assign rdfifo_rdreq = (~rdfifo_rdempty) && (~tx_busy);
assign rdfifo_wrreq = (~rdfifo_wrfull) && (state_c == READ) && din_vld;
assign tx_byte = rdfifo_qout;// bank row col 地址
assign brc_address = (state_c == WRITE)?cnt_wradd:((state_c == READ)?cnt_rdadd:0);
// assign brc_address = 24'b0;// 读请求
// assign rd_req = (state_c == READ) ? 1 : 0;// 写请求
// assign wr_req = (state_c == WRITE) ? 1 :0;// 串口数据有效
assign tx_byte_vld = rdfifo_rdreq;endmodule
3.top.v
module top(input clk,input rst_n,input [0:0] key_in,// 串口uartinput uart_rx,output uart_tx,// sdramoutput sdram_clk ,output sdram_cke ,output sdram_cs_n ,output [1:0] sdram_bank ,output [12:0] sdram_address,output sdram_ras_n ,output sdram_cas_n ,output sdram_we_n ,output [1:0] sdram_dqm ,inout [15:0] sdram_dq
);// 中间信号
wire clk_100m;
wire clk_100m_75deg;
wire key_out;
wire [15:0] rx_byte;
wire rx_byte_vld;
wire [15:0] tx_byte;
wire tx_byte_vld;
wire tx_busy;
wire [15:0] sdram_din;
wire sdram_din_vld;
wire [15:0] sdram_dout;
wire [23:0] brc_address;
wire rd_req;
wire wr_req;
wire busy;
wire ack;
wire [15:0] sdram_dq_in ;
wire [15:0] sdram_dq_out ;
wire sdram_dq_out_en;assign sdram_dq_in = sdram_dq;
assign sdram_dq = sdram_dq_out_en?sdram_dq_out:16'hzzzz;// pll锁相环
pll pll_inst (.areset ( ~rst_n ),.inclk0 ( clk ),.c0 ( clk_100m ),.c1 ( clk_100m_75deg ),.locked ( locked_sig ));// 串口接收模块
uart_rx u_uart_rx(/* input */.clk (clk ),/* input */.rst_n (rst_n ),/* input */.baud_sel (1),// 波特率的选择/* input */.din (uart_rx ),// 串口接收模块接收到主机来的1bit的数据/* output [7:0] */.dout (rx_byte ),// 串口接收模块串并转换的数据发送/* output */.dout_vld (rx_byte_vld)
);uart_tx u_uart_tx(/* input */.clk (clk ),/* input */.rst_n (rst_n ),/* input */.baud_sel (1),// 波特率的选择/* input [7:0] */.din (tx_byte ),// 串并转换的数据/* input */.din_vld (tx_byte_vld ),// 串并转换的数据有效/* output */.dout (uart_tx ),// 发送模块发送的1bit数据/* output */.busy (tx_busy ) // 发送模块忙标志
);key_filter u_key_filter(/* input */.clk (clk ),/* input */.rst_n (rst_n ),/* input [KEY_W-1:0] */.key_in (key_in ), /* output reg [KEY_W-1:0] */.key_out (key_out)
);sdram_control u_sdram_control(/* input */.clk (clk ),/* input */.clk_100m (clk_100m ),/* input */.rst_n (rst_n ),/* input [15:0] */.din (sdram_din ),// 从sdram来的数据/* input */.din_vld (sdram_din_vld),/* output [15:0] */.dout (sdram_dout ),// 给sdram的数据/* output [23:0] */.brc_address (brc_address),// bank row col 地址 2+13+9/* output */.rd_req (rd_req ),// 读请求/* output */.wr_req (wr_req ),// 写请求/* input */.busy (busy ),// 接口busy/* input */.ack (ack ),// 接口回应/* input */.rd_en (key_out ),/* input [7:0] */.rx_byte (rx_byte ),/* input */.rx_byte_vld (rx_byte_vld),/* output [7:0] */.tx_byte (tx_byte ),/* output */.tx_byte_vld (tx_byte_vld),/* input */.tx_busy (tx_busy )
);sdram_interface u_sdram_interface(/* input */.clk (clk_100m ),/* input */.sclk (clk_100m_75deg ),/* input */.rst_n (rst_n ),/* input [15:0] */.din (sdram_dout ),// 从wrfifo来的数据/* output [15:0] */.dout (sdram_din ),// 给rdfifo的数据/* output */.dout_vld (sdram_din_vld ),/* input [23:0] */.brc_address (brc_address ),// bank row col 地址 2+13+9/* input */.rd_req (rd_req ),// 读请求/* input */.wr_req (wr_req ),// 写请求/* output */.busy (busy ),// 接口busy/* output */.ack (ack ),// 接口回应/* output */.sdram_clk (sdram_clk ),/* output */.sdram_cke (sdram_cke ),/* output */.sdram_cs_n (sdram_cs_n ),/* output [1:0] */.sdram_bank (sdram_bank ),/* output [12:0] */.sdram_address (sdram_address ),/* output */.sdram_ras_n (sdram_ras_n ),/* output */.sdram_cas_n (sdram_cas_n ),/* output */.sdram_we_n (sdram_we_n ),/* output [1:0] */.sdram_dqm (sdram_dqm ),/* input [15:0] */.sdram_dq_in (sdram_dq_in ),/* output [15:0] */.sdram_dq_out (sdram_dq_out ),/* output */.sdram_dq_out_en (sdram_dq_out_en)
);endmodule
3.其他模块
串口发送模块
串口接收模块
按键消抖模块
三、仿真验证
这里我直接用signal tap没啥仿真
四、上板验证
我的突发长度是8
因为串口是8位数据,sdram是16位数据
五、总结
这个sdram我又是写了一周,一直看手册,一直漏条件,一直修改,本来想在sdram控制模块加个读写仲裁的,发现不行,嫌麻烦的我就直接上手按键了,我的fpga学习周期也快结束了,期望能在结束前写完全部的项目。
【FPGA】FPGA sdram读写实现相关推荐
- 【FPGA】基于Avalon_MM接口的SDRAM读写
1.SDRAM 1.1 SDRAM简介 C4开发板上的SDRAM芯片是海力士生产,有256Mbits容量. SDRAM是同步动态随机存储器(存储阵列不断刷新). SDRAM寻址基本原理:行列寻址 SD ...
- FPGA之SDRAM控制器设计(三)
FPGA之SDRAM控制器设计(三):写 由于已经涉及了上电刷新,写三个大的状态转移,先把状态转移图给出.主控状态转移图是基于手册上描述来的.在代码注释中会给出每个状态的意义解释. 写时序图 写状态转 ...
- 基于FPGA的SDRAM控制器设计(1)
基于FPGA的SDRAM初始化配置 SDRAM简述 SDRAM的引脚及作用 SDRAM初始化时序控制 SDRAM上电时序代码 SDRAM测试模块的代码 仿真测试结果 参考文献 总结 SDRAM简述 S ...
- 基于FPGA的SDRAM控制器设计(2)
基于FPGA的SDRAM的自刷新操作 SDRAM自刷新简述 SDRAM自刷新时序图 SDRAM自刷新代码 仿真模块的代码 仿真结果测试 参考文献 总结 SDRAM自刷新简述 SDRAM作为一个RAM并 ...
- FPGA驱动SDRAM
一.实验任务 实现PC向FPGA发送数据保存进SDRAM,再通过按键控制读出SDRAM中的数据发送给PC端,实现数据回环. 二.SDRAM介绍 同步动态随机存取内存(synchronous dynam ...
- 基于FPGA的EEPROM读写(IIIC 接口协议)
笔者使用的是黑金AX309的开发板,其板载了一块有一个 IIC 接口的 EEPROM 芯片 24LC04(data sheet),容量大小为 4Kbit.这里先简单总结下一般的存储器件,然后介绍IIC ...
- FPGA控制DDR读写(AXI4总线接口)
FPGA控制DDR读写(AXI4总线接口) 范围 本文适用于FPGA控制DDR读写 MIG核 MIG信号注释 DDR型号为 MT41K256M16TW-107 下面是MIG IP核的相关信号 图2.1 ...
- 通过vivado工具实现zynq的FPGA内部RAM读写
通过vivado工具实现zynq的FPGA内部RAM读写(调用vivado自带IP核),从新建工程到仿真并下载到FPGA开发板中,通过vivado自带的ILA逻辑分析仪查看读写数据是否正确,包含详细步 ...
- 基于FPGA的SDRAM控制器设计(二)
基于FPGA的SDRAM控制器设计(二) 1. SDRAM理论基础 2. SDRAM初始化模块以及仿真 3.TOP模块的仲裁机制 4. SDRAM刷新模块代码以及仿真 5.代码 6.参考资料 1. S ...
最新文章
- live555点播服务器流程深入分析(一)
- vue 嵌套表格组件_vue+element中表格嵌套怎么做?
- 【C 语言】内存四区原理 ( 栈内存与堆内存对比示例 | 函数返回的堆内存指针 | 函数返回的栈内存指针 )
- 深度解析两种信用评估模型
- MySql之DDL操作创建表(添加主键, 外键约束以及基本的数据类型)
- 前端学习(3233):高阶函数函数柯里化案例
- 教你一招用python发送QQ邮件
- Socket编程实践(6) --TCP服务端注意事项
- Kubernetes[3]-Server
- .h5是什么文件_PPT转H5丨再也不用担心忘带U盘怎么办了
- /usr 的由来及/usr目录结构 [转]
- ON1 Photo RAW 2022 for Mac(ps/lr滤镜raw图像编辑器)
- 安卓模拟器安装教程_安卓模拟器测试总结!究哪个最流畅?内附模拟换IP教程...
- We discovered one or more bugs in your app when reviewed on iPhone and iPad running iOS 14.1
- SiT3808:1 -80MHz 单端压控振荡器VCXO
- 王树尧老师运筹学课程笔记 02 高等数学基础
- 一张图,区分NPN于PNP型三极管的工作原理
- 爱你的人和你爱的人 你选哪个?
- matlab实验报告井字棋,有偿井字棋游戏300+
- 3乘3魔方第四步_3乘3魔方的解法都有哪些?(讲具体点,怎么具体呢?有公式步骤吧!)?...