前文已经介绍了DDR3和AXI4总线的相关知识,我们知道MIG ip核除了可以生成native接口还能生成AXI4接口,今天就练习一下将AXI4接口的DDR3打包成FIFO。首先我们生成一个AXI4接口的MIG ip核,其余步骤与Native接口的ip核相同,如果我们勾选AXI4接口的话,会多出如下界面的配置,
Data Width:表示axi_full接口读写数据的位宽,如果前面将DDR3芯片时钟设置为用户时钟频率的4倍,那么此处将读写数据位宽设置为DDR3数据位宽的8倍时,读写速率达到最大。原因在于DDR3芯片的突发一般是8,如果DDR3一次传输16位,8次传输128位数据,且DDR3的时钟是用户时钟的4倍,双沿传输数据。那么DDR3芯片突发一次,用户也只能传输一次数据,当用户一次传输数据位宽等于DDR3一次突发传输数据时,效率达到最大。但前面我们的摄像头输入数据是16位,因此在这里的位宽设置为128时并不能达到最大传输速率。
Arbitration Scheme:仲裁机制,由于DDR3芯片只有一组数据,而axi_full的读、写接口支持同时传输数据。当选用“TDM”时,读、写操作同时到达时,将交替进行。由于MIG IP自带仲裁机制,用户侧就不需要再考虑读写仲裁问题。
Narrow Burst设置位0即可。
地址位宽会根据DDR3芯片型号自动得到,不能设置。
ID位宽,axi_full协议每个通道都有ID信号,这里需要设置该信号位宽,默认即可。
接下来进行DDR3读写控制的设计,整体思路如下:
首先确定读、写FIFO的突发长度,然后根据写FIFO的读突发长度拉高开始信号,还需要声明一个状态变量,确定当前是否为写状态,DDR3初始化完成且当前状态不是写状态且写FIFO的读计数达到突发长度且当前写FIFO的读复位忙处于低电平时拉高开始信号,与此同时拉高s_axi_awvalid信号,当写地址通道握手成功后拉高s_axi_wvalid信号,实现写数据通道握手,开始向DDR3中写入数据,同时进入写状态,当前数据为一次突发写数据的最后一位时拉高s_axi_wlast信号,当s_axi_wlast与s_axi_wready与s_axi_wvalid信号同时为高时拉高s_axi_bready信号,与s_axi_bvalid信号进行握手,再定义一个写地址计数器对地址进行计数,需要注意的是每完成一次突发写后,地址并不是加一,突发写长度设置为128,位宽为128,而一个地址能够存储一个字节也就是8bit数据,因此每完成一次突发写地址应该加上128×128÷8=2048,当写地址达到设置的最大地址时可认为读出数据是有效的;进入读数据工程,定义一个读开始信号,当然此处的读是由DDR3中读取数据到读FIFO中,定义一个读状态,当前状态不是读状态且读FIFO的写侧不处于复位状态且读FIFO的写侧数据个数小于一次突发长度且读数据有效信号时拉高读开始信号,同时进入读状态,当检测到读开始信号拉高后拉高s_axi_arvalid与s_axi_ar_arready进行写通道握手,握手成功后紧接着拉高s_axi_rready信号,进行读数据通道握手当s_axi_rlast与s_axi_rvalid同时为高时拉低s_axi_rready信号,读过程结束。关于读写FIFO的读写使能信号,可以在写数据通道成功握手时拉高写FIFO的读使能信号,向DDR3中写入数据,同样的,可以将s_axi_rvalid赋值给读FIFO的写有效信号,同时声明两个读写复位计数器,当计数器计满时表示复位完成,防止FIFO初始化还没有完成就向里面写入数据。
下面来看仿真,整个仿真过程可以说是一波三折,首先就是部分信号的位宽对不上,导致仿真过程出现未知态,信号也失去了驱动能力,还有就是用VSC自动生产的teastbench,读写地址的最大值最小值信号也在testbench中进行了声明,但我没有对它们进行赋值,从而出现了未知态。
然后就是本次仿真最头疼也是最简单的问题,如下图所示,其他错误改正后可以进行仿真,但是我的s_axi_awready信号总是在s_axi_awvalid拉高的同时马上拉低,导致写地址通道不能完成握手,困扰我两天半后终于让我发现了问题,问题也很简单,读写控制模块中的复位信号是由MIG ip核输出的,而这个复位信号是高电平有效信号,我平时用的都是低电平复位信号,因此才会出现这种问题,浪费了好长时间,希望自己以后可以仔细一点,同时以后一定要搞清楚每个信号的来源和作用,防止这种错误再发生。
仿真验证:
复位完成,写FIFO读侧数据等于一次突发长度减2,拉高开始信号,进入写状态。
同时拉高s_axi_awvalid信号,完成写地址通道握手,握手完成后立马拉高s_axi_wvalid信号,进行写数据通道握手。
开始写入数据。
当前数据为一次突发写最后一位数据且写数据通道完成握手。
写响应通道握手。
开始读取数据。
读地址握手。
读地址握手完成立马拉高s_axi_rready信号。
读取第一个数据。