集成电路技术分享

 找回密码
 我要注册

QQ登录

只需一步,快速开始

搜索
查看: 1444|回复: 0

FPGA编程时的一些实际问题阐述及解决方案详解 - 全文

[复制链接]
月影星痕 发表于 2019-8-25 11:39:35 | 显示全部楼层 |阅读模式
随着NI的FPGA产品的广泛使用,很多同事和客户都碰到了一些FPGA编程时遇到的问题。由于FPGA不能实时调试,每次修改一点代码之后都要编译很长时间之后才能看到修改的效果,所以,我们希望尽量在FPGA编写代码时就将更多的问题考虑到位。本文针对项目过程中碰到的一些实际问题进行阐述,希望可以为大家在FPGA编程过程中提供一些帮助。
项目描述:该项目是一个实时频谱监测、流盘以及跳频信号检测的需求。具体参数是IQ速率为100MHz,流盘5分钟(要做类似Reference Trigger的效果,即按下按钮之前的一分钟和按下按钮之后的四分钟信号一起流盘),检测跳频信号的时间点和相应的频点,其中跳频信号的参数是:突发性,每次持续1ms~20ms,跳频信号在每个频点上的持续时间是1us~20us,跳频频率70000/s,每个频点上的信号带宽是5MHz;使用的硬件是5792+7966.其中与FPGA相关的部分就是数据采集和跳频信号的检测。对于数据采集部分,5792有专门的采集范例可以供大家参考,而跳频信号的检测算法是将数据每隔128个点做一次FFT(100M的采样率,对于1us的跳频信号持续时间,对应为100个时域采样点)。做出的FFT结果如果超过阈值,则将FFT结果的序号回传给上位机进行保存。
FPGA中FIFO的使用使得FPGA端和上位机端在很多时候都可以异步操作。上位机中没有有效的数据传递到FPGA端,FPGA端就不会进行有效的计算并传输无效的数据。但在有些情况下,FPGA端与上位机端需要进行握手的操作。比如:一个项目需要通过Adapter端口进行数据采集,然后将数据传回到上位机。这种情况下,如果FPGA先于上位机开始执行,那么FPGA采集到的端口数据会迅速地填满FIFO(此时上位机还没有准备好去读取FIFO的数据)导致后续的数据无法保存到FIFO中(写入超时)。而当上位机开始读取FIFO时,会发现FIFO的前一段数据(数据的长度与FPGA端配置的FIFO大小有关)与后续的数据是非连续的。为了避免类似的问题,需要在FPGA与上位机之间握手。
通常用于FPGA程序与Host程序同步的方法是使用一个握手控件。在FPGA的主程序之前,使用一个while循环,条件接线端链接着布尔控件。在上位机中,当一切准备就绪时(对FPGA的初始化以及其他初始化工作),可以为FPGA的Start控件赋上真值,这样,FPGA与Host端的数据传输就同步了,这是非常容易实现的方法。代码如下:

另一种方法是使用FPGA中提供的中断。在FPGA端需要等待上位机的数据或者等待上位机做好接收数据的准备时,产生一个中断。该中断会阻塞程序直到该中断被确认。当上位机中准备好向FPGA传输数据或者接收来自FPGA的数据时,上位机可以对中断进行确认。代码如下:
FPGA中的很多运算都用整型或者定点数完成,这其中会经常碰到数据转换的问题。比如,前端Adaptor采集到的信号的位宽是14,如果在FPGA中对数据进行FFT运算,就需要将整型数据转换成定点数;很多时候,在将整型数转换成定点数时,有客户会问:我的整数位数应该设置为多少呢?其实在数据转换时,首先要搞清楚整条链路上数据转换的步骤。前端的Adaptor在进行AD采样时,将数据转换从DBL的模拟量量化成N位的整数。在量化的过程中,有一个量程的概念。比如量程为±M,那么转换成将以±M作为归一化的参考值。假设实际的模拟值为A,则A采样值

之所以乘以2^((N-1)),是将最高位作为符号位进行处理。进一步,在FPGA端,将I16的数据转换成定点数,道理是一样的。在转换成定点数时需要设置整数位数,这个整数位数就是在FPGA中进行定点转换时的量程。当然,这里的量程表示的范围与AD量化时的量程有可能是不匹配的,导致转换之后的定点数与采样之前的信号实际值是不一致的,但是没有关系,只要牢记转换过程中的相对关系,可以基于相对的转换值进行计算。在将数据传递到上位机之后,如果要获取绝对的数值,则可以按照转换过程中的相对关系进行还原,即进行增益补偿。
另一种可能出现的转换就是:如果DMA接收到的数据是64位,其中包含两个样值,而后续处理是以32位的Sample为单位的,这就需要将64位FIFO中取出的数据转换成32位的数据,然后写入后续的FIFO中。前文有提到过,DMA的最高传输速率是基于64位数据位宽的,所以,很多时候,为了追求Host与FPGA之间的高速数据传输,FPGA从Host端接收的是64位数据。本程序就涉及到将64位数据写入32位的FIFO。具体实现的方法是取出一个64位数据之后,拆分成高位和低位两部分。定时循环每隔两个循环读取一个数据,但每次循环都要向32位FIFO中写入数据。有人可能认为,这是很简单的事儿啊:只要用一个奇偶判断,奇数循环时写入高位,偶数循环时写入低位不就行了?但测试发现,在一个循环内部,不能出现多个FIFO写入,否则,编译器会提示无法决定数据源。另外,这种方法本身也是不可靠的,如果奇数循环在写入高位时出现了超时,那么在下一个循环(即偶数循环),应该重新写入高位数据。同理,如果偶数循环写入时发生了超时,那么在下一个循环(即奇数循环)应该重新写入低位数据。:
您需要登录后才可以回帖 登录 | 我要注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|小黑屋|手机版|Archiver|集成电路技术分享 ( 京ICP备20003123号-1 )

GMT+8, 2024-4-26 19:30 , Processed in 0.070767 second(s), 19 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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