ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)

一、实验介绍

基本原理参考文章:ZYNQ实验—IQ调制实现SSB PART1,本实验将实现参考文章中的PS-PL间的数据转发功能。实验中PS端的数据存在DDR中,PS端通过AXI-stream FIFO将数据转变为流模式输出。

实验使用AXI-stream FIFO和AXI4-stream Data FIFO两个IP核希望实现以下功能:

  • AXI接口转换为AXI Stream接口
  • AXI Stream 流的异步读写

二、实验设置

实验框图

FIFO写入时钟200MHz,读出时钟50MHz,FIFO大小4096*32bits,实验中DDR循环输出实验数据,利用示波器观察输出波形分析结果。
注意:这里的写入时钟只是FIFO的写入时钟并不等于PS通过AXI写入FIFO的时钟速率
ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)_第1张图片

测试数据

Matlab测试数据生成

fs_au  = 1024E4;      % 实验中以1024个数据为一包数据,因此fs_au为1024的整数倍时,在ZYNQ端输出为整周期数据
t = 0:1/fs_au:0.002;  % 生成序列,步进为1/fs_au

% 生成正弦信号
f = 1E5;              % 正弦信号频率为100kHz
x = sin(2*pi*f*t);
y_hilbert=fi(hilbert(x), 1, 16); %定点化数据

y_real=real(y_hilbert);
y_imag=imag(y_hilbert);

% 绘制正弦信号
plot(t, y_real);
xlabel('时间(秒)');
ylabel('幅度');
ylim([-2 2]);
title('1kHz正弦信号');
grid on;

IP设置

  1. AXI-stream FIFO:实现AXI接口转换为AXI Stream接口。
    注:AXI-stream FIFO使用存储转发模式,每次读写需达到设置长度才会开始进行读写。
    ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)_第2张图片
  2. AXI4-stream Data FIFO:AXI Stream流的异步读写
    ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)_第3张图片
    实验中的FIFO连接
    ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)_第4张图片
    将连接起来的两个IP核视为一个FIFO,这个FIFO可以实现异步读写并且使用AXI接口写入,AXI Stream接口读出。
    ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)_第5张图片

FIFO读写

实验中的FIFO数据输入来自PS,数据输出则通过PL输出到DAC中。DAC需要的数据是匀速持续输出的,FIFO的读写采用半空读写机制保证AXIS始终都能读到有效的数据。
FIFO半空读写示例:
FIFO初始化写满FIFO (FIFO大小为4096*32bits)
ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)_第6张图片
FIFO半空写入
ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)_第7张图片

读写问题

  FIFO是一种先入先出的存储结构不需要数据地址,实验中的FIFO支持全双工读写。因此只需保证AXIS读取一半数据的时间内我们及时写入接下来要输出的数据即可保证AXIS端的输出是连续的,但问题在于 PS写入AXI-stream FIFO的速率较慢很难跟上PL端几十兆频率的操作,因此如何平衡PS与PL的数据操作速率是本实验想要研究和讨论的重点。

三、实验过程

  输入输出速率不匹配的问题在数字信号处理中经常会遇到,不对等的操作很容易导致数据丢失或者数据不连续,这样的情况在要求准确连续的项目中是不允许出现的,解决这个问题我们需要先找到整个操作速率最慢的部分。

实验主要代码

//初始化FIFO
DDR_rd(0,4096,IQchioce);
Status = FIFOTxSend(&FifoInstance, FIFOSourceBuffer);//FIFOTxSend是FIFO示例中的发送函数
while(1)
{
	//UDP是按512个数据发送到DDR中的,因此读取2048是从DDR中读4组数据
	for(i=0;i<cmd_picenum;i+=4)
	{
		 // 半空状态读取
		Status = XLlFifo_Status(&FifoInstance);
		Halfempty= Status & 0x00200000;
		if(Halfempty)
		{
			//DDR读取数据,幅值到FIFOSourceBuffer
			  DDR_rd(0,2048,IQchioce);
			//发送数据至FIFO。循环写入相同的2048个数据
			  XLlFifo_IntClear(&FifoInstance,0xffffffff);
			  Status = FIFOTxSend2(&FifoInstance, FIFOSourceBuffer);//FIFOTxSend2只发送2048个数据的
			  if (Status != XST_SUCCESS){
			  xil_printf("Transmisson of Data failed\n\r");
			  return XST_FAILURE;}
			  memset(FIFOSourceBuffer2,0,2048);
		}
		else
		{
			  i=i-4;
		}
	}}

1. AXI-stream FIFO为存储转发模式对读写的影响

  本实验中连接PS端的AXI-stream FIFO为存储转发模式,在该模式下每次读写需达到设置长度才会开始进行读写(具体代码如下)。AXI-stream FIFO每一次写入数据需要等待XLlFifo_iTxSetLen都设置完TLR长度寄存器后数据才开始传输,因此一次写入需要的数据越多等待的时间越长。

  1. 2048个数据波形
    图中是2048个数据的输出波形。根据Matlab生成的正弦信号读取2048个数据应该正好是20个周期,因此示波器显示的波形说明AXIS端成功读取到了2048个数据。
    ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)_第8张图片
  2. 循环写入相同2048个数据
    图中展示了在PS端循环写入相同的2048个数据并经过DAC后的输出情况。从图中可以很明显的看出两次相同读写情况下中间存在780us的等待间隔,说明AXIS端读取完数据后还需要等待下一组2048个数据的写入完成 (大概780us)
    ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)_第9张图片
  3. 循环写入相同4096个数据
    当把循环写入的数据增加为4096个数据,可以发现两组数据间隔时间翻倍变为1.56ms=2*780us
    ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)_第10张图片
  4. 上述实验情况表现出写入数据时间越多间隔时间越长,说明DDR写入AXI-stream FIFO一个数据的时间是固定的,
    设 NUM为传输数据个数,T为间隔时间,t为一个数据写入时间
    t = T / N U M = 780 u s / 2048 = 0.38 u s t=T/NUM=780us/2048=0.38us t=T/NUM=780us/2048=0.38us
    说明
      以前很多情况下使用FIFO时写入数据的速度都比较快,当我们确定输出数据率时,可以通过输出数据率反推去确定FIFO的大小。一般情况下FIFO空间越大,半空时的下一片数据写入时间便越长(即写入缓冲时间越长),因此通过增大FIFO空间就可以缓解输入输出速率不匹配的问题。
      本文中的实验通过实现发现PS端将数据从DDR写入到FIFO中速率很慢 (大概2.5MHz的频率输出一个数据),所以输出端很容易就会读到空数据导致分片数据间存在等待间隔,因此针对本文的情况我们需要先计算最大的写入速率后修改输出速率 (输出速率不能大于输入速率,否则缓冲时间不够),单纯的只增加FIFO空间并无法改善上述实验出现的情况。

2. DDR循环数据读出对读写的影响

实验采用间接测量的方法去观察DDR读写的时间,我们将实验代码中的DDR读写操作注释掉其他代码不变观察波形变化

if(Halfempty)
{
	//DDR读取数据
	//DDR_rd(0,2048,IQchioce);
	//发送数据至FIFO。循环写入相同的2048个数据
	XLlFifo_IntClear(&FifoInstance,0xffffffff);
	Status = FIFOTxSend(&FifoInstance, FIFOSourceBuffer);
	if (Status != XST_SUCCESS){
	xil_printf("Transmisson of Data failed\n\r");
	return XST_FAILURE;}
	//memset(FIFOSourceBuffer2,0,2048);
}

在循环传输同样的2048个数据下,去除DDR读数据代码,发现两次操作的间隔时间从780us变为了660us,由此可以大致推断出DDR读取2048个数据需要120us (大概17MHz的频率读取一个数据)
ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)_第11张图片

3. PS与PL的速率匹配

  通过1,2的实验得到的基本结论是在目前搭建的框架下,PS最多只能实现2.5MHz频率的数据写入,因后续实验的需要将M_CLK调整为16kHz再次进行实验,图中的正弦波形完好,数据连续,分片数据间不存在间隔。
ZYNQ实验 FIFO读写实验(如何平衡跨时钟域的读写)_第12张图片

四、实验结论

虽然实验成功了,但是这样的设计缺陷在于我们只能用于低速率场景的应用,如需提高速率应该使用DMA进行AXI到AXIS的数据转换。设计工程中如果涉及到异步数据传输的情况,一定要了解清楚不同端口传输速率的上下门限,在不清楚传输速率的情况下设计系统一定会出现数据丢失,时序混乱的情况。

目前我接触过的简单的测量端口数据率的方法(可能存在不合理的仅供参考,以后学习更系统的方法后再做记录):

  • 本实验中的结合DAC输出测试信号通过示波器去观察信号的时序情况
  • 还可以在模块中设计计数信号,从而记录每一个模块输出速率情况
  • 数据回环,发出后又再次接收看信号中间的间隔

参考资料

ZYNQ学习–AXI_Stream_FIFO
ZYNQ学习–AXI4-Stream data FIFO && FIFO的ADDA实验
AXI_Stream_FIFO 手册

你可能感兴趣的:(ZYNQ学习笔记,fpga开发)