本网页已闲置超过3分钟,按键盘任意键或点击空白处,即可回到网页

基于 FPGA 的低成本成像系统

发布时间:2021-12-05
分享到:

基于 FPGA 的低成本成像系统

发布时间:2021-12-05
分享到:

并非所有成像系统都需要昂贵。可以直接使用成本优化的 FPGA 和 CMOS 图像传感器来创建解决方案。

介绍
开发嵌入式视觉系统不需要使用昂贵的 FPGA 或 SoC、大型帧缓冲存储器和外部摄像头。

我们可以使用直接与 CMOS 传感器连接的成本优化的 FPGA / SoC 来开发非常强大的图像处理系统。这允许创建一种解决方案,该解决方案不仅可以实现成本目标,而且还可以实现紧凑和节能。

直接与传感器接口是带有照相机的接口,因为我们已经做了不同的先前。当我们与相机接口时,我们通过 HDMI、CameraLink 等接收视频信号,这是相当直接的。

当我们与图像传感器连接时,我们通常会以不同的格式接收图像,例如 MIPI 或并行格式,在接收视频之前,我们需要首先配置成像器以按照我们的需要进行操作。

通常,成像器需要通过 I2C 或 SPI 进行配置,并且通过接口发送的命令数量可能很大。

为了演示我们如何将传感器与成本优化的 FPGA 集成到该项目中,我们将研究集成

  • TDNext 1.26 兆像素 Pmod
  • 艺术S7-50

由于 Arty S7 不直接在板上提供 HDMI 或其他视频输出,因此本示例将使用 Avnet 10 英寸触摸屏。然而,这是可选的输出最终图像的另一个选项是Digilent Pmod VGA。 该 Pmod 还可用于实施成本非常低的解决方案。

与 TDNext Pmod 的接口非常简单,可以分为视频和配置两个元素。

  • 视频接口由 10 位像素(拆分 8 位和 2 位 LSB)帧和行有效、像素时钟和参考时钟 (24 MHz) 组成。
  • 配置接口由连接到成像设备的 I2C 和 I2C IO 扩展器组成,用于生成对成像器的复位。

该解决方案的架构如下,将使用软核处理器通过 I2C 配置成像器。然而,虽然图像处理路径将在 FPGA 内实现,但由于这是一个低成本应用,该解决方案不会在 DDR 存储器中实现外部帧缓冲器,而是图像处理流水线将完全在 FPGA 中实现。

该设计还将使用软核处理器来控制视频时序和图像处理路径的其他相关配置任务。

背景
TDNext 是一种彩色成像器,这意味着该成像器应用了拜耳模式,可以过滤每个像素的波长。这意味着在积分期间,每个像素仅累积红色、绿色或蓝色波长的光子。

在积分时间完成时,每个像素被读出为 8 位或 10 位像素。该像素值称为 RAW8 或 RAW10 像素。为了重新创建彩色图像,使用去拜耳算法组合包含不同波长像素的周围像素的值。

Vivado 构建
我们需要做的第一件事是创建 Vivado 平台,这将接收来自 TDNext Pmod 的图像。

为了创建框图,我们将主要使用 Vivado 库中的 IP 核,但我们将使用摄像头接口块和 Avnet 库中的输出块。

第一步是安装板定义文件,这使 Vivado 能够了解 Arty S7 的配置。

下载后,这些文件应安装在以下路径下的 Vivado 目录中:

<安装路径>/Vivado/<版本>/data/boards/board_files/

这将允许您选择 Arty S7 板作为创建新 Vivado 项目的目标板。

安装好电路板后,下一步是创建新项目、框图并创建 MicroBlaze 系统。

随着 MicroBlaze 系统的启动和运行,下一步是添加视频处理管道。处理链将使用以下 IP 块

  • CAM 接口 - 与 TDNext 视频接口接口
  • Video to AXIS - 将并行视频转换为 AXI Streaming 格式
  • Sensor Demosaic - 将代表 R、G 或 B 的 RAW 像素值转换为 24 位 RGB 格式
  • Video Timing Generator - 生成输出格式的视频时序信号
  • AXI Stream to Video Out - 将 AXI Stream 转换为并行视频
  • ZED ALI3 控制器 - 驱动 10 英寸触摸屏的 IP 模块
  • AXI IIC - 连接到 MicroBlaze 这将用于配置成像器
  • AXI UART - 连接到 MicroBlaze,用于向用户报告系统状态

如果我们使用 Pmod VGA,我们不需要使用 ZED ALI3 控制器 IP 块。

在我们添加 Zed ALI3 和 CAM 接口之前,我们需要重新配置 IP 核,以便能够包含在 Spartan 7 设计中。我们从 IP 目录视图执行此操作,选择所需的 IP 核并单击 packager 中的编辑 IP。

这将打开一个新项目并使您能够选择可比性选项卡并添加对 Spartan 7 设备的支持。重新打包设计并更新 Vivado 项目中的 IP 库。

一旦 IP 升级为支持 Spartan 7,我们就可以完成设计。完整的方框图应如下所示。

与之前基于异构 SoC 的示例不同,该示例使用外部帧缓冲区。此示例不会使用 VDMA 从外部帧缓冲区读取和写入,这种方法需要 AXIS 到 Video 和 VTC 的不同配置。

通常情况下,AXIS to video 配置为主控,VTC 不受控制。然而,在这种方法中,AXIS to video 被配置为从设备,并且 VTC 发生器时钟使能受到控制。

这种方法允许 AXIS 到视频 IP 模块通过启用和禁用 VTC 来控制同步的时序,因此它们与处理管道中的同步时序相匹配。

在 AXI Stream 中,帧的开始由 TUser 指示,行尾由 TLast 指示。

IP 块的关键定制是:-

视频输入到 AXI 4 流

传感器去马赛克设置

AXI IIC 设置

在设计中我还加入了几个集成逻辑分析仪(ILA),以实现系统状态的内部监控和调试。

项目完成后Arty S7-50的总利用率如下图所示。

我们可以使用额外的资源来实现使用 HLS 的图像处理算法是必要的。如果我们想节省资源,我们可以使用 MicroBlaze 的最小占用空间并移除 ILA。

在 SDK 中编写软件
生成 Vivado 硬件后,下一步是编写应用软件,该软件将在视频处理内核上配置成像器和 IP 内核。

因此,该软件将执行以下操作

  • 初始化 AXI IIC、VTC 和中断控制器
  • 设置中断控制器以生成 AXI 相关中断 - 这包括三个中断服务例程。IIC 发送、接收和状态各一个。
  • 为 10 英寸显示器配置 VTC 上的计时
  • 通过 I2C 重置相机并点亮 PMOD 上的 LED
  • 通过 I2C 检测摄像头,我们正在寻找检测 MT9M114
  • 通过 I2C 链接初始化相机 - 这将需要几秒钟来编写所有命令

为了初始化成像器,我已将 TDM114 示例设计提供的基于 Zynq 的库转换为可用于 AXI IIC 的格式。

相机初始化后,我们将能够在连接到 AXI 流组件的视频流的 ILA 上看到视频。

监控TDNext Pmod 背面的I2C 通信显示Arty S7 和TDNext 之间的通信。

检测到摄像头后,应用程序将下载多个 I2C 摄像头配置设置。

将使用 AXI UART 报告进度

一旦相机被初始化,我们就可以使用 ILA 来验证成像器正在生成视频,并且它是我们配置的分辨率。

我们通过使用 ILA 并直接检查在 FPGA 中接收到的视频来做到这一点。

上图显示了 1280 像素的线宽,这正是我们所期望的。

接收到的像素从并行格式转换为 AXI 流。

AXI Stream 是一种单向总线,用于将数据从主机传输到从机,作为数据流,它不包含地址通道。为了控制流和通过 AXI 流传输视频时序信息,使用以下信号

  • TReady - 准备好接收数据时由下游外设置位
  • TValid - 当输出数据有效时由发送外设断言
  • TUser - 为帧开始发出
  • TLast - 为行尾发布

第二个 ILA 可用于确保正确生成 AXI 流。

由于我们没有 VDMA,重要的是 AXIS 流上的视频输出是一个连续块,并且 TValid 在活动像素期间不会断言和取消断言。

我们可以通过将像素时钟用于图像处理链来确保 Tvalid 是连续的。

该项目中使用的库 API 如下,但包含 IIC 配置数据的 camera_initial.h 除外。Xilinx 根据硬件配置提供所有其他头文件。

设备地址和标识符

应用程序的主循环可以在下面看到

int main()
{
   u32  Status;
   XIic_Config *iic_conf;
   XVtc    VtcInst;
   XVtc_Config *vtc_config;
   XVtc_Timing vtcTiming;
   XVtc_SourceSelect SourceSelect;
   XV_demosaic_Config *mosaic_config;
   init_platform();
   printf("www.adiuvoengineering.com S7 Imager example\n\r");
   mosaic_config = XV_demosaic_LookupConfig(XPAR_XV_DEMOSAIC_0_DEVICE_ID);
   XV_demosaic_CfgInitialize(&mosaic,mosaic_config,mosaic_config->BaseAddress);
   XIntc_Initialize(&InterruptController, int_dev);
   SetUpInterruptSystem();
   iic_conf = XIic_LookupConfig(IIC_dev);
   Status =  XIic_CfgInitialize(&iic, iic_conf, iic_conf->BaseAddress);
   if (Status != XST_SUCCESS) {
     printf("XIic initial is fail \n \r") ;
    return XST_FAILURE;
   }
   XIic_SetSendHandler(&iic, &iic,    (XIic_Handler) SendHandler);
   XIic_SetRecvHandler(&iic, &iic, (XIic_Handler) ReceiveHandler);
   XIic_SetStatusHandler(&iic, &iic,(XIic_StatusHandler) StatusHandler);
   vtc_config = XVtc_LookupConfig(XPAR_VTC_0_DEVICE_ID);
   XVtc_CfgInitialize(&VtcInst, vtc_config, vtc_config->BaseAddress);
   vtcTiming.HActiveVideo = 1280;
   vtcTiming.HFrontPorch = 65;
   vtcTiming.HSyncWidth = 55;
   vtcTiming.HBackPorch = 40;
   vtcTiming.HSyncPolarity = 0;
   vtcTiming.VActiveVideo = 800;
   vtcTiming.V0FrontPorch = 7;//8;
   vtcTiming.V0SyncWidth = 4;
   vtcTiming.V0BackPorch = 12;
   vtcTiming.V1FrontPorch = 7;
   vtcTiming.V1SyncWidth = 4;
   vtcTiming.V1BackPorch = 12;
   vtcTiming.VSyncPolarity = 0;
   vtcTiming.Interlaced = 0;
   memset((void *)&SourceSelect, 0, sizeof(SourceSelect));
   SourceSelect.VBlankPolSrc = 1;
   SourceSelect.VSyncPolSrc = 1;
   SourceSelect.HBlankPolSrc = 1;
   SourceSelect.HSyncPolSrc = 1;
   SourceSelect.ActiveVideoPolSrc = 1;
   SourceSelect.ActiveChromaPolSrc= 1;
   SourceSelect.VChromaSrc = 1;
   SourceSelect.VActiveSrc = 1;
   SourceSelect.VBackPorchSrc = 1;
   SourceSelect.VSyncSrc = 1;
   SourceSelect.VFrontPorchSrc = 1;
   SourceSelect.VTotalSrc = 1;
   SourceSelect.HActiveSrc = 1;
   SourceSelect.HBackPorchSrc = 1;
   SourceSelect.HSyncSrc = 1;
   SourceSelect.HFrontPorchSrc = 1;
   SourceSelect.HTotalSrc = 1;
   XVtc_RegUpdateEnable(&VtcInst);
   XVtc_SetGeneratorTiming(&VtcInst,&vtcTiming);
   XVtc_SetSource(&VtcInst, &SourceSelect);
   XVtc_EnableGenerator(&VtcInst);
   XIic_Reset(&iic);
   PCA9534_CTRL ();
   Detect_Camera();
   Soft_Reset_Camera();
   Initial_Camera();
   
   XV_demosaic_Set_HwReg_width(&mosaic,0x500);
   XV_demosaic_Set_HwReg_height(&mosaic,0x31f);
   XV_demosaic_Set_HwReg_bayer_phase(&mosaic,0x1);
   XV_demosaic_EnableAutoRestart(&mosaic);
   XV_demosaic_Start(&mosaic);
   while(1){
   }
   cleanup_platform();
   return 0;

运行整个软件应用程序使我捕捉到了我的会议徽章收藏的下面的图像。

我需要调整一些设置以增加集成时间,但是,基本图像处理管道正在按我们的预期工作。

结论
很容易创建一个视觉处理系统,它直接与成像器一起工作,而不是相机。随着处理链的显着减少,这通常允许更具成本效益和潜在的响应更快的解决方案。

本方案所用到的一些代码

如果您对此项目有任何想法、意见或问题,请在下方留言。

原文链接丨以上内容来源网络,如涉及侵权可联系删除。

加入微信技术交流群

技术交流,职业进阶

关注与非网服务号

获取电子工程师福利

加入电路城 QQ 交流群

与技术大牛交朋友

讨论