芯路恒电子技术论坛

 找回密码
 立即注册
热搜: 合集
查看: 6607|回复: 1

【实验指导书】Ad9226数据采集DDR3缓存串口发送实验

[复制链接]
  • TA的每日心情
    开心
    2021-12-31 09:03
  • 71

    主题

    79

    帖子

    967

    积分

    高级会员

    Rank: 6Rank: 6

    积分
    967
    发表于 2022-3-28 09:42:46 | 显示全部楼层 |阅读模式
    1.  Ad9226数据采集DDR3缓存串口发送实验
    1.1.数据采集的意义
    在计算机广泛应用的今天,数据采集的在多个领域有着十分重要的应用。
    数据采集是计算机与外部物理世界连接的桥梁,通过数据采集工作,自然界的许多模拟量信息能够借助计算机进行保存,分析,还原等操作。技术实践中,我们只需要制订上位机(PC)与移动数据采集器的通信协议,就可以实现两者之间阻塞式通信交互过程。
    数据采集系统往往由传感器、模拟多路开关、放大器,采样保持器、AD转换器、计算机及外设等组成。
    在农业、工业、日常生活和航空航天等领域,尤其是在对信息实时性能要求较高或者恶劣的自然环境中,数据采集有其应用的必要性。比如说:在工业生产和科学技术研究的各行业中,常常有利用PC或工控机配合末端传感器对诸如液位、温度、压力、频率等参数进行实时监控和记录的需求,这些环境往往有时候并不适合人类直接作业,或者即使人类进行直接作业,也无法达到和计算机自动采集分析处理某一个任务的实施效果。再比如说:在航天航空领域,卫星数据采集系统利用航天遥测、遥控、遥监等技术,对航天器远地点进行各种监测,并根据需求进行自动采集,经过卫星传输到数据中心处理后,送给用户使用。
    谈到数据采集,不得不说说数据转换器。现在常用的数据转换方式是通过数据采集板卡进行,常用的有如A/D卡以及422、485等总线板卡,我们今天要进行的实验,就是利用ACM9226数据采集卡实施数据采集。
    1.2.工程目标、任务和难点
    本工程介绍如何通过利用ACX720/ACX735开发板上的DDR3资源,实现ACM9226模块的串口数据采集功能。
    本工程在实验条件下,期望达到如下功能要求:
    1、实验通过数据采集模块实现模数转换,传递给开发板。在这里,我们采用ACM9226双通道数据采集模块作为数据采集卡进行数据采集。为了真实模拟数据采集的实验环境,我们借助以芯路恒品牌的ACM9767触摸屏信号发生器作为信号源,使用时可以通过设置其不同频率进行采样观察效果。
    2、使用相关的串口通信软件,通过串口发码指令,可以设定需要采集的字节数,选择采集通道号,启动采集。
    3、使用相关的串口通信软件,可以按设定的采集参数,接收采集的数据。数据通过串口发送到串口调试软件(后期可开发对应PC上位机)。将读取到的数据我们进行txt文件的保存,便于后期分析。
    4、采集到的数据经过matlab波形分析,能够得到和输入波形一致的输出波形,无数据丢失,无杂波。后期可结合实际情况,增加对噪声评定的环节。

    本实验的难点:
    1.   对DDR3的配置、信号控制和灵活运用;
    2.   状态机的跳转设计;
    3.   串口调试软件的运用和MATLAB的数据分析处理。

    1.3.工程和代码讲解1.3.1.工程可行性分析
        通过对各部分的参数进行分析,我们进一步论证了数据采集串口接收的方案可行性。
    (1)  ADC采集数据的最大带宽:65MSPS *12bit = 780Mbps,由于ACM9226模块需要外部提供工作时钟,所以FPGA应向ACM9226模块供应50M时钟。
    (2)   ACX720板载DDR3带宽:400*16*2 = 12,800Mbps,考虑到DDR3控制器不能100%效率,按80%效率,读写各占一半,也足够大于780Mbps,ADC采集数据存储到DDR3不会存在带宽不够导致数据丢失问题
    (3)   先考虑使用串口上传采集的ADC采集的数据,常见的串口波特率9600bps,115200bps,这个比ADC采集数据的带宽要小的多,想通过串口实时的将采集的数据传出去是不行,会存在数据丢失问题,考虑到这点,将ADC采集和串口上传数据分开处理,先ADC采样指定个数(或指定时间)的数据,保存在板载DDR3,然后停止ADC采样,之后串口再将ADC采样数据依次上传到PC。
    (4)  DDR3存储数据量:DDR3内存256MByte,ADC数据位宽为12bit,按16bit(2个Byte)计算,可存储数据最大个数为256*1024*1024/2= 134,217,728(个16bit数)。在这里,由于AD9226的最高工作频率为65M,而DDR3的默认工作频率为200M,为了简易的处理硬件的时钟异步问题,同时简化对DDR3的控制,可以在程序中分别开拓一个fifo写缓冲区和fifo读缓冲区,完成ddr3的调度控制机制和跨时钟域的处理。
    1.3.2.工程总体框架
    整体来说,程序的硬件架构如下图所示:

    系统硬件架构图.png

    其中,ACX720模块内部的FPGA代码,设计了7个软件子模块,

    ACX720内部子模块框图.png

    内部各子模块功能如下:
    u0、全程序50M时钟输入,各频率锁相环输出
    u1、串口接收模块的指令接收功能。
    u2、u3接收到的指令进行翻译拆解,指令分类。
    u4、ACM9226数据输入12bit到16bit的转换。
    u5、ddr3的含fifo的2端口封装模块,主要负责整个数据的存储功能。
    u6、串口数据输出模块。
    u7、状态机模块,协调各个模块的信号控制,程序状态的总控制模块。
    下面给出原理级的简易的状态转移图:

    003.png

    初步分析程序的状态机核心部分,主要分为上电,空闲,采样,串口上传四个部分。
    程序上电后,进入状态2空闲状态,此时可以通过串口指令设置采样个数,设置采样频率,下发采样开始的指令。
    FPGA收到采样开始指令后,进入状态3开始进行ADC采样。这时候,FPGA利用计数器对采样数据个数进行计数,采样的同时数据直接储存在DDR3中。如果未达到采样个数,则进行状态3的循环,如果达到采样个数,则进入状态4串口上传。如果串口上传完成,则返回空闲状态,如果串口上传未完成,则继续进行串口上传。
    在实际的执行过程中,状态机还需要考虑:先有数据信号,后有控制信号的问题,所以从细节出发,在代码实现阶段,还需要添加一些辅助的状态来保证这些核心状态的正常运行。
    状态转换细节处理的相关问题,以及如何选取状态转换的判断条件,我们在后面程序部分进行详述。
    1.3.3.程序顶层模块及对外接口功能设计
    004.png
    为了保证代码的可读性和风格的美观,我们在顶层模块中,仅进行端口定义,端口信号连线,简单的组合逻辑处理和模块例化工作。

    005.png

    顶层模块声明了输入输出接口以及数据流向,这里,我们对模块的端口列表给出说明,如有需要,请对照代码进行深入理解:
    顶层输入输出端口列表及说明
      
    端口名
      
    端口类型
    描述
    clk
    input
    系统时钟50MHz
    reset_n
    input
    系统复位,低有效
    led
    output[1:0]
    用于测试的LED指示灯,我们定义led[0]为锁相环初始化完成指示灯,led[1]为DDR3初始化完成指示灯。
    uart_rx
    input
    串口接收信号引脚
    uart_tx
    output
    串口发送信号引脚
    ad_in1
    input[11:0]
    AD9226模块的12位数据输入引脚第一通道
    ad_in2
    input[11:0]
    AD9226模块的12位数据输入引脚第二通道
    ad_clk1
    output
    AD9226模块的第一通道时钟
    ad_clk2
    output
    AD9226模块的第二通道时钟
    ddr3_dq
    inout[15:0]
    DDR3数据输入、输出:双向数据总线。若模式寄存器中使能了CRC功能,那么在数据burst结束时就会附加一段CRC码。
    ddr3_dqs_n
      
    ddr3_dqs_p
    inout[1:0]
      
    inout[1:0]
    DDR3差分数据选通信号:差分信号对,作输入时与写数据同时有效,作输出时与读数据同时有效。读数据时与边沿对齐,但是跳变沿位于写数据的中心。DDR3 SDRAM仅支持选通信号为差分信号,不支持单根信号的数据选通信号。
    ddr3_addr
    output[13:0]
    地址输入,为ACTIVATE命令提供行地址和READ/WRITE命令的列地址和自动预充电(A10),以便从某个bank的内存阵列里选出一个位置
    ddr3_ba
    output[2:0]
    Bank地址输入,定义ACTIVATE、READ、WRITE或PRECHARGE命令是对哪一个bank操作的
    ddr3_ras_n
      
    ddr3_cas_n
      
    ddr3_we_n
    output
    命令输入,这三个信号,连通cs_n,定义一个命令
    ddr3_reset_n
    output
    复位,低电平复位,复位是异步的
    ddr3_ck_p
      
    ddr3_ck_n
    output[0:0]
      
    output[0:0]
    时钟,差分时钟输入,所有控制和地址输入信号在ck_p上升沿和ck_n的下降沿交叉处被采样,输出数据选项(dqs_n、dqs_p)参考与ck_p和ck_n的交叉点。
    ddr3_cke
    output[0:0]
    时钟使能:CKE为高电平时,启动内部时钟信号、设备输入缓冲以及输出驱动单元。CKE低电平时则关闭上述单元。当CKE为低电平时,可使设备进入PRECHARGE POWER DOWN、SELF-REFRESH以及ACTIVE POWER DOWN模式。CKE与SELF REFRESH退出命令是同步的。在上电以及初始化序列过程中,VREFCA与VREF将变得稳定,并且在后续所有的操作过程中都要保持稳定,包括SELF  REFRESH过程中。CKE必须在读写操作中保持稳定的高电平。在POWER DOWN过程中,除CK_t,CK_c,ODT以及CKE以外的所有输入缓冲都是关闭的。在SELF REFRESH过程中,除CKE以外的所有输入缓冲都是关闭的。在正时钟上升边沿采样。
    ddr3_cs_n
    output[0:0]
    片选信号,当CS_n锁存为高电平时,所有的命令都被忽略。在正时钟上升边沿采样。
    ddr3_dm
    output[0:0]
    输入数据掩码,dm信号是作为写数据的掩码信号,当dm信号信号为低电平时,写命令的输入数据对应的位将被丢弃。dm信号在DQS的两个条边沿都采样。
    ddr3_odt
    output[0:0]
    On-Die Termination,片上终端电阻;ODT信号可使能DDR SDRAM内部的RTT_NOM终端电阻。该设计通过允许DRAM控制器独立地打开/关闭任一或所有DRAM设备的终端电阻来改善存储器通道的信号完整性。
      
    DRAM通过ODT控制引脚为每个DQ,DQS和DM开启/关闭终端电阻。与其他输入命令不同,ODT引脚直接控制ODT动作,不对其进行时钟采样。在自刷新模式下不支持ODT。可以选择在CKE掉电期间通过模式寄存器启用ODT操作。
      
    请注意,如果在掉电模式下启用ODT,则在掉电期间可能无法关闭VDDQ(I/O供电),同时DRAM也会在读操作期间无法关闭。
    u0:pll实现的功能就是产生各个模块需求的时钟。这里,由于xilinx的内部buf寄存器的使用要求,如果使用pll,则要求锁相环的输入时钟具有独占性而不能和其他模块共用。如果使用mmcm,则有更优秀的灵活度。
    1.3.4.各子模块设计1.3.4.1.锁相环模块
      
      pll pll (
      
        // Clock out ports
      
        .clk_out1 (loc_clk50m  ), // output clk_out1
      
        .clk_out2 (loc_clk200m ), // output clk_out2
      
        .resetn   (reset_n     ), // input reset
      
        .locked   (pll_locked  ), // output locked
      
        // Clock in ports
      
        .clk_in1  (clk         )  // input clk_in1
      
      );
      

    006.png

    我们的锁相环模块直接使用的vivado自带的IP,输入信号为系统时钟50M,输出两种时钟频率,一种loc_clk50m作为DDR3模块外其他模块的基础的时钟,配合pll_locked
    信号使用,另一种loc_clk200m是提供给DDR3的工作时钟。
    1.3.4.2.数据采集卡ACM9226简介及工程代码12bit转16bit模块
    ACM9226模块使用2片ADI公司的高性能12位6Msps采样率的模数转换芯片AD9226,配合前端信号调理电路,实现了双通道65M采样率的高速采样功能,模块模拟电压输入范围为±5V、采用12位并行数据接口。只需要fpga提供时钟信号,开发板就能在每个时钟周期从模块12位并行数据接口上读取到一个数据。借助其较高的采样速率,配合PC上位机和模拟量幅度变送装置,可以满足绝大多数领域的数据采样需求。下面给出ACM9226模块与FPGA的连接对应关系:

    007.png

    ACM9226模块使用32针排母与开发板母板连接,支持直接连接的开发板包括但不限于小梅哥出品的AC620教学板,ACX720教学板、AC6102、Starter入门板,友晶科技出品的DE2、DE1、DE1_SoC、DEO-Nano-SoC等。
    在引脚绑定的时候,我们要特别注意ACM9226模块的LSB引脚和MSB引脚。与大多数芯片不同,ACM9226模块对应的LSB是数据位最高位,而对应的MSB是数据位的最低位。如果在绑定引脚芯片的时候没有注意,则有可能会得到没有规律的输出数据。
    计算机业界,端表示数据在存储器中的存放顺序。大端与小端是两种数据的存储方式!大端方式将高位存放在低地址,小端方式将高位存放在高地址。(比如将16位数0x1234存放在地址0x00,0x01两个连续地址中时,按照大端方式应该0x00中存放0x12,而0x01中存放0x34,小端方式0x00中存放0x34,而0x01中存放0x12)
    如果我们对引脚采用相同的理论,则写出来的12bit数据和引脚绑定的高位和地位,将呈现镜像关系。比如,我们引脚输出的12bit数据是12’b1011_0111_1111,则实际反应的模拟采样值是12‘b1111_1110_1101,如果模拟量再提高一个分度值,则得到12’b1111_1110_1110。如果我们错误的处理了大端和小端,误认为存储值和管脚输出值一一对应,则模拟量再提高一个分度值,得到的12bit数据是12’b1011_1000_0000,这样,就会丢失数据采样的规律,得到错误的结果。
    数据采集卡采集到的12bit数据不便于计算机存储,由于计算机对数据进行分析、存储的时候都以8位或16位数据作为统一的存储标准,则我们需要将12bit数据转换成16bit数据进行存储。这里我们给出代码如下:
      
    module ad9226_12bit_to_16bit(
      
      clk,
      
      ch_sel,
      
      ad_in1,
      
      ad_in2,
      
      ad_out
      
    );
      
      
      input clk;
      
      input [1:0]ch_sel;
      
      input[11:0] ad_in1;
      
      input[11:0] ad_in2;
      
      output[15:0] ad_out;
      
      reg[15:0] ad_out;
      
      
      always @(posedge clk)
      
      if(ch_sel == 2'b01)
      
        ad_out<={4'd0,ad_in1};
      
      else if(ch_sel == 2'b10)
      
        ad_out<={4'd0,ad_in2};
      
    endmodule
      
           本模块的功能,是将输入的12bit数据,转换为16bit数据。

    008.png

    关于这里的数据采集和处理,有两种方案,第一种是在此处认为采集的线信号是无符号数,我们在前面补4个0位扩宽成为16bit数据存储,后面使用matlab进一步处理。另一种是把采集到的线信号当作有符号数来处理,后面使用matlab作另一种方案处理。最后的目标是:我们有理有据的得出函数信号发生器发出的波形即可。本工程中,我们采用的第一种方案。
    1.3.4.3.串口指令接收和指令解析模块
    这两个模块的作用,是把串口接收到的指令进行拆解和识别。从串口接收到指令数据后,uart_byte_rx模块将串口数据从串行信号转为8位的并行数据uart_rx_data。8位的并行数据在uart_cmd模块中,被解析出地址、数据和使能信号。uart_cmd_rx将前面解析出的数据,作为各个类型,分别储存在各个寄存器中。
    在这里,我们给出指令解析的代码和讲解:
      
      always@(posedge loc_clk50m or posedge g_reset)
      
      if(g_reset)begin
      
        uart_baud_set  <= 3'd4; //默认115200bps
      
        adc_ch_sel <= 2'b00;
      
         set_sample_num <= 16'd32768;
      
        start_sample <= 1'b0;
      
      end
      
      else if(cmdvalid)begin
      
        case(cmd_addr)
      
            0: start_sample <= 1'b1;
      
            1: adc_ch_sel <= cmd_data[1:0];
      
            2: set_sample_num <= cmd_data[15:0];
      
            4:
      
              begin
      
                 adc_ch_sel <= cmd_data[1:0];
      
                 set_sample_num <= cmd_data[23:8];
      
                 start_sample <= 1'b1;
      
              end
      
            5: uart_baud_set <= cmd_data[2:0];
      
          default:;
      
        endcase
      
      end
      
      else
      
        start_sample <= 1'b0;
      
    AD9226的控制指令,由8个字节的数据组成,前两个字节D0,D1用55 A5,最后一个字节D7帧尾用F0,标明这是一个接收的指令,第三个字节D2,标明的是控制存储地址,本工程中,我们定义00是发送启动命令,01是采样通道号,02是采样深度。
    串口一次发送的数据内容为1个字节,为了实现通过串口修改这些寄存器的值,需要发送多个字节才能实现,为此,设计了简单的串口数据帧,该帧一帧数据共8个字节,包含帧头、帧尾、地址段(决定任务设定目标)、数据段。帧格式如下所示:
      
    数据
      
    D0
    D1
    D2
    D3
    D4
    D5
    D6
    D7
    功能
    帧头0
    帧头1
    地址
    data[31:24]
    data[23:16]
    data[15:8]
    data[7:0]
    帧尾
    0x55
    0xA5
    xx
    xx
    xx
    xx
    xx
    0xF0
    下面讲解一下典型的参数设置方法:
    采样通道如果是9226的第一通道,则设置为55 A5 01 00 00 00 01 F0
    采样通道如果是9226的第二通道,则设置为55 A5 01 00 00 00 02 F0
    如果采512字节的数据,则设置为:55 A5 02 00 00 01 00 F0
    如果采65536字节的数据,则设置为:55 A5 02 00 00 80 00 F0
    启动采样命令:整个字节为 55 A5 00 00 00 27 0F F0  
    我们在下方给出软件的典型用法

    009.png

    后面在软件使用的时候,连接好串口,然后依次点击发送区1,发送区2,发送区3,就可以开始采集数据。
    1.3.4.4.DDR3二端口模块简介
    1.3.4.4.1.DDR3二端口模块整体结构框图

    010.png

    1.3.4.4.2.DDR3二端口模块参数及端口描述
    ddr3_ctrl_2port模块参数说明
      
    参数名
      
    描述
    DW
    模块写FIFO的写数据和读FIFO的读数据位宽,即数据wrfifo_din和rdfifo_dout的位宽,设置值需被128整除
    WR_ADDR_BEGIN
    写数据存储空间的起始地址,1个地址对应的数据位宽为(DW) bit
    WR_ADDR_END
    写数据存储空间的终止地址,1个地址对应的数据位宽为(DW) bit
    RD_ADDR_BEGIN
    取数据存储空间的起始地址,1个地址对应的数据位宽为(DW) bit
    RD_ADDR_END
    取数据存储空间的终止地址,1个地址对应的数据位宽为(DW) bit
    ddr3_ctrl_2port模块端口说明
      
    端口名
      
    方向
    描述
    ddr3_clk200m
    I
    提供给DDR3控制器的基本工作时钟,要求200MHz
    ddr3_rst_n
    I
    提供给DDR3控制器的复位信号,低电平时为复位
    ddr3_init_done
    O
    DDR3控制器初始化及校准完成标识信号,为高表示初始化及校准成功
    写FIFO的写接口,用户往DDR3写入数据的接口
    wrfifo_clr
    I
    写FIFO清空控制信号,给高电平表示执行清空,执行清空操作时,需保证给3个及以上个时钟(wrfifo_clk)周期的高电平
    wrfifo_clk
    I
    写FIFO的写操作工作时钟
    wrfifo_wren
    I
    写FIFO的写数据使能控制信号,给高电平表示往FIFO写入数据,为避免写入数据的丢失,确保在FIFO非满(wrfifo_full=0)情况下写入数据
    wrfifo_din
    I
    写FIFO的写数据信号,数据位宽为DW
    wrfifo_full
    O
    写FIFO的写满标识信号,用于标识当前FIFO是否有被写满
    wrfifo_wr_cnt
    O
    写FIFO的写数据计数,表示当前FIFO中缓存数据的个数

    读FIFO的读接口,用户向DDR3读取数据的接口
    rdfifo_clr
    I
    读FIFO清空控制信号,给高电平表示执行清空,执行清空操作时,需保证给3个及以上个时钟(rdfifo_clk)周期的高电平
    rdfifo_clk
    I
    读FIFO的读操作工作时钟
    rdfifo_rden
    I
    读FIFO的读数据使能控制信号,给高电平表示往FIFO读数据,为避免读数据的丢失,确保在FIFO非空(rdfifo_empty =0)情况下读数据
    rdfifo_dout
    O
    读FIFO的读数据输出,数据位宽为DW,
    rdfifo_empty
    O
    读FIFO的读空标识信号,用于标识当前FIFO是否为空(即FIFO内有无数据)
    rdfifo_rd_cnt
    O
    读FIFO的读数据计数,表示当前FIFO中缓存数据的个数
    接DDR3管脚接口(仿真中与ddr3_model对接)
    ddr3_dq[15:0]
    IO
    数据输入、输出:双向数据总线。若模式寄存器中使能了CRC功能,那么在数据burst结束时就会附加一段CRC码。
    ddr3_dqs_n[1:0]
      
    ddr3_dqs_p[1:0]
    IO
    差分数据选通信号:差分信号对,作输入时与写数据同时有效,作输出时与读数据同时有效。读数据时与边沿对齐,但是跳变沿位于写数据的中心。DDR3 SDRAM仅支持选通信号为差分信号,不支持单根信号的数据选通信号。
    ddr3_addr[13:0]
    O
    地址输入,为ACTIVATE命令提供行地址和READ/WRITE命令的列地址和自动预充电(A10),以便从某个bank的内存阵列里选出一个位置
    ddr3_ba[2:0]
    O
    Bank地址输入,定义ACTIVATE、READ、WRITE或PRECHARGE命令是对哪一个bank操作的
    ddr3_ras_n ddr3_cas_n ddr3_we_n
    O
    命令输入,这三个信号,连通cs_n,定义一个命令
    ddr3_reset_n
    O
    复位,低电平复位,复位是异步的
    ddr3_ck_p
      
    ddr3_ck_n
    O
    时钟,差分时钟输入,所有控制和地址输入信号在ck_p上升沿和ck_n的下降沿交叉处被采样,输出数据选项(dqs_n、dqs_p)参考与ck_p和ck_n的交叉点
    ddr3_cke
    O
    时钟使能:CKE为高电平时,启动内部时钟信号、设备输入缓冲以及输出驱动单元。CKE低电平时则关闭上述单元。当CKE为低电平时,可使设备进入PRECHARGE POWER DOWN、SELF-REFRESH以及ACTIVE POWER DOWN模式。CKE与SELF REFRESH退出命令是同步的。在上电以及初始化序列过程中,VREFCA与VREF将变得稳定,并且在后续所有的操作过程中都要保持稳定,包括SELF  REFRESH过程中。CKE必须在读写操作中保持稳定的高电平。在POWER DOWN过程中,除CK_t,CK_c,ODT以及CKE以外的所有输入缓冲都是关闭的。在SELF REFRESH过程中,除CKE以外的所有输入缓冲都是关闭的。在正时钟上升边沿采样。
    ddr3_cs_n
    O
    片选信号,当CS_n锁存为高电平时,所有的命令都被忽略。在正时钟上升边沿采样。
    ddr3_dm
    O
    输入数据掩码,dm信号是作为写数据的掩码信号,当dm信号信号为低电平时,写命令的输入数据对应的位将被丢弃。dm信号在DQS的两个条边沿都采样。
    ddr3_odt
    O
    On-Die Termination,片上终端电阻;ODT信号可使能DDR SDRAM内部的RTT_NOM终端电阻。该设计通过允许DRAM控制器独立地打开/关闭任一或所有DRAM设备的终端电阻来改善存储器通道的信号完整性。
      
    DRAM通过ODT控制引脚为每个DQ,DQS和DM开启/关闭终端电阻。与其他输入命令不同,ODT引脚直接控制ODT动作,不对其进行时钟采样。在自刷新模式下不支持ODT。可以选择在CKE掉电期间通过模式寄存器启用ODT操作。
      
    请注意,如果在掉电模式下启用ODT,则在掉电期间可能无法关闭VDDQ(I/O供电),同时DRAM也会在读操作期间无法关闭。
    模块例化模板,参数的设置可查看上述参数描述,端口信号的连接可查看上述端口列表描述。
      
    ddr3_ctrl_2port #(
      
      .DW            ( 32   ),
      
      .WR_ADDR_BEGIN ( 0    ),
      
      .WR_ADDR_END   ( 1024 ),
      
      .RD_ADDR_BEGIN ( 0    ),
      
      .RD_ADDR_END   ( 1024 )
      
    )ddr3_ctrl_2port_inst
      
    (
      
      //clock reset
      
      .ddr3_clk200m   (ddr3_clk200m   ),//input
      
      .ddr3_rst_n     (ddr3_rst_n     ),//input
      
      .ddr3_init_done (ddr3_init_done ),//output
      
      //wr_fifo Interface
      
      .wrfifo_clr     (wrfifo_clr     ),//input
      
      .wrfifo_clk     (wrfifo_clk     ),//input
      
      .wrfifo_wren    (wrfifo_wren    ),//input
      
      .wrfifo_din     (wrfifo_din     ),//input   [DW-1:0]
      
      .wrfifo_full    (wrfifo_full    ),//output
      
      .wrfifo_wr_cnt  (wrfifo_wr_cnt  ),//output [15:0]
      
      //rd_fifo Interface
      
      .rdfifo_clr     (wrfifo_clr     ),//input
      
      .rdfifo_clk     (wrfifo_clk     ),//input
      
      .rdfifo_rden    (wrfifo_wren    ),//input
      
      .rdfifo_dout    (wrfifo_din     ),//output [DW-1:0]
      
      .rdfifo_empty   (wrfifo_full    ),//output
      
      .rdfifo_rd_cnt  (wrfifo_wr_cnt  ),//output [15:0]
      
      //DDR3 Interface
      
      // Inouts
      
      .ddr3_dq        (ddr3_dq        ),//inout   [15:0]
      
      .ddr3_dqs_n     (ddr3_dqs_n     ),//inout   [1:0]
      
      .ddr3_dqs_p     (ddr3_dqs_p     ),//inout   [1:0]
      
      // Outputs
      
      .ddr3_addr      (ddr3_addr      ),//output [13:0]
      
      .ddr3_ba        (ddr3_ba        ),//output [2:0]
      
      .ddr3_ras_n     (ddr3_ras_n     ),//output
      
      .ddr3_cas_n     (ddr3_cas_n     ),//output
      
      .ddr3_we_n      (ddr3_we_n      ),//output
      
      .ddr3_reset_n   (ddr3_reset_n   ),//output
      
      .ddr3_ck_p      (ddr3_ck_p      ),//output [0:0]
      
      .ddr3_ck_n      (ddr3_ck_n      ),//output [0:0]
      
      .ddr3_cke       (ddr3_cke       ),//output [0:0]
      
      .ddr3_cs_n      (ddr3_cs_n      ),//output [0:0]
      
      .ddr3_dm        (ddr3_dm        ),//output [1:0]
      
      .ddr3_odt       (ddr3_odt       ) //output [0:0]
      
    );
      
    1.3.4.4.3.DDR3二端口模块使用说明
    从模块的整体结构框图可以看出,里面包含4个子模块,其中wr_ddr3_fifo和rd_ddr3_fifo为双时钟FIFO IP,mig_7series_0是Memory Interface Generator(MIG 7 Series) IP,fifo2mig_axi模块是芯路恒开发的接口转换模块。其中,
    (1)mig_7series_0模块IP的详细配置参阅“小梅哥Xilinx FPGA自学教程”中“DDR控制器Example Design的使用”章节文档资料。
    (2)fifo2mig_axi模块的设计开发参阅“小梅哥Xilinx FPGA自学教程”中“基于DDR3的串口传图帧缓存系统设计实现”章节中关于该模块的文档资料,模块代码和对应的仿真文件有文件包附带,名称如下:
    设计文件:fifo2mig_axi.v
    仿真文件:fifo2mig_axi_tb.v
    (3)wr_ddr3_fifo是双时钟FIFOIP,具体配置如下,
    接口选择Native,FIFO实现选择IndependentClocks Block RAM;

    011.png
    012.png

    0125.png

    013.png

    (4)rd_ddr3_fifo是双时钟FIFOIP,具体配置如下,
    接口选择Native,FIFO实现选择IndependentClocks Block RAM;
    014.png 015.png

    016.png

    1.3.4.4.4.DDR3二端口模块仿真说明
    双端口FIFO DDR3控制器模块的仿真需要注意的是,需要将DDR3仿真模型(即ddr3_model模块)例化到tb文件中。例化框图可参考如下

    018.png

    只需要将接ddr3管脚接口的信号与ddr3_model模型端口信号一一连接即可。具体例程可参考“小梅哥Xilinx FPGA自学教程”中“基于DDR3的串口传图帧缓存系统设计实现”章节中的工程。需要注意的是需要将ddr3_model.v文件和ddr3_model_parameters.vh文件复制粘贴到需要仿真的工程下,然后添加仿真文件ddr3_model.v。相关代码随文件包附带,文件名如下:
    关于ddr3_ctrl_2port模块和模块仿真文件ddr3_ctrl_2port_tb的代码随文件包附带,文件名如下:
    设计文件:ddr3_ctrl_2port.v
    仿真文件:ddr3_ctrl_2port_tb.v
    下图是对ddr3_ctrl_2port模块仿真的波形图,注意波形中ddr3_init_done信号大概在0.1ms之后一点出现有低电平变高电平,如果超过这个很长时间没有变为高电平,那说明DDR3初始化可能存在问题,需要检查ddr3_model模块是否例化好,相关信号的数据位宽是否正确。
    019.png


    1.3.4.5.状态机模块介绍
    我们先给出状态机模块的输入输出框图

    020.png

    1.4.程序仿真
    在程序仿真之前,我们先解除工程主文件的代码相关注释行以启用仿真模式。

    021.png

    在进行仿真的时候,我们编写的tb文件需要加入ddr3_model如下:
      
    `timescale 1ns/1ns
      
    `define CLK_PERIOD 20
      
      
    module ad9226_ddr3_uart_tb();
      
    …… ……
      
    ddr3_model ddr3_model(
      
      .rst_n  (ddr3_reset_n),
      
      .ck     (ddr3_ck_p   ),
      
      .ck_n   (ddr3_ck_n   ),
      
      .cke    (ddr3_cke    ),
      
      .cs_n   (ddr3_cs_n   ),
      
      .ras_n  (ddr3_ras_n  ),
      
      .cas_n  (ddr3_cas_n  ),
      
      .we_n   (ddr3_we_n   ),
      
      .dm_tdqs(ddr3_dm     ),
      
      .ba     (ddr3_ba     ),
      
      .addr   (ddr3_addr   ),
      
      .dq     (ddr3_dq     ),
      
      .dqs    (ddr3_dqs_p  ),
      
      .dqs_n  (ddr3_dqs_n  ),
      
      .tdqs_n (            ),
      
      .odt    (ddr3_odt    )
      
    );
      
      
    endmodule
      
    ddr3_model是用来在仿真中替代真实的硬件ddr3工作的一个仿真模型,它可以完美的模拟出硬件ddr3初始化过程。
      
    initial clk= 1;
      
    always#(`CLK_PERIOD/2) clk = ~clk;
      
      
    initial begin
      
      reset_n=1'b0;
      
      #(`CLK_PERIOD*10);
      
      reset_n=1'b1;
      
      uart_send_en = 1'b0;
      
      uart_tx_data = 8'd0;
      
      @(posedge ad9226_ddr3_uart.ddr3_init_done);//等待DDR3初始化完成
      
      #(`CLK_PERIOD*10+1);
      
      //启动采集,仿真串口发送55 A5 00 00 00 00  00 F0
      
      uart_tx_data = 8'h55;
      
      uart_send_en = 1'b1;//-----发送55
      
      #(`CLK_PERIOD);
      
      uart_send_en = 1'b0;
      
      @(posedge uart_tx_done);
      
      
      #(`CLK_PERIOD*10+1);
      
      
      uart_tx_data = 8'hA5;
      
      uart_send_en = 1'b1;//-----发送A5
      
      #(`CLK_PERIOD);
      
      uart_send_en = 1'b0;
      
      @(posedge uart_tx_done);
      
      
      #(`CLK_PERIOD*10+1);
      
      
      uart_tx_data = 8'h00;
      
      uart_send_en = 1'b1;//-----发送00
      
      #(`CLK_PERIOD);
      
      uart_send_en = 1'b0;
      
      @(posedge uart_tx_done);
      
      
      #(`CLK_PERIOD*10+1);
      
      
      uart_tx_data = 8'h00;
      
      uart_send_en = 1'b1;//-----发送00
      
      #(`CLK_PERIOD);
      
      uart_send_en = 1'b0;
      
      @(posedge uart_tx_done);
      
      
      #(`CLK_PERIOD*10+1);
      
      
      uart_tx_data = 8'h00;
      
      uart_send_en = 1'b1;//-----发送00
      
      #(`CLK_PERIOD);
      
      uart_send_en = 1'b0;
      
      @(posedge uart_tx_done);
      
      
      #(`CLK_PERIOD*10+1);
      
      
      uart_tx_data = 8'h00;
      
      uart_send_en = 1'b1;//-----发送00
      
      #(`CLK_PERIOD);
      
      uart_send_en = 1'b0;
      
      @(posedge uart_tx_done);
      
      
      #(`CLK_PERIOD*10+1);
      
      
      uart_tx_data = 8'h00;
      
      uart_send_en = 1'b1;//-----发送00
      
      #(`CLK_PERIOD);
      
      uart_send_en = 1'b0;
      
      @(posedge uart_tx_done);
      
      
      #(`CLK_PERIOD*10+1);
      
      
      uart_tx_data = 8'hF0;
      
      uart_send_en = 1'b1;//-----发送F0
      
      #(`CLK_PERIOD);
      
      uart_send_en = 1'b0;
      
      @(posedge uart_tx_done);
      
      
      repeat(512)
      
        @(posedge ad9226_ddr3_uart.uart_tx_done);
      
      
      #2000;
      
      $stop;
      
    end
      
    仿真文件的顶层,除了例化工程文件的顶层和DDR3模型以外,描述了我们的启动指令的生成过程。我们上方代码模拟的正是串口接收口接收55 A5 00 00 00 00 00 F0的过程。
    经过仿真,我们能验证整个程序的工作流程符合设计要求。下面,我们给出仿真的整体效果波形图和局部重要信息波形图供各位读者参考。
    022.png
    从整体效果波形图可以依次看出程序的全局信息,仿真的结果符合我们的设计预期。

    023.png

    上图可以看出DDR3的模型给出DDR3上电初始化完成的时间参考值为0.11ms。

    024.png

    上面的波形展现了当开始采样信号到来时,进入清写fifo状态,并收到写fifo拉低反馈,进入采样状态的过程。
    下方三幅图,展现的是达到设定采样数量(16’h8000即十进制32768)后,清读fifo的过程。发送rdfifo_clr后,收到rdfifo_empty拉高的反馈,这时候,等待rdfifo_empty拉低进入下个状态。


    025.png

    026.png

    027.png

    028.png


    上图展现的是低8位数据发送完成后,在状态8读取高8位,并向串口发送send_en信号的细节过程。

    029.png

    030.png

    上面两幅图展现的是数据高8位发送完成后,进入下一个小循环,从读fifo中提取新一轮16bit数据,并提取新的低8位的过程。第二幅图,为第一幅图的状态切换细节展示。

    031.png

    上图为完整的从ddr初始化到前三个16位数据发送的过程关键信号全貌图。

    032.png

    上图反映的是接收到启动指令后,仿真的波形效果。
    1.5.板级调试1.5.1管脚绑定
    按下表给出管脚对应关系后,编写好xdc文件。
    ACM9226AC620ACX720开发板输入输出端口列表及说明
      
    端口名
      
    信号名
    620板管脚位置
    720板管脚位置
    方向
    描述
    ADCA_D0
    GPIO0-12
    PIN_K6
    PIN_D14
    input
    A通道输出D0端,MSB
    ADCA_D1
    GPIO0-11
    PIN_L3
    PIN_B13
    input
    A通道输出D1端
    ADCA_D2
    GPIO0-10
    PIN_L6
    PIN_C13
    input
    A通道输出D2端
    ADCA_D3
    GPIO0-9
    PIN_J1
    PIN_E14
    input
    A通道输出D3端
    ADCA_D4
    GPIO0-8
    PIN_J2
    PIN_E13
    input
    A通道输出D4端
    ADCA_D5
    GPIO0-7
    PIN_K1
    PIN_F14
    input
    A通道输出D5端
    ADCA_D6
    GPIO0-6
    PIN_K2
    PIN_F13
    input
    A通道输出D6端
    ADCA_D7
    GPIO0-5
    PIN_L1
    PIN_A19
    input
    A通道输出D7端
    ADCA_D8
    GPIO0-4
    PIN_L2
    PIN_A18
    input
    A通道输出D8端
    ADCA_D9
    GPIO0-3
    PIN_N1
    PIN_A16
    input
    A通道输出D9端
    ADCA_D10
    GPIO0-2
    PIN_N2
    PIN_A15
    input
    A通道输出D10端
    ADCA_D11
    GPIO0-1
    PIN_P2
    PIN_A14
    input
    A通道输出D11端,LSB
    CLKA
    GPIO0-0
    PIN_R1
    PIN_A13
    output
    ADCA时钟,最高支持65MHz
    ADCB_D0
    GPIO0-26
    PIN_B1
    PIN_F16
    input
    B通道输出D0端,MSB
    ADCB_D1
    GPIO0-25
    PIN_D3
    PIN_C19
    input
    B通道输出D1端
    ADCB_D2
    GPIO0-24
    PIN_E5
    PIN_C18
    input
    B通道输出D2端
    ADCB_D3
    GPIO0-23
    PIN_D1
    PIN_B18
    input
    B通道输出D3端
    ADCB_D4
    GPIO0-22
    PIN_F1
    PIN_B17
    input
    B通道输出D4端
    ADCB_D5
    GPIO0-21
    PIN_F5
    PIN_D16
    input
    B通道输出D5端
    ADCB_D6
    GPIO0-20
    PIN_F2
    PIN_E16
    input
    B通道输出D6端
    ADCB_D7
    GPIO0-19
    PIN_G2
    PIN_C17
    input
    B通道输出D7端
    ADCB_D8
    GPIO0-18
    PIN_G1
    PIN_D17
    input
    B通道输出D8端
    ADCB_D9
    GPIO0-17
    PIN_F3
    PIN_B16
    input
    B通道输出D9端
    ADCB_D10
    GPIO0-16
    PIN_G5
    PIN_B15
    input
    B通道输出D10端
    ADCB_D11
    GPIO0-15
    PIN_J6
    PIN_C15
    input
    B通道输出D11端,LSB
    CLKB
    GPIO0-14
    PIN_K5
    PIN_C14
    output
    ADCB时钟,最高支持65MHz
    在此再次特别提醒:AD9226的12位输出数据接口中,bit11为LSB、bit0为MSB,这与我们FPGA中对于多位宽信号的高低位的处理恰好相反,所以使用时,要么在分配引脚时直接调换过来,要么在程序中对所有位的高低位置进行调换。不然采集到的数据将看不到规律。
    1.5.2硬件连接
    和前面的描述一致,我们连接好ACM9767,示波器,ACM9226,720FPGA开发板电源、下载器、串口连接线。完成后如下图:

    033.png

    在信号发生器上设定好采样频率,我们这里设定为100k的正弦波,此时,示波器就会显示出相应的波形信息:

    034.png

    给FPGA开发板上电,然后确认文件路径正确后,烧写我们编写好的程序bit文件,

    035.png

    036.png

    程序烧写完成后,开发板的led0和led1的灯会点亮。

    037.png

    此时表明:锁相环工作正常,ddr3初始化正常。

    038.png

        依次设定好com端口,波特率,然后打开串口,清空计数器和接收区后,点击第1,2,3条手动发送按钮,数据设定完成后开始采集。

    039.png

    可以看到,采集的数据和下发的指令是匹配的。
    再看我们工程生成的RTL级Schematic图,和我们的工程介绍,也是吻合的。
    040.png


    1.6.数据的简易分析与评定
    前面的实验能够进行,能够得出结论,但是采样得到的数据是否有丢失的情况发生,仅凭人工,无法完成这个分析工作。因此我们需要借助matlab的打印函数图形的功能。
    下面给出matlab数据分析代码函数部分的简单介绍:
      
    src_data=textread('C:\Users\Administrator\Desktop\003.txt
      
    ','%s');
      
    src_data_hex=hex2dec(src_data)
      
    DATA_NUM = length(src_data_hex);
      
    voltage_code = 1:DATA_NUM/2;
      
    voltage_code = voltage_code';
      
    for i=1:1:DATA_NUM/2
      
       if  src_data_hex(2*i-1)+src_data_hex(i*2)*256>2048
      
        wave_data(i)  = src_data_hex(2*i-1)+src_data_hex(i*2)*256-4096;
      
      else
      
        wave_data(i)  = src_data_hex(2*i-1)+src_data_hex(i*2)*256;
      
      end
      
    end
       
      
           代码的第一行,指定的是数据文件的路径及格式,使用时执行matlab程序前替换第一个单引号内为自己需要打印的数据的文件位置、名称和格式,代码的第二行,是将16进制转为10进制的函数运算,代码的第三行,是计算转换后的数据的总长度,代码的第四行,是对采样得到的数据进行减半,以还原从8bit到16bit的数据原貌。下方的循环语句,用来判断纵坐标的极值是否超过2048,如果超过2048,则整个图形向下平移4096个单位,如果极值没有超出2048,则保持不变。最后一句是执行matlab的打印指令。
    为了保证我们的波形能够准确体现实验结果并且显示直观,我们采用200k频率下只进行2048个点的采样输出策略,只要保证这2048个点能够完全覆盖一个周期,就可以证明我们的工程是能够得到验证的。
    打开matlab代码的工程文件,修改好文件路径,进行保存后点击运行:

    041.png

    输出得到的波形如图:

    042.png

    这样,工程的上板实验数据,就得到了验证。
    另外我们给出4096点采样下,1Mhz的发生频率,200khz的发生频率,100khz的发生频率和50khz的发生频率图,供大家参考。

    043.png

    1.7.总结
    通过本实验,我们介绍了如下知识点:
    1、ACM9226模块的使用方式和硬件连接方法
    2、串口发码程序向FPGA发布工作控制指令的设计和应用方法
    3、二端口带双fifo的ddr3模块使用方法
    4、含二端口带双fifo的ddr3仿真模块使用注意事项
    5、本工程的数据运行流程和状态机的状态转换策略
    6、matlab数据绘图分析方法和程序代码
    这些知识点,你都收获了吗?







    017.png

    ACX720_ad9226_ddr3_uart_pdf_V4.2.rar

    16.49 MB, 下载次数: 804

    回复

    使用道具 举报

  • TA的每日心情
    开心
    2021-12-31 09:03
  • 71

    主题

    79

    帖子

    967

    积分

    高级会员

    Rank: 6Rank: 6

    积分
    967
     楼主| 发表于 2022-3-28 11:43:49 | 显示全部楼层
    提示:最后提供的资料包内有本说明书的pdf文档
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|小黑屋|Archiver|芯路恒电子技术论坛 |鄂ICP备2021003648号

    GMT+8, 2024-5-17 12:22 , Processed in 0.134066 second(s), 34 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc. Template By 【未来科技】【 www.wekei.cn 】

    快速回复 返回顶部 返回列表