基于zynq实现一个边缘识别视频流(预学习HLS篇)

news/2025/10/13 21:44:05/文章来源:https://www.cnblogs.com/hanhuang/p/19139348

视频流通了之后,我要在上面添加算法模块,手撕verilog可能比较慢,可以先尝试使用hls。
前面通过block design搭建视频流通路,然后SDK控制写入分辨率这些东西,现在如果要加入算法模块简单实现边缘识别,必须先学习hls生成ip核,以及SDK的进一步学习(初始化中断,以及一些函数的调用)。
现在要学习一些hls基本语法,SDK基本开发,以黑金教程的浮点型求平均数,彩条显示为例(不涉及任何算法,也暂时不涉及测试)
HLS:
https://docs.amd.com/r/zh-CN/ug1399-vitis-hls/pragma-HLS-stream这个网站来学习基本语法是最好的。
要设计一个浮点数求平均数,数据有1024个,HLS能做的是访问DDR3获取数据,然后内部进行计算输出结果,接口我们要求规范化点用AXIlite控制和AXIS数据流传输。
float average_float(float *src, int num)
{

pragma HLS INTERFACE m_axi depth=1024 offset=slave port=src

pragma HLS INTERFACE s_axilite port=num

pragma HLS INTERFACE s_axilite port=return

sum = 0;
float_sum(src, num);
return (float)(sum/num);

}
image
image
这部分是顶层模块接口定义,这样意味着image
就相当于有了一个m_axi4,以及一个s_axilite接口,num和return分别是内部寄存器,利用axilite接口进行读写。
除此之外,内部还会有个start和done寄存器,done的话是用来读取的,不过也可以设置中断,即完成后通过中断进行控制,中断信号在s_axilite port=return会自带,除非你用ap_none换掉s_axilite,之后要在ps端开启start寄存器才会进行读取ddr3数据后工作。
*src是因为指向了庞大的数据(DDR3内部),所以用指针变量。(传递指向DDR3第一个数据的地址,直接用就已经解引用了)
void float_sum(float *src, int num)
{
int len;
float cachebuff[64];

pragma HLS STREAM variable=cachebuff depth=64

for(int i=0;i<num;i+=64)
{

pragma HLS loop_tripcount min=0 max=1024

pragma HLS dataflow

	len = ((num-i) >= 64) ? 64 : num-i;memcpy(cachebuff, src+i, len*4);for(int j=0;j<len;j++){

pragma HLS pipeline

		sum += cachebuff[j];}
}

}

pragma HLS STREAM variable=cachebuff depth=64标注格式,要求cachebuff以深度为64的fifo来输入数据

pragma HLS loop_tripcount min=0 max=1024 定义了最大和最小循环次数,若不在这个区间会出现错误状态,是必要的,没有这个的话综合不知道最高深度是多少,无法生成时序报告。

pragma HLS dataflow在循环内用,将这个循环包含的事务流水线化(与pipeline不一样,一个是事务间流水线化,一个是事务内的东西流水线化)

然后这里是分区间读入并计算的,也和loop_tripcount同个道理,hls不知道你的num最大值是多少,所以无法生成时序报告,然后哪怕你限定最大值了,时序也还不如减少容器容量,增大访问次数。还能减少bram占用(64*4字节)。
image

再来设计一个彩条显示模块。
这个模块功能在于以axis发送彩条数据给ddr3,需要一个axilite接口进行控制分辨率,需要一个axis接口发送彩条数据到ddr3

include <hls_stream.h>

include <hls_video.h>

include <ap_axi_sdata.h>

void colorbar(pixel_stream &dst, int rows, int cols)
{

pragma HLS INTERFACE axis port=dst

pragma HLS INTERFACE s_axilite port=rows

pragma HLS INTERFACE s_axilite port=cols

pragma HLS INTERFACE s_axilite port=return

pragma HLS INTERFACE ap_ctrl_none port=return

hls::Mat<1080, 1920, HLS_8UC3> imgColorbar(rows, cols);

pragma HLS dataflow

createColorBar(imgColorbar);
hls::Mat2AXIvideo(imgColorbar, dst);

}

pragma HLS INTERFACE ap_ctrl_none port=return会不让生成中断,并且覆盖前面的定义。

hls::Mat<1080, 1920, HLS_8UC3> imgColorbar(rows, cols);这个hls_video.h库内的一个定义,定义一个分辨率1920x1080,RGB888的图像数据。并且引出了行列信息。

pragma HLS dataflow

createColorBar(imgColorbar);
hls::Mat2AXIvideo(imgColorbar, dst);

}
两个事务并行执行。前者调用函数进行图像数据的编辑(不然你定义一个图像,数据是啥谁知道),后者通过函数将图像转为Video接口(在此处其实是转为axis接口,并不是标准的视频接口)。
typedef ap_axiu<24,1,1,1> pixel_data;
typedef hls::stream<pixel_data> pixel_stream;

template<int ROWS, int COLS, int T>
void createColorBar(hls::Mat<ROWS, COLS, T> &imgColorbar)
{
hls::Scalar<HLS_MAT_CN(T), HLS_TNAME(T)> pixel;
int move, wBar;
int rows = imgColorbar.rows;
int cols = imgColorbar.cols;
static int moving = 0;

for(int row=0;row<rows;row++)
{

pragma HLS loop_flatten off

	if( (row < rows/3) || (row >= rows/3*2) ){move = 0;}else{move = moving;}wBar = cols>>3;for(int col=0;col<cols;col++){

pragma HLS pipeline

		int index = ((col+move)/wBar)&0x7;switch(index){case 0:pixel.val[0] = 0xff;pixel.val[1] = 0xff;pixel.val[2] = 0xff; //whitebreak;case 1:pixel.val[0] = 0x00;pixel.val[1] = 0xff;pixel.val[2] = 0xff; //yellowbreak;case 2:pixel.val[0] = 0xff;pixel.val[1] = 0xff;pixel.val[2] = 0x00; //cyanbreak;case 3:pixel.val[0] = 0x00;pixel.val[1] = 0xff;pixel.val[2] = 0x00; //greenbreak;case 4:pixel.val[0] = 0xff;pixel.val[1] = 0x00;pixel.val[2] = 0xff; //magentabreak;case 5:pixel.val[0] = 0x0;pixel.val[1] = 0x0;pixel.val[2] = 0xff; //redbreak;case 6:pixel.val[0] = 0xff;pixel.val[1] = 0x00;pixel.val[2] = 0x00; //bluebreak;default:pixel.val[0] = 0x00;pixel.val[1] = 0x00;pixel.val[2] = 0x00; //blackbreak;}imgColorbar << pixel;}
}
if(!moving)
{moving = cols;
}
else
{moving--;
}

}

pragma HLS loop_flatten off再嵌套循环中使用(第一层内),可以防止生成二层循环导致资源过度占用,会生成状态机进行嵌套循环。

template<int ROWS, int COLS, int T>
void createColorBar(hls::Mat<ROWS, COLS, T> &imgColorbar)修改输入参数类型。用法参考这里即可。
hls::Scalar<HLS_MAT_CN(T), HLS_TNAME(T)> pixel;定义一个面向RGB888的容器,这个容器里的数据要为什么由imgcolorbar的行列决定,相当于传入行列指示应该要哪个图像数据,传入RGB格式来定义这个pixl。记得把最后的数据传出去就行。
这里的pixl更像是一个变量而已,为多少由colorbar决定,最后又把这个数据传给pixl即可。
typedef ap_axiu<24,1,1,1> pixel_data;
typedef hls::stream<pixel_data> pixel_stream;在开头定义了dst数据的类型,就是24位的输出。
imgColorbar << pixel;把这个彩条数据传给图像。

再拿led_control和led_register进行补充。
ap_int<1> &led 一位宽的led输出,需要&做前缀,其实可以发现上面的dst由于是输出数据所以也用&,但是访问大量数据的src就应该为*类型了。

pragma HLS interface ap_none port=led

pragma HLS interface ap_ctrl_none port=return

这样就不会出现中断信号了。
void led_register(ap_int<1> &led, int total_cnt, int high_cnt)这两个计数器是内部寄存器用于被配置的,是外界要传入数据,所以不要*,而且数据量也不大。
那么HLS基础语法到这里先暂时结束。

SDK:SDK主要参考浮点那一节,因为彩条显示会涉及很多其他模块,而这些模块我在之前只进行控制,甚至直接调用例程的API函数,因此不打算自己写。非必要,而浮点这一节只在浮点模块上配置,并且只用浮点的宏,还包含了中断的基本配置格式。
算了放下一篇写

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/936448.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

centos7 离线安装mysql8 并建立主从架构

centos7 离线安装mysql8 并建立主从架构pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mo…

2025/10/13

2025/10/13学习Java界面如何设置

项目计划管理实战:从“纸上谈兵”到“动态导航”的艺术 - 实践

项目计划管理实战:从“纸上谈兵”到“动态导航”的艺术 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Co…

设计文档规范

文档标题和作者信息​ 在文档的开头包括标题和作者信息,以便其他团队成员可以轻松识别文档的内容和负责人。​ 目的和背景 说明文档的目的和背景,包括项目的背景信息、需求和目标。​ 需求 / 用例 case​ 描述清楚实…

实用指南:Apache Doris 4.0 AI 能力揭秘(二):为企业级应用而生的 AI 函数设计与实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

QAxios研发笔记(一):在Qt环境下,构建Promise风格的Get请求接口 - 指南

QAxios研发笔记(一):在Qt环境下,构建Promise风格的Get请求接口 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family:…

10月13日日记

1.今天早上上了数据结构的相关课程,下午学习java 2.明天上工程实训的课 3.方法重载中的方法返回值能不能作为其判断条件?不能。

分享一个知乎高赞回答生成AI指令:让技术人也能写出有深度的回答

技术人写作和写代码完全是两回事。代码讲究逻辑严谨,而写作需要故事性、共鸣感和可读性。这个矛盾让很多技术大牛的优质经验无法有效传播。最近我整理了一个AI指令模板,专门用于生成高质量的知乎回答。配合DeepSeek、…

【知识总结】数据库的事务、并发与锁管理

【知识总结】数据库的事务、并发与锁管理Posted on 2025-10-13 21:22 江城2211 阅读(0) 评论(0) 收藏 举报事务的四大属性(ACID) Atomicity(原子性):一个事务中的所有操作,要么全部完成,要么全部不完成,不…

实用指南:C语言速成秘籍——循环结构(while、do while、for)和跳转语句(break,continue)

实用指南:C语言速成秘籍——循环结构(while、do while、for)和跳转语句(break,continue)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !importa…

描述https的加密过程

链接过程:整体:建立链接时:公钥 + 私钥 => 非对称加密 后续数据传输: mastersecret 对称加密 为什么安全:每一步劫持,都只能截取mastersecret,没法解密,只能透传,转发。有效保护通信数据挣钱养家

CSP-S 2025 提高级模拟赛 Day6 复盘 A.选择方案

题面 给出 \(n\) 个数 \(a_i\),求出 \(a_i+a_j\geq s\) 的 \(i,j\) 总数。 赛时想法 从前往后考虑所有在 \(i\) 之前的,大于 \(s-i\) 的数,\(i\) 可以与这些数配对。自然而然就想到用pbds里的平衡树维护。 预估复杂…

“不要通过共享内存来通信”——深入理解Golang并发模型与CSP理论

“不要通过共享内存来通信”——深入理解Golang并发模型与CSP理论Golang 在设计上另辟蹊径,其并发哲学的核心信条是:“不要通过共享内存来通信,而要通过通信来共享内存。” (Do not communicate by sharing memory;…

SSL证书批量申请终极指南:一次搞定所有域名

免费好用的SSL证书选lcjmSSL,多域名、泛域名都能办,自动流程超省心,安全防护马上有!您的网站必须安装SSL证书? 数据加密,保护隐私:这是最核心的作用。防止用户敏感信息在传输过程中被窃取或篡改。 身份认证,防…

详细介绍:百度C++实习生面试题深度解析(下篇)

详细介绍:百度C++实习生面试题深度解析(下篇)2025-10-13 21:14 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display…

npm install creat-vue命令使用报错解决方法

IDEA使用 npm install creat-vue命令的时候出现以下报错! image 可以使用npm init vue@latest就可以解决问题

ARM(IMX6ULL)——通信(IIC/I2C) - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

PDF转图片工具:基于PyQt5的完整实现与深度解析 - 详解

PDF转图片工具:基于PyQt5的完整实现与深度解析 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&q…

MongoDB安装及使用

安装参考教程: https://dblab.xmu.edu.cn/blog/3980/ 作业要求: 在电脑中完成MongoDB的安装,并通过MongoDB Shell新建一个以自己名字(英文全拼,例如Sunjing)的数据库,并创建一个名为“grade”的集合, 在该集合中…