基本原理参考文章:ZYNQ实验—IQ调制实现SSB PART1,本实验将实现参考文章中的PS-PL间的数据转发功能。实验中PS端的数据存在DDR中,PS端通过AXI-stream FIFO将数据转变为流模式输出。
实验使用AXI-stream FIFO和AXI4-stream Data FIFO两个IP核希望实现以下功能:
FIFO写入时钟200MHz,读出时钟50MHz,FIFO大小4096*32bits,实验中DDR循环输出实验数据,利用示波器观察输出波形分析结果。
注意:这里的写入时钟只是FIFO的写入时钟并不等于PS通过AXI写入FIFO的时钟速率
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;
实验中的FIFO数据输入来自PS,数据输出则通过PL输出到DAC中。DAC需要的数据是匀速持续输出的,FIFO的读写采用半空读写机制保证AXIS始终都能读到有效的数据。
FIFO半空读写示例:
FIFO初始化写满FIFO (FIFO大小为4096*32bits)
FIFO半空写入
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;
}
}}
本实验中连接PS端的AXI-stream FIFO为存储转发模式,在该模式下每次读写需达到设置长度才会开始进行读写(具体代码如下)。AXI-stream FIFO每一次写入数据需要等待XLlFifo_iTxSetLen都设置完TLR长度寄存器后数据才开始传输,因此一次写入需要的数据越多等待的时间越长。
实验采用间接测量的方法去观察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的频率读取一个数据)
通过1,2的实验得到的基本结论是在目前搭建的框架下,PS最多只能实现2.5MHz频率的数据写入,因后续实验的需要将M_CLK调整为16kHz再次进行实验,图中的正弦波形完好,数据连续,分片数据间不存在间隔。
虽然实验成功了,但是这样的设计缺陷在于我们只能用于低速率场景的应用,如需提高速率应该使用DMA进行AXI到AXIS的数据转换。设计工程中如果涉及到异步数据传输的情况,一定要了解清楚不同端口传输速率的上下门限,在不清楚传输速率的情况下设计系统一定会出现数据丢失,时序混乱的情况。
目前我接触过的简单的测量端口数据率的方法(可能存在不合理的仅供参考,以后学习更系统的方法后再做记录):
ZYNQ学习–AXI_Stream_FIFO
ZYNQ学习–AXI4-Stream data FIFO && FIFO的ADDA实验
AXI_Stream_FIFO 手册