FPGA驱动SDRAM

这篇具有很好参考价值的文章主要介绍了FPGA驱动SDRAM。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一.实验任务

实现PC向FPGA发送数据保存进SDRAM,再通过按键控制读出SDRAM中的数据发送给PC端,实现数据回环。

二.SDRAM介绍

同步动态随机存取内存(synchronous dynamic random-access memory,简称SDRAM)是有一个同步接口的动态随机存取内存(DRAM)。
本次实验使用的SDRAM芯片(HY57V561620FTP)内部被分成了4个bank,每个bank有64Mbit大小,SDRAM与输入时钟同步,时钟信号上升沿采样,行列地址线复用,数据线输入输出复用。读写访问是突发的,突发(Burst)是指在同一行中相邻的存储单元连续进行数据传输的方式,连续传输所涉及到存储单元(列)的数量就是突发长度(Burst Lengths,简称BL)。本次SDRAM芯片对应的突发长度有1、2、4、8、全页,自动预充电在突发访问结束自动进行预充电。访问从激活命令开始,紧接着是读写命令。激活命令选择激活的bank和行,而读写命令选择激活的bank和列。
SDRAM的数据存储是利用电容实现的,因为电容存在放电的特性,所以需要定时刷新芯片才可以保证数据不丢失。查看芯片手册,可以看见刷新周期为64ms,也就是说在64ms内要保证每一块内存都要刷新一次,内存共8192行,平均下来,只要每7.8us刷新一行,就能保证64ms内刷新所有内存。

SDRAM原理框图:
sdram fpga,FPGA,fpga开发
由上图可以看见行列地址线被复用了,SDRAM接收到地址,会将数据传递给相应的地址预译码器和地址计数器,行地址预译码器会激活bank的行,列地址预译码器会激活bank的列,同时模式寄存器设置的突发长度会联合列地址计数器共同决定当前操作的列地址。外部状态机给出时钟信号,时钟使能信号,片选信号,行地址,列地址,数据允许信号,数据屏蔽信号,输入数据;SDRAM输出数据。
每块bank大小为4M*16bit,如果想要扩展内存,有两种方法:

①扩展深度,将两块bank的地址线并联,片选信号并联,将数据线串联能够实现8M16bit。
②扩展宽度,将两块bank的地址线并联,数据线并联,通过一个2输入译码器选择片选信号就能实现4M
32bit。
如果既想扩展深度,又想扩展宽度,可以将上述两个方法结合起来。

注意:时钟和其他输入信号被异步重新启用,需要等待200us,同时FPGA和SDRAM的时钟存在时钟偏移,这是为了SDRAM能够采到稳定的数据,在芯片手册中有说到,具体偏移角度须自己调试。
SDRAM内部存在一个有限状态机,其状态跳转如下:
sdram fpga,FPGA,fpga开发
本次实验实现的是蓝色箭头表示的过程。
在读写命令之前,必须先激活相应的bank和行地址,激活命令和读写命令之间需要一个tRCD的间隔,READ突发读取,BA0和BA10用于选择bank,A10的值决定是否使用自动预充电,自动预充电用于突发结束时自动预充电,不选择自动预充电,则行保持打开供后续访问READ命令发出后,经过列激活延迟才可以得到数据。写命令用于启动对活动行的突发写访问。BA0和BA1的值用于选择数据开始传输的bank地址和列地址。A10的值决定了是否使用自动预充电。如果选择了自动预充电,则正在访问的行将在写突发结束时进行预充电;如果未选择自动预充电,则该行将保持打开状态以供后续访问。
SDRAM控制操作比较复杂,所以我们使用了SDRAM的接口IP,这大大减少了我们的工作量,在调用IP的基础上,我们只需要设计一个控制模块就能操作SDRAM进行读写操作了。

三.设计思路

程序框图:
sdram fpga,FPGA,fpga开发

四.代码实现

调用IP核(这里IP核的调用不同于之前的PLL,RAM等):
sdram fpga,FPGA,fpga开发
sdram fpga,FPGA,fpga开发
设置配置文件参数:
sdram fpga,FPGA,fpga开发
添加相关延时:
sdram fpga,FPGA,fpga开发

设置时钟为100MHZ:
sdram fpga,FPGA,fpga开发
完成相关连线和端口命名:
sdram fpga,FPGA,fpga开发
sdram fpga,FPGA,fpga开发
顶层模块设计:

/**********************************************************
// Copyright 2022.05-2025.05
// Contact with xxxxxxxxx@qq.com
================ xxx.v ======================
>> Author       : lj
>> Date         : 20XX/XX/XX
>> Description  : 
>> note         : 
>>              : 
>> V180121      : 
************************************************************/
module sdram_top(
    input                   clk       ,//时钟信号 50MHZ
    input                   rst_n     ,//复位信号
    input                   rx        ,//串口接收数据

    input                   key_in    ,//按键输入 作为读请求信号

    output    [12:0]        mem_addr  , 
    output    [1 :0]        mem_bank  , 
    output                  mem_cas_n , 
    output                  mem_cke   , 
    output                  mem_cs_n  , 
    inout     [15:0]        mem_dq    , 
    output    [1 :0]        mem_dqm   , 
    output                  mem_ras_n , 
    output                  mem_we_n  ,
    output                  sdram_clk ,     
  
    output                  tx         //串口发送数据
);

//参数定义

//信号定义
    wire            key_done        ;
    wire            clk_100m        ;
    wire            clk_100m_s      ;

    wire    [7:0]   din             ;
    wire            din_vld         ;

    wire            ready           ;
    wire    [7:0]   dout            ;
    wire            dout_vld        ;

    wire            locked          ;


//模块例化
    //按键消抖模块
    key u_key(
        /*input                */.clk       (clk     ),//时钟信号
        /*input                */.rst_n     (rst_n   ),//复位信号
        /*input        [1:0]   */.key_in    (key_in  ),//按键输入信号
        /*output  reg  [1:0]   */.key_done  (key_done) //输出信号       
    );

    //锁相环
    pll	pll_inst (
	    .areset ( ~rst_n     ),
	    .inclk0 ( clk        ),
	    .c0     ( clk_100m   ),
	    .c1     ( clk_100m_s ),//100MHZ时钟,带有相位偏移
        .locked (locked      )
	);

    //串口接收模块
    uart_rx u_uart_rx(                  //将接收的串行数据转换成并行数据
        .clk        (clk        ),
        .rst_n      (rst_n      ),
        .rx         (rx         ),//串行数据
        .set_bps    (0          ),

        .dout       (din        ),//并行数据
        .dout_vld   (din_vld    )
    );

    //sdram控制
    sdram_controller u_sdram_controller(
        /*input                   */.clk        (clk_100m        ),//时钟信号 100MHZ
        /*input                   */.rst_n      (rst_n           ),//复位信号
        /*input                   */.clk_in     (clk             ),//50MHZ 时钟
        /*input                   */.clk_out    (clk             ),//50MHZ 时钟

        /*input                   */.ready      (ready           ),//串口发送模块准备好

        /*input       [7:0]       */.din        (din             ),//输入数据 来自串口接收模块
        /*input                   */.din_vld    (din_vld         ),//输入数据有效

        /*input                   */.rd_req     (key_done        ),//读请求信号 来自按键
        /*output      [7:0]       */.dout       (dout            ),//输出数据 发送给串口发送模块
        /*output                  */.dout_vld   (dout_vld        ),//输出数据有效 

        /*output      [12:0]      */.mem_addr   (mem_addr        ),
        /*output      [1 :0]      */.mem_bank   (mem_bank        ),
        /*output                  */.mem_cas_n  (mem_cas_n       ),
        /*output                  */.mem_cke    (mem_cke         ),
        /*output                  */.mem_cs_n   (mem_cs_n        ),
        /*inout       [15:0]      */.mem_dq     (mem_dq          ),
        /*output      [1 :0]      */.mem_dqm    (mem_dqm         ),
        /*output                  */.mem_ras_n  (mem_ras_n       ),
        /*output                  */.mem_we_n   (mem_we_n        ) 
    );

    //串口发送模块
    uart_tx u_uart_tx(                  //将接收的并行数据转换成串行数据传输
        .clk        (clk        ),
        .rst_n      (rst_n      ),
        .din        (dout       ),//并行数据
        .din_vld    (dout_vld   ),
        .set_bps    (0          ),

        .tx         (tx         ), //串行数据
        .ready      (ready      )
    );

    assign sdram_clk = clk_100m_s;
endmodule

控制模块调用SDRAM接口IP核:

/**********************************************************
// Copyright 2022.05-2025.05
// Contact with xxxxxxxxx@qq.com
================ xxx.v ======================
>> Author       : lj
>> Date         : 20XX/XX/XX
>> Description  : 
>> note         : 
>>              : 
>> V180121      : 
************************************************************/
module sdram_controller(
    input                   clk      ,//时钟信号 100MHZ
    input                   rst_n    ,//复位信号
    input                   clk_in   ,//50MHZ 时钟
    input                   clk_out  ,//50MHZ 时钟
    input                   ready    ,//串口发送模块准备好
    input       [7:0]       din      ,//输入数据 来自串口接收模块
    input                   din_vld  ,//输入数据有效
    input                   rd_req   ,//读请求信号 来自按键
    output      [7:0]       dout     ,//输出数据 发送给串口发送模块
    output                  dout_vld ,//输出数据有效
    output      [12:0]      mem_addr ,
    output      [1 :0]      mem_bank ,
    output                  mem_cas_n,
    output                  mem_cke  ,
    output                  mem_cs_n ,
    inout       [15:0]      mem_dq   ,
    output      [1 :0]      mem_dqm  ,
    output                  mem_ras_n,
    output                  mem_we_n  
);
//参数定义

//信号定义               
    wire     [23:0]     avs_port_address      ;
    wire                avs_port_write_n      ;
    wire     [15:0]     avs_port_writedata    ;
    wire                avs_port_read_n       ;
    wire     [15:0]     avs_port_readdata     ;
    wire                avs_port_readdatavalid;
    wire                avs_port_waitrequest  ;

//模块例化
    sdram_ctrl u_sdram_ctrl(
        /*input                   */.clk             (clk                   ),//时钟信号 100MHZ
        /*input                   */.rst_n           (rst_n                 ),//复位信号
        /*input                   */.clk_in          (clk_in                ),//50MHZ
        /*input                   */.clk_out         (clk_out               ),//50MHZ
        
        /*input      [7:0]        */.din             (din                   ),//输入数据 来自串口接收模块
        /*input                   */.din_vld         (din_vld               ),//输入数据有效

        /*output     [7:0]        */.dout            (dout                  ),//输出数据 发给串口发送模块
        /*output                  */.dout_vld        (dout_vld              ),//输出数据有效

        /*input                   */.ready           (ready                 ),//串口发送模块准备好
        /*input                   */.rd_req          (rd_req                ),//读请求信号 来自按键

        /*output     [23:0]       */.avm_addr        (avs_port_address      ),//地址
        /*output                  */.avm_wr_n        (avs_port_write_n      ),//写请求 低有效
        /*output     [15:0]       */.avm_wr_data     (avs_port_writedata    ),//写数据
        /*output                  */.avm_rd_n        (avs_port_read_n       ),//读请求 低有效
        /*input      [15:0]       */.avm_rd_data     (avs_port_readdata     ),//读出的数据
        /*input                   */.avm_rd_data_vld (avs_port_readdatavalid),//读出数据有效
        /*input                   */.avm_waitrequest (avs_port_waitrequest  ) //从机等待请求信号          
    );

	sdram_interface u0 (
		.clk_clk                (clk                   ),//      clk.clk
		.reset_reset_n          (rst_n                 ),//    reset.reset_n
		.mem_port_addr          (mem_addr              ),// mem_port.addr
		.mem_port_ba            (mem_bank              ),//         .ba
		.mem_port_cas_n         (mem_cas_n             ),//         .cas_n
		.mem_port_cke           (mem_cke               ),//         .cke
		.mem_port_cs_n          (mem_cs_n              ),//         .cs_n
		.mem_port_dq            (mem_dq                ),//         .dq
		.mem_port_dqm           (mem_dqm               ),//         .dqm
		.mem_port_ras_n         (mem_ras_n             ),//         .ras_n
		.mem_port_we_n          (mem_we_n              ),//         .we_n

		.avs_port_address       (avs_port_address      ),// avs_port.address
		.avs_port_byteenable_n  (2'b00                 ),//         .byteenable_n
		.avs_port_chipselect    (1'b1                  ),//         .chipselect
		.avs_port_writedata     (avs_port_writedata    ),//         .writedata
		.avs_port_read_n        (avs_port_read_n       ),//         .read_n
		.avs_port_write_n       (avs_port_write_n      ),//         .write_n
		.avs_port_readdata      (avs_port_readdata     ),//         .readdata
		.avs_port_readdatavalid (avs_port_readdatavalid),//         .readdatavalid
		.avs_port_waitrequest   (avs_port_waitrequest  ) //         .waitrequest
	);
endmodule

控制模块具体状态设计:
sdram fpga,FPGA,fpga开发
由于读写操作不能同时进行,为了防止一直读或一直写的情况,实现读写仲裁让读写操作交替进行。
具体实现如下:

//读写优先级仲裁
    //wr_flag
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            wr_flag <= 1'b0;
        end
        else if(wrfifo_usedw > BURST_LEN)begin
            wr_flag <= 1'b1;
        end
        else begin
            wr_flag <= 1'b0;
        end
    end

    //rd_flag
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            rd_flag <= 1'b0;
        end
        else if(~rd_flag && rd_req)begin
            rd_flag <= 1'b1;
        end
        else begin
            rd_flag <= 1'b0;
        end
    end

    //flag_sel 0:上一次写 1:上一次读
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            flag_sel <= 1'b0;
        end
        else if(write2idle)begin
            flag_sel <= 1'b0;
        end
        else if(read2idle) begin
            flag_sel <= 1'b1;
        end
    end

    //prior_flag 0:写 1:读
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            prior_flag <= 1'b0;
        end
        else if(wr_flag && (flag_sel || ~rd_flag))begin
            prior_flag <= 1'b0;
        end
        else if(rd_flag && (~flag_sel || ~wr_flag)) begin
            prior_flag <= 1'b1;
        end
    end

使用SDRAM接口IP注意地址拼接:

{bank[1],addr[21:9],bank[0],addr[8:0]}

其余代码:略

五.测试

sdram fpga,FPGA,fpga开发
PC端利用串口调试助手向FPGA发送数据保存到SDRAM芯片中,FPFA开发板按下按键从SDRAM芯片中读出数据发送给PC端。文章来源地址https://www.toymoban.com/news/detail-728484.html

到了这里,关于FPGA驱动SDRAM的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【FPGA入门】第八篇、FPGA驱动VGA实现动态图像移动

    目录 第一部分、实现效果 第二部分、动态VGA显示的原理 1、将动态显示的区域提前进行赋值 2、图像块的移动是每张图片叠加后的效果 3、如何实现图像块位置的改变 第三部分、系统结构和驱动波形 1、系统的Top-down结构 2、图像块移动的驱动波形 第四部分、代码 1、同步信号

    2024年02月04日
    浏览(47)
  • FPGA驱动SDRAM

    实现PC向FPGA发送数据保存进SDRAM,再通过按键控制读出SDRAM中的数据发送给PC端,实现数据回环。 同步动态随机存取内存(synchronous dynamic random-access memory,简称SDRAM)是有一个同步接口的动态随机存取内存(DRAM)。 本次实验使用的SDRAM芯片(HY57V561620FTP)内部被分成了4个bank,

    2024年02月07日
    浏览(36)
  • FPGA SPI 驱动程序

    此驱动程序已经完成很久了,花了2个星期的时间,主要是提升程序运行的效率。最近整理文件的时候又看到了,记录一下。 (1)状态控制程序 其主要是以空状态,写状态,读状态三个状态顺序执行的。 (2)写命令程序部分 (3)读数据程序部分

    2024年02月10日
    浏览(47)
  • 【技术分享】Altera FPGA EP4CGX22CF19C8详解:原理图、PCB图纸、源代码及PCIe二次开发驱动和代码全解析

    altera fpga ep4cgx22cf19c8,有原理图,PCB图纸,源代码,PCIe二次开发驱动和代码等。 ID:313000 681436451614 小明子555 《基于Altera FPGA EP4CGX22CF19C8的硬件开发与PCIe驱动开发》 摘要:本文基于Altera FPGA EP4CGX22CF19C8芯片,探讨了硬件开发和PCIe驱动开发的相关技术。首先介绍了EP4CGX22CF19C8芯片

    2024年04月25日
    浏览(34)
  • FPGA驱动SPI屏幕(附完整工程)

    相信大家都玩过屏幕,在FPGA上使用最多的就是VGA/HDMI接口的显示器了,这两种显示器的优点就不用说了,缺点就是体积比较大,而且价格比较贵,对于追求便携/价格低的我来说,SPI接口的屏幕才是我的首要选择,而且一般是可以带触摸的哦。 后面图像处理相关的代码都会基于

    2024年02月16日
    浏览(50)
  • 【最通用版FPGA 实现 SPI 驱动】

    最近研究了一下SPI协议的FPGA实现,发现网上很多大佬分享的方法都是针对某一特定的flash芯片或者某一传感器芯片来设计电路结构的。所以想根据SPI(Serial Peripheral Interface)的基本通讯协议实现一个通用版的SPI Master驱动。SPI在嵌入式领域是一个很成熟且应用非常广泛的通信协

    2024年02月05日
    浏览(46)
  • 二、17【FPGA】无源蜂鸣器驱动实验

    学习说明此文档为本人的学习笔记,注重实践,关于理论部分会给出相应的学习链接。 学习视频:是根据野火FPGA视频教程——第二十讲 https://www.bilibili.com/video/BV1nQ4y1Z7zN?p=3      蜂鸣器按其结构可分为电磁式蜂鸣器和压电式蜂鸣器两种类型。 压电式蜂鸣器是以压电陶瓷的压

    2023年04月25日
    浏览(48)
  • FPGA 第2章 摄像头驱动讲解

    参考文献 图像采集——OV5640摄像头简介、硬件电路及上电控制的Verilog代码实现并进行modelsim仿真 https://blog.csdn.net/H19981118/article/details/115503184 本文介绍OV5640摄像头相关知识。 OV5640 是一款 1/4 英寸单芯片图像传感器,其感光阵列达到 2592 1944(即 500W 像素),能实现最 快 15fps

    2024年03月26日
    浏览(49)
  • 基于FPGA的QSPI底层驱动代码实现

    相信各位优秀的工程师们对SPI协议已经是非常了解了,SPI全名为串行外围设备接口(Serial Peripheral Interface),是一种高速全双工的同步通信总线,广泛应用于设备间的通讯传输。 而本文所要讲的QSPI,为SPI接口的扩展,Q代表quad即4倍传输的意思,也称为四线制SPI,因此该接口的

    2024年02月03日
    浏览(44)
  • FPGA驱动AD9240实现AD转换

    在做项目中,经常会用到AD转换模块。前段时间做毕业设计的时候需要用到FPGA驱动AD9240模块实现模拟数据的采集和转换,尽管相对来说AD9240算比较简单的驱动模块,但是也想记录下分析和设计过程。 首先通过芯片手册可以看到AD9240是14位,最高速率可达10Mbps的模数转换器件。

    2024年02月06日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包