FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
登录
首页-所有问题-其他-正文

使用Vivado的‘High-Level Synthesis(HLS)’开发图像处理流水线,如何通过‘数据流(Dataflow)’优化和‘接口协议(AXI-Stream)’的使用来最大化吞吐量?

FPGA小学生FPGA小学生
其他
9小时前
0
0
0
用Vitis HLS写了一个图像滤波算法,综合出来的流水线性能不理想。听说正确使用Dataflow指令和AXI-Stream接口能极大提升性能。具体应该怎么组织函数和数据结构?如何判断数据依赖是否被正确打破?
FPGA小学生

FPGA小学生

这家伙真懒,几个字都不愿写!
1600
分享:
芯片封装中的‘先进封装(如2.5D/3D IC)’技术,对数字IC后端工程师和FPGA原型验证工程师的工作带来了哪些新的挑战和机遇?上一篇
作为FPGA初学者,用Verilog写了一个UART收发模块,但在板上测试时发现数据偶尔出错,应该如何系统地调试(从仿真、时序分析到板级测试)?下一篇
回答列表总数:5
  • 电子工程学生

    电子工程学生

    补充一些容易踩的坑和选择建议。

    首先,不是所有算法都适合无脑dataflow。如果步骤之间有严格的数据依赖,比如第二步必须等第一步完全算完所有结果才能开始(而不是第一个结果出来就能开始),那dataflow效果有限。图像滤波通常是滑动窗口,这种有局部依赖的,很适合用dataflow配合行缓存来实现。

    组织函数时,建议把缓存管理(比如生成滑动窗口)单独封装成一个函数,这个函数用stream输入原始像素,用stream输出窗口数据。这样卷积计算函数就只需要处理窗口,结构清晰。

    关于数据结构,在stream里传输的数据类型,尽量用原生C类型(如int, float)或者ap_fixed, ap_int。避免在stream里传复杂的struct,除非你很清楚综合后的硬件行为。

    判断依赖是否被打破,除了看报告,一定要做C仿真(C Simulation)和C/RTL协同仿真(Co-Simulation)。C仿真可以快速验证功能正确性,看看dataflow的逻辑对不对。C/RTL仿真虽然慢,但能最真实地看到硬件时序和行为,有没有背压(backpressure)问题一目了然。

    最后,如果吞吐量要求极高,可以考虑在dataflow里复制多个相同的处理单元,但这就需要手动做数据分配和收集了,复杂度会提高。先把手头的单流水线优化到极致再说。

    9小时前
  • 单片机初学者

    单片机初学者

    简单直接说下重点。

    目标:让数据源源不断流进来,处理完立马流出去,中间别卡住。

    怎么做?三步。

    第一,把你算法里顺序执行的几个大步骤,变成几个并行运行的函数。比如,第一步读像素,第二步做滤波,第三步写结果。这三个函数在dataflow区域里是同时工作的。

    第二,这几个函数之间别用数组或者全局变量传数据,就用hls::stream。一个函数往stream里写,下一个函数从里面读,自然就流水了。

    第三,每个函数自己也要优化好,用pipeline指令,争取II=1。

    怎么判断成功?看综合报告里的“Latency”和“Interval”。如果Interval远小于Latency,说明流水线起作用了。比如处理一帧要1000个周期,但每帧间隔(Interval)只有10个周期,那说明你差不多能同时处理100帧,吞吐量很高。

    另外,注意数据位宽要和AXI-Stream总线匹配,别浪费带宽。

    9小时前
  • 数字系统入门

    数字系统入门

    从接口协议的角度聊聊。用AXI-Stream就是为了让数据流动没有瓶颈。

    你需要确保两件事:一是HLS模块的顶层接口是AXI-Stream,二是模块内部的数据通路也是stream。

    具体操作:在顶层函数的参数里,对于输入输出数据,使用hls::stream类型,并加上#pragma HLS interface axis port=你的流变量。这样综合出来的IP核,数据输入输出就是标准的AXI-Stream接口,可以很容易地挂到PS-PL的数据流上,DMA可以连续不断地收发数据,不会像内存映射接口那样有寻址开销。

    在组织内部函数时,所有子函数之间的通信通道都用hls::stream。记住,hls::stream默认是FIFO,深度是2。如果你的某个处理阶段比较耗时,可能会导致上游数据没地方放而阻塞。这时候需要# pragma HLS stream depth=...来增加FIFO深度,比如设成几行图像的大小,作为缓冲区,让流水线更平滑。

    判断数据依赖是否打破,一个直观方法是看HLS生成的C/RTL协同仿真波形。观察各个stream的读写是否重叠进行。如果读和写是交错连续发生的,说明流水线运作良好;如果总是写完了停一阵才读,或者读完了等很久才有写,那说明依赖没处理好,或者FIFO深度不够。

    9小时前
  • 嵌入式小白菜

    嵌入式小白菜

    我最近刚调通一个类似的项目,分享点实际经验。

    除了楼上说的拆函数和用hls::stream,有几个细节很关键。第一,数据粒度要选好。比如你处理图像,不要一个像素一个像素地流,那样开销大。可以打包成一行像素,或者一个小的像素块(比如8x8),用ap_uint<128>这种宽数据类型在stream里传输,总线利用率高,吞吐量一下子就上来了。

    第二,每个子函数(也就是dataflow里的一个节点)内部最好也用#pragma HLS pipeline II=1优化一下,保证每个时钟周期都能吃进新数据。内外都是流水线,才是真的快。

    怎么判断数据依赖?Vitis HLS的综合报告里有个“Dependence Analysis”的部分,仔细看。它会告诉你哪些依赖是循环携带的(loop-carried),哪些是阻止流水化的。对于dataflow,还要看“Inter-iteration Dependence”。理想情况应该是“false”或者距离足够大。

    最后,仿真一定要做。用testbench灌入连续多帧图像,看输出是不是连续不断的,中间有没有停滞。波形图里看各个stream的valid和ready信号是不是几乎一直有效,如果是,那吞吐量就差不多了。

    9小时前
  • 电子系小白

    电子系小白

    这个问题很典型,HLS里Dataflow用不好,性能确实上不去。核心就一点:把算法拆成多个独立子任务,让数据像流水线一样在不同任务间流动,而不是等一个任务全做完再开始下一个。

    具体步骤:先把你整个滤波算法按处理步骤拆成几个函数,比如分成“像素读取”、“行缓存”、“卷积计算”、“结果输出”这几个阶段。然后在顶层函数里,用#pragma HLS dataflow把调用这些函数的区域包起来。

    数据结构尽量用hls::stream(对应AXI-Stream)。数据通过stream在函数间传递,天然就是流式的,依赖就打破了。判断依赖是否打破,最简单是看综合报告里的Timing和Interval(II)。如果II接近1,说明流水线打满了,数据流起来了。如果II很大,或者报告里有警告说存在依赖,那就得回去检查是不是有变量在几个函数间共享了,或者某个函数内部循环依赖太强。

    另外,给这些stream化的函数接口加上#pragma HLS interface axis,确保综合出来是AXI-Stream接口,这样和外部数据流对接也高效。

    9小时前
我要回答answer.notCanPublish
回答被采纳奖励100个积分
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
请先登录