2.7 FPGA图像处理的开发流程
2.7.1 需求分析及问题描述
无论最后的系统是基于硬件还是基于软件来实现的,对问题或者应用的详细描述都是最重要的阶段。如果没有恰当的问题描述或需求分析,那么就不可能衡量问题解决得好还是坏。
问题描述应该清楚地描述问题而不是解决方法。它应该包括系统
需要做什么、为什么要做,而不包括怎么做。为使描述更具体,至少需要讨论三个方面。第一是系统功能,也就是系统需要做什么。在一个图像处理应用中,需要详细说明图像处理后的预期结果。第二,必须讨论系统的性能,即说明系统完成这些功能的指标是什么。对于实时图像处理来说,允许的最大延时和每秒需要处理的帧数是两个很重要的指标。如果涉及分类,那么对于非一般的问题来说,错分是避免不了的,分类成功率就是一个设计指标。如果结果是二元的,那么允许错误率应该具体到错误接收率和错误拒绝率两方面。第三个需要考虑的方面是系统将要运行的环境。应用图像处理不仅仅包含图像处理算法,它是一个需要对整个系统进行考虑和说明的系统工程问题。其他需要考虑的重要方面包括照明、光学及所支持的硬件和机械接口。图像处理系统之间及其与整个工程系统其他部分之间的联系也需要认真地说明和定义。
问题说明必须全面,不仅要考虑常运作,还要考虑在特殊环境下系统该怎么运作。如果系统是交互式的,那么用户和系统之间的接口需要定义清楚。描述不仅应该考虑系统的运作,而且应该讨论系统的可靠性和超过系统预期寿命所需要的维修。同样,系统所有的方面都应该讨论,而不仅仅是图像处理部分。
由问题描述定义的系统必须是可实现的,这样才能可观地评估整体系统以证实它满足描述。因此需求定量,并且要尽量避免使用一些含糊的词,如过多的、充分的、耐久的,等等。确定系统的约束条件是很重要的,对于嵌入式实时系统,包括帧频、系统延迟、尺寸、量、功耗及成本约束。要求组成的集合也必须是相容的。强约束条件和弱约束条件应该有区别。不同的约束条件可能有冲突,尤其是实时操作,一个常见的冲突是速度和精度之间。这些冲突必须在开发之前解决。
重构的问题描述需要全面了解问题或任务。这种了解是很重要的,因为它是提高应用层鲁棒性的前提。它用来选择具有代表性的图像采集用于开发和检测图像处理算法。在算法开发过程中,也能用来指导要检测的图像特征的选择。没有对这些问题的了解很容易对人物本身做出无效的假设。系统开发者如果对问题了解地不够全面,往往会导致算法只能在特定的条件下运行,缺乏足够的鲁棒性和适用性。在这种情况下,与客户或者其他问题领域专家进行定期的反馈和验证是十分有必要的,尤其是在算法开发阶段。
2.7.2 软件算法设计及验证
实际上,软件开发及验证会适当地在硬件设计之前进行,这是由于软件的复杂性会对系统硬件架构、硬件选型及资源和消耗产生影响。
我们往往不是急着去设计和开发FPGA,实际上很少直接在FPGA上开发图像处理算法,这主要是由于在FPGA上调试算法周期过长,即使仅仅做仿真工作所消耗的时间也远远比软件多。如果在硬件上进行映射,其综合、编译和布局布线的时间花费更是无法令人接受。大部分情况下,FPGA更多的是仅仅作为一个映射工具。
将算法开发和FPGA实现分离出来的好处之一是在将算法映射到目标硬件之前可以完全测试应用层算法。这些测试在基于软件的图像处理环境中更容易实现,特别是在需要大批量的图像样本时。通常情况下,Windows的图像处理开发平台是Matlab或VisualStudio。硬件平台需要至少一个相机来捕获图像,软件平台只需一个简单的接口即可获得图像源。硬件映射的软件开发尽可能少地使用OpenCV等开源项目接口,除非对这些接口非常熟悉,否则将会使硬件映射工作变得异常复杂。此外,避免使用一些复杂的数据结构或是基于C++机制的接口。之所以有这个方面的考虑,主要是因为在整个系统中的上层应用可能有DSP等处理的部分。虽然DSP支持C++,但是其效率相对于C语言比较低,采用基于C语言的代码风格可以大大减轻下位机的移植工作量。
在软件设计的过程中,另一个需要重点关注的问题是算法的精度,这就需要我们小心地处理浮点运算。在图像处理算法中,大部分的算法都涉及浮点运算,而在FPGA中,浮点运算是非常昂贵的(详见映射技术相关章节),这时将浮点运算转换为定点运算是十分有必要的。定点转换带来的首要问题就是计算精度的下降,精度的丢失很有可能造成算法失效,在软件测试的时候要仔细评估计算精度的丢失对整个系统带来的影响,并以此评估在FPGA中定点转换的位数。
2.7.3 硬件平台设计
硬件平台的设计往往会和软件开发同时进行。硬件平台的设计需要依赖于软件的复杂度,通常一个算法的测试及改进是一个周期很长的任务,如果硬件平台的设计等步骤到软件完全成熟时再进行,那么时间成本是非常高的。硬件平台的设计在算法开发基本功能验证之后就可以对其进行整体评估。实际上,在进行硬件结构设计时算法已经成熟,做硬件映射工作或对算法有足够的了解,就可以直接利用经验来设计硬件平台。
1.软件与硬件的划分
硬件平台设计的第一步是合理地划分硬件和软件。这里的硬件是指算法由FPGA逻辑实现,软件是指算法由DSP、ARM或单片机软件编程实现。规则的底层图像处理操作(如形态学滤波、Sobel算子、均值滤波等)具有计算数据量大、结构规则并行等特点,非常适合于用FPGA硬件实现。不规则的底层图像处理操作(如具有动态可变长度循环的算法)和串行顶层图像处理操作(如弹道计算、任务判决融合等)用FPGA实现会非常繁琐且效率较低,此类操作用软件实现效率较高,开发难度较低。
在软件中实现的常用两类操作或任务是高级图像处理操作和结构复杂的通信协议。高级图像处理操作的特点是数据量小但控制模式较为复杂。许多操作的并行性有限,并且通常来说计算所采用的步骤取决于数据。类似地,通信协议如USB,TCP/IP,需要一个复杂的协议栈来支持上层协议。虽然这些任务能够在FPGA中实现,但是就资源利用率上来说在软件中实现更有效且简单。用FPGA来管理和操作一个复杂的协议是非常令人头疼的一项工作。
应用程序的软件与硬件划分所采用的主要方法主要取决于系统级结构,尤其是软件处理器和可编程逻辑之间的耦合程度。软件处理器可以包括一个独立的CPU,如外部的ARM或是DSP处理器。此外,有的FPGA内部集成了CPU硬核,如Xinlinx Virtex Pro内的PowerPC。用FPGA实现的软核处理器也达到了一定程度的应用,如Altera的FPGA大部分器件支持其自家的软核处理器NIOS。此外,还有很多已经在FPGA上面实现的可用标准处理器,例如80C51,PIC等。使用标准处理器的一个好处是,针对这个处理器开发的所有应用软件都可以使用,尤其是使用处理器集成的高级语言开发和仿真工具,可加快软件部分的代码开发和调试。
无论怎么划分层级,清楚地定义软件与硬件之间的接口与通信机制是基本的要求。尤其有必要设计同步和数据交换机制来促进数据流的平滑。在最终的设计中,考虑所设计的硬件和软件之间的通信开销也是必不可少的。
2.资源评估与FPGA选型
在硬件方案确定之后,在确定具体的FPGA型号之前,对整个系统所消耗的资源进行预估是十分必要的。对于图像处理系统来讲,比较敏感的资源是存储器资源。无论是处理算法中的行缓存、帧缓存还是显示缓存,都不可避免地要用到片上存储器。此外,系统需预留一定的资源作为调试资源。通常情况下,资源比较多的FPGA成本比较高,因此,将图像缓存放在片外也是常用的解决方法之一。
此外,FPGA所拥有的一些高速接口资源也是重要的考虑因素,这主要考虑到视频处理的高带宽特点。
2.7.4 FPGA映射
FPGA映射是将软件算法转换为FPGA设计的过程。这个过程并不是直接简单地把操作级算法移植到FPGA(除非这些算法是用硬件的方式开发的),而是把软件的功能通过修改算法映射到硬件上面。
映射在不同抽象层上需要进行不同的考虑。在较高级上,应用级算法在映射到硬件之前应该全部在基于软件的平台上进行测试。在一些情况下,也许需要修改不同的图像处理操作来获得统一的计算结构。通常情况下,应用级算法在映射过程中不应该改变很多。映射个别的图像处理操作又是另一种过程。利用并行性操作级算法可以改变很多。对于一些操作,从串行到并行算法的转换是直接的,然而对于其他操作完全是一个崭新的方法并且算法可能需要重新开发。
在映射过程中,不仅考虑操作本身,有时候也需要将它们作为一个序列来考虑。通过合成邻近的操作并且开发一个算法来实现这个合成操作有可能简化处理过程。在其他实例中通过将一个操作分离成一系列简单的操作有可能简化处理过程。例如,将一个可分离的滤波器分离成两个简单的滤波器。在一些情况下,交换操作的顺序可以减少硬件需求。例如,与等价的先完成阈值操作再使用二值形态学滤波器相比,由阈值处理跟随的灰度形态学滤波器需要一个更复杂的滤波器。
任何实时应用都有时序约束问题。这个约束分为两类:吞吐量和延迟。流操作有吞吐量约束,通常每个时钟周期处理一个像素。如果不能维持这个速度,那么从相机流出的数据可能丢失,或者流向显示器的数据可能错过。由于处理操作每个像素所用的时间要远远长于一个时钟周期,因此,有必要采用流水线结构来保持吞吐量。另外一个时序约束是延迟。这是指从采集图像到输出结果或者完成一个动作的最大可容许空间。延迟对于使用图像处理结果反馈以控制状态的实时控制应用来讲尤为重要。控制系统反馈的延迟会影响闭环系统的响应时间,并且使得控制困难,过长的延时还会影响系统的稳定性。
与时序约束紧密相关的是存储器带宽约束,每个时钟周期仅能访问一个存储器端口。片上存储器遇到这样的问题通常会少一点,因为这些存储器包括很多相当小的模块,每个模块都能独立访问。但是片外存储器的访问一般都在较大的整片模块上进行,对于计算顺序和操作窗口顺序不相关的操作通常需要缓存整帧图像。大尺寸的图像缓存通常放在片外。因此,每个时钟要读取多于一个的像素是很难的。流水线式的存储结构更为复杂,其中在数据可用之前,地址需要提前几个时钟周期提供。由于片上存储器的带宽约束比较宽松,因此,将片外存储器的数据转移到片上的多个模块通常是很有必要的。
此外,还有一个约束与FPGA上可利用的资源有关。一个FPGA的成本通常是随着尺寸的增加而增加的,因此,充分利用资源是十分必要的。使用较少的资源可以通过两个方案提高时序。第一个方案,也是较明显的方案,是使用较少资源的算法,由于其较窄的逻辑深度因而通常有较短的延迟。第二个方案是采用较规律的设计以便在FPGA上更容易地布线,并且获得较短的布线延迟。随着设计的深入,FPGA的容量逐渐用完,有效布线变得越来越难,并且所设计的最大时钟也会变得越来越低。
与资源有关的第二个问题是共享资源之间的竞争。一个并行的实现会有多个并行的模块同时工作。尤其是,在任何一个时钟周期,只有一个过程能够访问存储器或者写入存储器。对共享资源的同时访问必须规划好以避免冲突,或者可以设计额外的仲裁电路来限制对一个操作的访问。仲裁设计会延迟一些操作,使得确定任务的延时变得更难。
2.7.5 仿真及验证
在FPGA映射之后,接下来的重点工作是对设计的系统进行仿真和验证。在FPGA代码撰写完毕时对其进行功能测试是十分有必要的。我们将在仿真测试章节详细介绍功能仿真。
在硬件中的在线调试也是十分必要的。最简单的方法是将主信号布线到不用的IO口上,使得它们从FPGA外部是可观测的,在外部使用一个示波器或是逻辑分析仪来监控信号。此外,Xilinx和Altera厂商提供的IDE中也提供了虚拟的逻辑分析仪来辅助调试。不过,辅助调试手段需要占用片内的存储器资源。
第3章 FPGA编程语言
虽然本书不是一本专门介绍硬件和描述语言语法及应用的教材,但是考虑到本书中会较多地出现一些算法和测试代码,因此有必要首先介绍下主要的开发语言及常用的语法(本书仅对硬件描述语言进行介绍)。
实际上,本书中介绍的大部分案例是以Verilog语言作为基础的。因此,本书将会针对Verilog语言列出一些常见的语法及应用,方便读者理解实例中的代码。
3.1 HDL语言简介
HDL语言即硬件描述语言,在传统的电子GUI设计已经越来越不能满足人们更大的“胃口”之后,硬件描述语言应运而生。这里的“大胃口”指的是更高层面的更加抽象的建模与设计,例如图像处理中的算法处理流程。
硬件描述语言产生于20世纪80年代,需要注意的是这个名字“硬件描述”很好地总结了这种语言的精髓。有些初学者在刚开始学Verilog的时候,可能把它当成一门类似于C的“软件”语言。实际上
几乎所有的关于Verilog的介绍都要把它和C语言扯上一点关系,这样就给初学者一种错觉:这个语言是类似于C语言的一门语言,C语言的设计思想和思维都可以“移植”过来。这种想法对于初学者是极其危险的。硬件描述语言的本质就是绘制电路,只是很多电路直接用传统的GUI设计工具,如Cadance,PADS等绘制起来比较复杂或是难以加以描述,硬件描述语言就负责把这些需求给“描述”出来。这就是为什么我们在设计工具里面会有原理图设计方法,并可以和其他的硬件描述文件无缝对接。
VHDL和Verilog无疑是FPGA和ASIC设计领域最为广泛应用的硬件描述语言,并且都有各自的IEEE标准。就从笔者的应用经验来讲,两个语言没有太大的区别。一般情况下,在各类高校,研究机构,和军工院,使用VHDL的较多。而在国内大部分公司,使用Verilog比较多。就语法而言,Verilog紧凑易学,上手快,但是比起VHDL不够严谨,因此初学者往往更容易犯错误。
初学者往往为选择哪个语言而纠结。实际上,如何选择语言是根据需求方来定的。例如客户要求,或是公司的规定。所有的语言都是工具,最重要的是编程的思想和思维,也就是解决事情的方法。因此,建议两门语言最好都要学,在实践中,精通一门常用的语言,但是要做到能够熟练阅读另外一门语言。
非常幸运的是,我们已经有了“先驱者”解决两门语言的转换问题,这个软件就是HDL-X,可以完美实现Verilog与VHDL的相互转换,使用方法也很简单,X-HDL使用界面如图3-1所示。
选择转换方向、源文件和目标路径,在菜单栏Aciton中选择Translate即可。这个转换工具并不能保证成功率和转换效率,在转换完成之后还需要对一些细节进行修正处理。一般情况下,在阅读另外一种语言的设计文件时,可把它转换为自己所熟悉的程序语言来提高可读性。