开源ISP介绍(1)——开源ISP的Vivado框架搭建

开源github链接:bxinquan/zynq_cam_isp_demo: 基于verilog实现了ISP图像处理IP

国内Gitee链接:zynq_cam_isp: 开源ISP项目

基于以上开源链接移植项目到正点原子领航者Zynq7020开发板,并对该项目的Vivddo工程进行架构详解,后续会讲解ISP算法对应源码

Vivado版本(2023.2)

Zynq通用视频处理框架介绍

这个可以参考知乎文章:ZYNQ视频图像处理系统(下) - 知乎

贴出里面的一张图

Vivado工程搭建

创建vivado工程,选择对应的器件

在Vivado中导入开源的IP核目录(开源链接中下载)

创建一个BlockDesign,添加ZYNQ7 Processsing System,并按照以下设置PS端

若需要烧录到QSPI Flash中就勾选以下,注意必须勾选Feedback Clock选项,否则会烧录到Flash Timeout失败。

SD卡也勾选上,稍后可以将程序放在SD卡并使用SD卡启动,在Vitis中也可以挂载SD卡保存相应的RAW/RGB图像。

 UART用于向串口输出相关调试信息

 EMIO和MIO用于映射PL端和PS端的按键以及LED

 PL配置两个时钟系统:低速时钟用于AXI-Lite总线寄存器配置,高速时钟用于ISP等其他IP的基准时钟(经过不同分频/倍频提供给相应IP核)

正点原子DDR使用的型号为MT41J256M16 RE-125

勾选中断相关

另外注意:Bnak0 的电平为3.3V ,bank1的电平为1.8V

添加相关IP并连线,最终的BlcokDesign如下

完整框架图可以在这个链接下载查看:【免费】开源ISPVivado框架PDF资源-CSDN文库

由于使用了正点原子开发板,因此需要修改开源项目中对应的管脚约束XDC文件,修改的XDC文件内容如下:

#----------------------摄像头接口的时钟---------------------------
#96M
create_clock -period 10.416 -name cam_pclk [get_ports cam_pclk]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets cam_pclk_IBUF]
# set_clock_groups -async -group [get_clocks cam_pclk] \
#         -group [get_clocks clk_fpga_0] -group [get_clocks clk_fpga_1] \
#         -group [get_clocks camif_xclk_base_clk_wiz_0_0] \
#         -group [get_clocks isp_pclk_base_clk_wiz_0_0] \
#         -group [get_clocks lcd_clk_base_clk_wiz_0_0] \
#         -group [get_clocks dvi_clk_base_clk_wiz_1_0_1]

set_clock_groups -async -group [get_clocks cam_pclk]

#----------------------摄像头接口---------------------------
#camera  采用的是DVP接口
set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports cam_rst_n]
set_property -dict {PACKAGE_PIN V15 IOSTANDARD LVCMOS33} [get_ports cam_pwdn]

set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVCMOS33} [get_ports cam_pclk]
set_property -dict {PACKAGE_PIN U12 IOSTANDARD LVCMOS33} [get_ports cam_vsync]
set_property -dict {PACKAGE_PIN T12 IOSTANDARD LVCMOS33} [get_ports cam_active_video]

set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports cam_data[0]]
set_property -dict {PACKAGE_PIN U13 IOSTANDARD LVCMOS33} [get_ports cam_data[1]]
set_property -dict {PACKAGE_PIN V13 IOSTANDARD LVCMOS33} [get_ports cam_data[2]]
set_property -dict {PACKAGE_PIN U15 IOSTANDARD LVCMOS33} [get_ports cam_data[3]]
set_property -dict {PACKAGE_PIN U14 IOSTANDARD LVCMOS33} [get_ports cam_data[4]]
set_property -dict {PACKAGE_PIN W13 IOSTANDARD LVCMOS33} [get_ports cam_data[5]]
set_property -dict {PACKAGE_PIN V12 IOSTANDARD LVCMOS33} [get_ports cam_data[6]]
set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports cam_data[7]]


#camera xclk  实际中该约束不起作用,OV5640模组已经板载了24M有源晶振
set_property -dict {PACKAGE_PIN U19 IOSTANDARD LVCMOS33} [get_ports cam_xclk]
     
#iic for camera 
set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports iic_scl_io] 
set_property -dict {PACKAGE_PIN T11 IOSTANDARD LVCMOS33} [get_ports iic_sda_io]   

set_property PULLUP true [get_ports iic_scl_io]
set_property PULLUP true [get_ports iic_sda_io]

#----------------------GPIO EMIO接口---------------------------
#PL_RESET 
set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports {GPIO_EMIO_tri_io[0]}]
#PL_KEY0
set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports {GPIO_EMIO_tri_io[1]}]
#PL_KEY1
set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {GPIO_EMIO_tri_io[2]}]
#PL_LED0
set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports  {GPIO_EMIO_tri_io[3]}]
#PL_LED1
set_property -dict {PACKAGE_PIN L15 IOSTANDARD LVCMOS33} [get_ports {GPIO_EMIO_tri_io[4]}]

#----------------------LCD接口---------------------------
set_property -dict {PACKAGE_PIN W18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[0]}]
set_property -dict {PACKAGE_PIN W19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[1]}]
set_property -dict {PACKAGE_PIN R16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[2]}]
set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[3]}]
set_property -dict {PACKAGE_PIN W20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[4]}]
set_property -dict {PACKAGE_PIN V20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[5]}]
set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[6]}]
set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[7]}]
set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[8]}]
set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[9]}]
set_property -dict {PACKAGE_PIN T17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[10]}]
set_property -dict {PACKAGE_PIN R18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[11]}]
set_property -dict {PACKAGE_PIN Y18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[12]}]
set_property -dict {PACKAGE_PIN Y19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[13]}]
set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[14]}]
set_property -dict {PACKAGE_PIN P16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[15]}]
set_property -dict {PACKAGE_PIN V16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[16]}]
set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[17]}]
set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[18]}]
set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[19]}]
set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[20]}]
set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[21]}]
set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[22]}]
set_property -dict {PACKAGE_PIN U17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[23]}]

set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports lcd_hs]
set_property -dict {PACKAGE_PIN T20 IOSTANDARD LVCMOS33} [get_ports lcd_vs]
set_property -dict {PACKAGE_PIN U20 IOSTANDARD LVCMOS33} [get_ports lcd_de]
set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports lcd_bl]
set_property -dict {PACKAGE_PIN P19 IOSTANDARD LVCMOS33} [get_ports lcd_clk]

#----------------------HDMI接口---------------------------
set_property -dict {PACKAGE_PIN J18  IOSTANDARD TMDS_33 } [get_ports TMDS_tmds_clk_p]
set_property -dict {IOSTANDARD TMDS_33                  } [get_ports TMDS_tmds_clk_n]

set_property -dict {IOSTANDARD TMDS_33  PACKAGE_PIN G19} [get_ports {TMDS_tmds_data_p[0]}]
set_property -dict {IOSTANDARD TMDS_33                 } [get_ports {TMDS_tmds_data_n[0]}]
set_property -dict {IOSTANDARD TMDS_33  PACKAGE_PIN K19} [get_ports {TMDS_tmds_data_p[1]}]
set_property -dict {IOSTANDARD TMDS_33                 } [get_ports {TMDS_tmds_data_n[1]}]
set_property -dict {IOSTANDARD TMDS_33  PACKAGE_PIN J20} [get_ports {TMDS_tmds_data_p[2]}]
set_property -dict {IOSTANDARD TMDS_33                 } [get_ports {TMDS_tmds_data_n[2]}]

set_property -dict {PACKAGE_PIN L19  IOSTANDARD LVCMOS33} [get_ports tmds_oen]

在正点原子带的ov5640模块中已经有一个24MHz的有源晶振了,因此cam_xclk可以省略。 正点原子ov5640模块中将摄像头的xclk引脚直接接到24Mhz晶振上了,需要不同的pclk直接配置该模块内部的相关寄存器即可。(后面嵌入式vitis端搭建会讲)

摄像头的配置可参考:摄像头配置——OV5640配置输出RAW格式-CSDN博客

Vaivado 工程讲解

数据输入通路

在Vitis中配置Ov5640的输出为DVP格式,OV5640 提供了一个 10 位的 DVP 接口(支持 8 位接发)。ATK-MC5640 模块采用 8 DVP 连接的方式

在配置成RAW格式输出时,RAW格式实际是以RAW10输出的,所以低两位数据会被截断(对于后续ISP的处理确实会有影响,因为低两位的数据直接丢失了)

cam接口为8位宽的RAW数据,cam_pclk为摄像头输出的像素时钟,在例程里,像素时钟配置为了96MHz,对应摄像头输出的帧率(2592x1944的分辨率)大致在17帧左右。OV5640的输出时序如下

Ov5640图像传感器的数据输出(通过 D[9:0]),是在 PCLKVSYNCHREFHSYNV

的控制下进行的。,图像数据在 HREF 为高的时候输出,当 HREF 变高后,每一个 PCLK

时钟,输出一个 8 位或 10 位的数据,ATK-MC5640 模块采用 8 位,所以每个 PCLK 输出 1 个字节图像数据,且在 RGB/YUV 输出格式下(565格式),每个像素数据需要两个 PCLK 时钟,在 RAW输出格式下,每个像素数据需要一个 PCLK 时钟。

xil_camif这个IP是一个接收并传递RAW数据的IP核,通过配置该IP可以选择后续数据是来自于摄像头还是该IP生成的彩条。(后续会讲解这个IP的源码仿真以及打包封装)

RAW数据VDMA暂存通路

在进入ISP前,先将RAW帧通过VDMA缓存到DDR中,ISP随后通过VDMA再读取数据进行处理,例程中isp_pclk设置为了120MHz,稍微大于摄像头输入的像素时钟频率,但是由于VDMA的存在,可以保证时序同步。VDMA使用了多缓冲机制(例程配置了3帧),将写入和读取解耦,写端写完会将该缓冲帧标记为可读,读端读完会将对应的帧标记为可写,读写之间不会冲突。由于输入的帧率低于ISP处理的帧率,因此可以想象一段时间后,ISP读帧会拿到与上一帧相同位置的帧进行处理输出。

ISP处理与后处理通路

ISP通过VDMA从DDR中取出一帧数据开始处理(例程中分辨率设置为了2592x1944),处理完后分为了两路数据,一路用于后续处理输出到HDMI,另一路用于输出到LCD。由于两者输出的分辨率是不同的,DVI输出为1280x720@60FPS,而LCD输出为800x480@60FPS,所以Xil_vip_v1.0这个IP会对视频进行相应的缩放裁剪以达到输出的尺寸(在嵌入式Vitis中对该IP进行配置以裁剪成两种输出尺寸),由于显示输出帧率快于ISP和xil_vip处理输出的帧率,因此在输出到显示器之前都需要先将帧缓冲到VDMA中,将输入与输出解耦。以下对VDMA的同步机制进行解释。

以1280×720 @ 60 FPS的输出情况进行解释:

写缓冲器:输入路径(120MHz 的isp_pclk时钟)将1280x720的帧数据写入一个缓冲器。

读缓冲器:输出路径(基于 1280×720 @ 60 FPS 的时钟)从缓冲器中读取帧数据。

假设使用 3 个缓冲区(A、B、C):

1、初始状态:

缓冲区 A:写缓冲区(输入通路正在写)。

缓冲区 B:可供读取(已写入完成)。

缓冲区 C:空闲。

2、输入路径完成写入 A,切换到 C。

3、输出路径读取 B,完成后切换到 A。

4、循环以上过程,确保输入和输出互不干扰。

总之,写入和读取操作不会发生在同一个缓冲区上。但是由于输出帧率大于输入帧率,因此输出过程有时候会重复读取上一帧已经读取过的帧。VDMA中每帧的平均被显示的次数:约为 60/17 ≈ 3.5 次。

HDMI输出通路

在HDMI输出端中,通过VDMA从DDR中获取对应尺寸的输出通过DVI_Transmitter输出到HDMI中。因为DDR中对于该输出保存的帧尺寸为1280x720,因此对axs_to_video这个IP的配置也要相应改成如下:

LCD输出通路

同理LCD端输出也需要配置axis_to_video为相应的参数(LCD参数的配置参考正点原子对于LCD屏的描述),IP配置如下:

其他注意

开启LCD的背光lcd_bl、cam_pwdn为掉电使能(高有效),正常工作情况下需要保持该引脚一直为低电平。cam_rst_n保持为高电平,一直工作。

实际效果

在正点原子的领航者zynq7020实际效果如下:

该开源项目的Vivado工程讲解结束!敬请期待后续关于该开源项目的嵌入式vitis讲解、IP核代码讲解、ISP算法讲解.....

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java基础面试题009】Java的I/O流是什么?

相关知识补充:黑马-字符集、IO流(一).pdf Autism_Btkrsr/Blog_md_to_pdf - 码云 - 开源中国 (gitee.com) 黑马-IO流(二).pdf Autism_Btkrsr/Blog_md_to_pdf - 码云 - 开源中国 (gitee.com) 回答重点 Java的I/O&…

Python Tkinter 模块

Python 支持多种图形界面的第三方库,包括 TkQtwxWidgets… Python 提供的 Tkinter 模块,就是 Tk GUI 工具包的接口。 Tkinter Tk 是图形库,支持多种操作系统,使用 Tcl 语言开发; Tk 会调用操作系统提供的本地 GUI …

详细介绍下oracle建库过程中核心脚本dbcore.bsq

在我们搭建oracle 11g数据库过程中,当我们设置好安装参数后,最后一步进行数据库安装时,oracle安装进程实际上调用的是$ORACLE_HOME/rdbms/admin/sql.bsq脚本进行建库。今天我们将详细介绍下其中的核心脚本dbcore.bsq。 一、建库脚本 我们先看…

解决`-bash: ./configure:/bin/sh^M:解释器错误: 没有那个文件或目录`的问题

解决`-bash: ./configure:/bin/sh^M:解释器错误: 没有那个文件或目录`的问题 一、错误原因分析二、解决方法方法一:使用`dos2unix`工具方法二:使用`sed`命令方法三:使用`tr`命令方法四:在文本编辑器中转换方法五:在Windows系统中使用适当的工具三、预防措施四、总结在使…

linux安全-firewalld防火墙-基础讲解

目录 一、 防火墙技术分类 二、 firewalld 三、 firewalld支持的类型的NAT 四、 富语言 五、 firewalld配置方式 六、 firewall-cmd命令 七、 小实验 这篇文章将对 firewalld 防火墙的基础知识进行介绍 firewalld简介:firewalld的作用是为包过滤机制提供匹配…

图的概念即存储结构(C++实现图【1】)

目录 1. 图的基本概念 2. 图的存储结构 2.1 邻接矩阵 2.1.1私有成员变量 2.1.2类模板的声明 2.1.3构造函数 2.1.4获取顶点下标 2.1.5添加边的信息 2.1.6打印图 2.1.7测试用例 2.2邻接表 2.2.1私有成员变量 2.2.2Edge类 2.2.3类模板的声明 2.2.4构造函数 2.2.5获取顶点下标 2.2.…

使用Tauri创建桌面应用

当前是在 Windows 环境下 1.准备 系统依赖项 Microsoft C 构建工具WebView2 (Windows10 v1803 以上版本不用下载,已经默认安装了) 下载安装 Rust下载安装 Rust 需要重启终端或者系统 重新打开cmd,键入rustc --version,出现 rust 版本号&…

实验13 使用预训练resnet18实现CIFAR-10分类

1.数据预处理 首先利用函数transforms.Compose定义了一个预处理函数transform,里面定义了两种操作,一个是将图像转换为Tensor,一个是对图像进行标准化。然后利用函数torchvision.datasets.CIFAR10下载数据集,这个函数有四个常见的…

Wwise SoundBanks内存优化

1.更换音频格式为Vorbis 2.停用多余的音频,如Random Container的随机脚步声数量降为2个 3.背景音乐勾选“Stream”。这样就让音频从硬盘流送到Wwise,而不是保存在内存当中,也就节省了内存 4.设置最大发声数Max Voice Instances 5.设置音频…

【测试工具JMeter篇】JMeter性能测试入门级教程(六):JMeter中实现参数化的几种方式

一、参数化的定义 什么是参数化?从字面上去理解的话,就是事先准备好数据(广义上来说,可以是具体的数据值,也可以是数据生成规则),而非在脚本中固化,脚本执行时从准备好的数据中取值。…

2024年11月份实时获取地图边界数据方法,省市区县街道多级联动【附实时geoJson数据下载】

首先,来看下效果图 在线体验地址:https://geojson.hxkj.vip,并提供实时geoJson数据文件下载 可下载的数据包含省级geojson行政边界数据、市级geojson行政边界数据、区/县级geojson行政边界数据、省市区县街道行政编码四级联动数据&#xff0…

【力扣】—— 二叉树的前序遍历、字典序最小回文串

Hi~!这里是奋斗的明志,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~ 🌱🌱个人主页:奋斗的明志 🌱🌱所属专栏:数据结构 📚本系列文章为个人学…

电脑显示没信号显示屏不亮怎么办?电脑没信号解决方法

电脑没信号显示屏不亮这种故障的原因可能有多种,例如显示器的供电、连接、设置等问题,或者电脑的显卡、内存、硬盘、主板等硬件问题。所以我们想要解决这个问题,也是需要多方面排除找到具体原因然后进行修复。下面将为大家介绍一些常见的电脑…

【docker】Windows11创建Ubuntu-desktop并使用VNC完成远程访问

【docker】Windows11创建Ubuntu-desktop并使用VNC完成远程访问 文章目录 【docker】Windows11创建Ubuntu-desktop并使用VNC完成远程访问前言创建Ubuntu容器下载镜像运行容器连接容器 搭建容器XFCE桌面环境安装ubuntu桌面 总结 前言 docker ubuntu容器在深度学习领域的使用过程…

歇一歇,写写段子

无聊的日子都在写段子1.0 中学的时候喜欢看意林之类的杂志, 里面的作者用乱七八糟的理由跑去旅游,然后说“阻碍你脚步的永远只有逃离的勇气和对生活的热爱”, 我觉得太对了,可惜 12306 付款方式里没有勇气和热爱,不…

1203论文速读

1、Hierarchical Stochastic Block Model for Community Detection in Multiplex Networks∗ (多层网络社区检测的层次随机块模型 ) 全文总结:本文提出了一种新颖的贝叶斯模型,称为分层随机块模型(HSBM)&a…

双向长短期记忆(Bi-LSTM)神经网络介绍

长短期记忆(Long Short-Term Memory, LSTM)神经网络: 1.是Hochreiter和Schmidhuber设计的循环神经网络(Recurrent Neural Network, RNN)的改进版本。LSTM模型借鉴了人类大脑的选择性输入和选择性遗忘机制,获取序列中的关键信息,遗忘和当前预测…

.NET 9 中 LINQ 新增功能实现过程

本文介绍了.NET 9中LINQ新增功能,包括CountBy、AggregateBy和Index方法,并提供了相关代码示例和输出结果,感兴趣的朋友跟随我一起看看吧 LINQ 介绍 语言集成查询 (LINQ) 是一系列直接将查询功能集成到 C# 语言的技术统称。 数据查询历来都表示为简单的…

解决PowerPoint的流程图图标中输入文字位置偏下的问题

解决PowerPoint的流程图图标中输入文字位置偏下的问题 背景 在PowerPoint中,插入流程图形状,并在其内部输入中文字符,是很常规的操作。然而,有时输入文本发现文本整体偏下,靠近流程图下侧。 症状 文字位置偏下的效…

C++基础:list的基本使用

文章目录 1.基本构造和插入删除基本构造和尾插数据迭代器的分类内置排序sort任意位置插入删除 2.链表的合并,去重和剪切链表的合并链表去重链表的剪切 list的本质就是带头双向循环列表 1.基本构造和插入删除 基本构造和尾插数据 与之前vector的方法相同直接调用即可 迭代器的分…