文章目录

  • 一、状态机设计
  • 二、代码部分
    • 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读写实现相关推荐

  1. 【FPGA】基于Avalon_MM接口的SDRAM读写

    1.SDRAM 1.1 SDRAM简介 C4开发板上的SDRAM芯片是海力士生产,有256Mbits容量. SDRAM是同步动态随机存储器(存储阵列不断刷新). SDRAM寻址基本原理:行列寻址 SD ...

  2. FPGA之SDRAM控制器设计(三)

    FPGA之SDRAM控制器设计(三):写 由于已经涉及了上电刷新,写三个大的状态转移,先把状态转移图给出.主控状态转移图是基于手册上描述来的.在代码注释中会给出每个状态的意义解释. 写时序图 写状态转 ...

  3. 基于FPGA的SDRAM控制器设计(1)

    基于FPGA的SDRAM初始化配置 SDRAM简述 SDRAM的引脚及作用 SDRAM初始化时序控制 SDRAM上电时序代码 SDRAM测试模块的代码 仿真测试结果 参考文献 总结 SDRAM简述 S ...

  4. 基于FPGA的SDRAM控制器设计(2)

    基于FPGA的SDRAM的自刷新操作 SDRAM自刷新简述 SDRAM自刷新时序图 SDRAM自刷新代码 仿真模块的代码 仿真结果测试 参考文献 总结 SDRAM自刷新简述 SDRAM作为一个RAM并 ...

  5. FPGA驱动SDRAM

    一.实验任务 实现PC向FPGA发送数据保存进SDRAM,再通过按键控制读出SDRAM中的数据发送给PC端,实现数据回环. 二.SDRAM介绍 同步动态随机存取内存(synchronous dynam ...

  6. 基于FPGA的EEPROM读写(IIIC 接口协议)

    笔者使用的是黑金AX309的开发板,其板载了一块有一个 IIC 接口的 EEPROM 芯片 24LC04(data sheet),容量大小为 4Kbit.这里先简单总结下一般的存储器件,然后介绍IIC ...

  7. FPGA控制DDR读写(AXI4总线接口)

    FPGA控制DDR读写(AXI4总线接口) 范围 本文适用于FPGA控制DDR读写 MIG核 MIG信号注释 DDR型号为 MT41K256M16TW-107 下面是MIG IP核的相关信号 图2.1 ...

  8. 通过vivado工具实现zynq的FPGA内部RAM读写

    通过vivado工具实现zynq的FPGA内部RAM读写(调用vivado自带IP核),从新建工程到仿真并下载到FPGA开发板中,通过vivado自带的ILA逻辑分析仪查看读写数据是否正确,包含详细步 ...

  9. 基于FPGA的SDRAM控制器设计(二)

    基于FPGA的SDRAM控制器设计(二) 1. SDRAM理论基础 2. SDRAM初始化模块以及仿真 3.TOP模块的仲裁机制 4. SDRAM刷新模块代码以及仿真 5.代码 6.参考资料 1. S ...

最新文章

  1. live555点播服务器流程深入分析(一)
  2. vue 嵌套表格组件_vue+element中表格嵌套怎么做?
  3. 【C 语言】内存四区原理 ( 栈内存与堆内存对比示例 | 函数返回的堆内存指针 | 函数返回的栈内存指针 )
  4. 深度解析两种信用评估模型
  5. MySql之DDL操作创建表(添加主键, 外键约束以及基本的数据类型)
  6. 前端学习(3233):高阶函数函数柯里化案例
  7. 教你一招用python发送QQ邮件
  8. Socket编程实践(6) --TCP服务端注意事项
  9. Kubernetes[3]-Server
  10. .h5是什么文件_PPT转H5丨再也不用担心忘带U盘怎么办了
  11. /usr 的由来及/usr目录结构 [转]
  12. ON1 Photo RAW 2022 for Mac(ps/lr滤镜raw图像编辑器)
  13. 安卓模拟器安装教程_安卓模拟器测试总结!究哪个最流畅?内附模拟换IP教程...
  14. We discovered one or more bugs in your app when reviewed on iPhone and iPad running iOS 14.1
  15. SiT3808:1 -80MHz 单端压控振荡器VCXO
  16. 王树尧老师运筹学课程笔记 02 高等数学基础
  17. 一张图,区分NPN于PNP型三极管的工作原理
  18. 爱你的人和你爱的人 你选哪个?
  19. matlab实验报告井字棋,有偿井字棋游戏300+
  20. 3乘3魔方第四步_3乘3魔方的解法都有哪些?(讲具体点,怎么具体呢?有公式步骤吧!)?...

热门文章

  1. R语言向前或者向后移动时间序列数据(自定义滞后或者超前的期数):使用lag函数将时间序列数据向后移动一天(设置参数k为负值)
  2. 我可是一个有图的留言板咳咳√
  3. 多对一,多对多RNN例子(摘抄笔记)
  4. 超细粒度分析 XLNet 中神奇的 Attention Mask
  5. 原理+代码|深入浅出决策树算法
  6. uni-app基础(二)
  7. html+css设计页面
  8. DynamicMethod
  9. 大学生心理健康咨询系统的设计与实现
  10. 虹软人脸识别初试(windows SDK,idea,USB摄像头)