请选择 进入手机版 | 继续访问电脑版
[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_SDK高级篇连载-15PS灰度算法演示方案

文档创建者:FPGA课程
浏览次数:139
最后更新:2024-10-09
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-SOC » 1_SDK应用方案(仅旗舰型号) » 2-SDK高级应用方案
本帖最后由 FPGA课程 于 2024-10-9 17:15 编辑

​ 软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!



1概述
在前文中,我们已经掌握了uifdma_vbuf3.0 ip的使用,本文实现一个综合性的实验,把摄像头的数据以BMP格式保存到TF卡中。
本文实验目的:
1:掌握uifdma_vbuf3.0的地址空间分配方法
2:利用多缓存机制,把内存中的图像以BMP格式保存到TF卡
2系统框图
4817f387b1db48a89b517ff41b4515bb.jpg
3硬件电路分析
硬件接口和子卡模块请阅读“附录1”
配套工程的FPGA PIN脚定义路径为soc_prj/uisrc/04_pin/ fpga_pin.xdc。
4搭建SOC系统工程
4.1PL图形化编程
bcd327753bec47248c914db96c8320a1.jpg
由于ARM性能主频较低,因此演示中把输入视频设置为640*480分辨率,如果计算速度不够,会造成图像的撕裂。
1:CAM0中FDMA IP设置
关键设置:
1`WBaseaddr 0x10000000 设置缓存的起始地址
2`WDsizebits 设置缓存的大小,2^23次方代表8MB大小
3`WBufsize 设置图像采用三缓存
4`WXsize设置行像素640
5`WXStride设置行Stride参数为1280,改参数用于2个视频在一个显存中显示
6`WYsize设置场像素为480
ef96cf7feefa48ababf788ba66f14af1.jpg
2:视频输出 VDMA IP 设置
1acab568043c4417aa22f32a8e07c1dd.jpg
以下设置视频输出 VDMA 为从模式,帧同步跟随主模式的 CAM0/uifdma_dbuf
d399136d2eab444bab4dc758b9c8af0f.jpg
3:多路视频同屏显示原理
下图中,CAM0代表了需要计算的原始图像,CAM1代表了计算后的灰度图像。
e753c97423b14c3fa255895e9a5cf266.jpg
为了把2个图像显示到1个显示器,首先得搞清楚以下关系:
hsize:每1行图像实际在内存中占用的有效空间,以32bit表示一个像素的时候占用内存大小为hsize*4
hstride:用于设置每行图像第一个像素的地址,以32bit 表示一个像素的时候h_cnt* hstride*4
vsize:有效的行
因此很容易得出cam0的每行第一个像素的地址也是h_cnt* hstride*4
同理如果我们需要把计算后的cam1在hsize和vsize空间的任何位置显示,我们只要关心计算后的cam1每一行图像第一个像素的地址,可以用以下公式h_cnt* hstride*4+offset
比如我们这里背景输出到显示器的分辨率为1280*720,计算后cam1的分辨率是640*480需要移动上图的右下脚,offset=(1280-640)*4*(720-480)
4.2设置地址分配
以sccb方式初始化摄像头的地址空间截图
97eccc37d57547c484f3dd931b35929c.jpg
4.3添加PIN约束
1:选中PROJECT  MANAGERà Add SourcesàAdd or create constraints,添加XDC约束文件。
5da45330fa0d45e5bd89b8d2b908eabb.jpg
2:打开提供例程,复制约束文件中的管脚约束到XDC文件,或者查看原理图,自行添加管脚约束,并保存。
以下是添加配套工程路径下已经提供的pin脚文件。配套工程的pin脚约束文件在uisrc/04_pin路径
4.4编译并导出平台文件
1:单击Block文件à右键àGenerate the Output ProductsàGlobalàGenerate。
2:单击Block文件à右键à Create a HDL wrapper(生成HDL顶层文件)àLet vivado manager wrapper and auto-update(自动更新)。
3:生成Bit文件。
4:导出到硬件: FileàExport HardwareàInclude bitstream
5:导出完成后,对应工程路径的soc_hw路径下有硬件平台文件:system_wrapper.xsa的文件。根据硬件平台文件system_wrapper.xsa来创建需要Platform平台。
0ef9f9fbecf0472091507cb1341caeec.jpg
5搭建Vitis-sdk工程
创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。
5.1创建SDK Platform工程
5402bc15233b470f96c4cd3b3d273268.jpg
5.2创建cam_gray_ps_test APP测试工程
c3ac3c44ca52424fa10690034932bb85.jpg
6程序分析
6.1 5640_test.c主程序
1:uifdma_dbuf 设置的地址空间
为了可以把uifdma_dbuf写入到DDR指定地址的数据读出来,首先需要对地址进行定义
  1. #define VIDEO_OUT_HSIZE         1280*4
  2. #define VIDEO_OUT_STRIDE  1280*4
  3. #define VIDEO_OUT_VSIZE         720
  4. #define IMG_SIZE VIDEO_OUT_HSIZE*VIDEO_OUT_VSIZE
  5. #define BUF_BASE_SIZE   0x10000000
  6. #define BUF_RANG_SIZE          0x800000
  7. #define BUF1_ADDR                BUF_BASE_SIZE + BUF_RANG_SIZE*0;
  8. #define BUF2_ADDR                BUF_BASE_SIZE + BUF_RANG_SIZE*1;
  9. #define BUF3_ADDR                BUF_BASE_SIZE + BUF_RANG_SIZE*2;
  10. u8 *UIFDMA_DBUF[IMG_SIZE];
复制代码

2:CAM0指向三个缓存地址
CAM0 给分配的内存指针数字指向FPGA中uifdma_dbuf中设置的地址空间:
  1. UIFDMA_DBUF[0] = (u8*)BUF1_ADDR;
  2. UIFDMA_DBUF[1] = (u8*)BUF2_ADDR;
  3. UIFDMA_DBUF[2] = (u8*)BUF3_ADDR;
复制代码

3:设置VDMA的地址
  1. video_out_ReadCfg.FrameStoreStartAddr[0] = (INTPTR)UIFDMA_DBUF[0];
  2. video_out_ReadCfg.FrameStoreStartAddr[1] = (INTPTR)UIFDMA_DBUF[1];
  3. video_out_ReadCfg.FrameStoreStartAddr[2] = (INTPTR)UIFDMA_DBUF[2];
复制代码

4:GRAY计算后的三个缓存地址
在以上输出1280*720的显示器区域,计算后的图像左上角偏移为(640+1280*240)*4
  1. #define GRAY_IMG_OFFSET (640+1280*240)*4
  2. #define GRAY_BUF1_ADDR        BUF1_ADDR        + GRAY_IMG_OFFSET
  3. #define GRAY_BUF2_ADDR        BUF2_ADDR        + GRAY_IMG_OFFSET
  4. #define GRAY_BUF3_ADDR        BUF3_ADDR        + GRAY_IMG_OFFSET
复制代码

设置灰度图像的缓存地址
  1. VIDEO_GRAY_BUF_ADDR[0] = (u8*)GRAY_BUF1_ADDR;
  2. VIDEO_GRAY_BUF_ADDR[1] = (u8*)GRAY_BUF2_ADDR;
  3. VIDEO_GRAY_BUF_ADDR[2] = (u8*)GRAY_BUF3_ADDR;
复制代码

5:启动采集和停止采集
  1. XGpio_DiscreteWrite(&rstn_5640, 1, 0x1);//启动采集
  2. XGpio_DiscreteWrite(&rstn_5640, 1, 0x0);//停止采集
复制代码

6:本方案核心程序
核心程序中,等待uifdma_dbuf 的PL中断是否到来,如果到来就开始一帧计算。
  1. while(1)
  2. {
  3.             if(fdma_irq_done)
  4.             {
  5.                     fdma_irq_done = 0;
  6.                     Xil_DCacheInvalidateRange((INTPTR) VIDEOOUT_DBUF[fdma_buf], IMG_SIZE);
  7.                     rgb2gray((xrgb *)VIDEOOUT_DBUF[fdma_buf], (xrgb *)VIDEO_GRAY_BUF_ADDR[(fdma_buf+1)%3],480, 640, 1280);
  8.                         //frush cache data all into ddr
  9.                     Xil_DCacheFlushRange((INTPTR)VIDEOOUT_DBUF[(fdma_buf+1)%3], IMG_SIZE);
  10.             }
  11. }
复制代码

6.2pl_intr.c程序
该程序中响应来自uifdma_dbuf的中断,每当一帧图形发送完毕即产生一次PL中断,在PL中断中读取uifdma_dbuf的当前缓存号.
  1. void PS_RX_intr_Handler(void *param)
  2. {
  3.         fdma_irq_done = 1;
  4.         fdma_buf = Xil_In32((UINTPTR)FDMA_DBUF_BASE_ADDR);
  5. }
复制代码

6.3vdma_pl.c程序
本方案中VDMA的工作模式配置为了circle模式,并且帧同步延迟一帧,跟随uifdma_dbuf的帧同步进行同步。
  1. int Video_Out_MM2SSetup(u16 DeviceID, XAxiVdma * InstancePtr , XAxiVdma_DmaSetup ReadCfg ,int Vsize, int  Hsize, int Stride)
  2. {
  3.         int Status;
  4.         XAxiVdma_Config *Config;
  5.         ReadCfg.VertSizeInput = Vsize;
  6.         ReadCfg.HoriSizeInput = Hsize;
  7.         ReadCfg.Stride = Stride;
  8.         ReadCfg.FrameDelay = 1;  /* frame delay one frame */
  9.         ReadCfg.EnableCircularBuf = 1;
  10.         ReadCfg.EnableSync = 1;  /* enable Gen-Lock */
  11.         ReadCfg.PointNum = 0;    /* No Gen-Lock */
  12.         ReadCfg.EnableFrameCounter = 0; /* Endless transfers */
  13.         ReadCfg.FixedFrameStoreAddr = 0; /* We are not doing parking */
  14.         Config = XAxiVdma_LookupConfig(DeviceID);
  15.         if (NULL == Config) {
  16.                 xil_printf("XAxiVdma_LookupConfig failure\r\n");
  17.                 return XST_FAILURE;
  18.         }
  19.         Status = XAxiVdma_CfgInitialize(InstancePtr, Config, Config->BaseAddress);
  20.         if (Status != XST_SUCCESS) {
  21.                 xil_printf("XAxiVdma_CfgInitialize failure\r\n");
  22.                 return XST_FAILURE;
  23.         }
  24.         Status = XAxiVdma_DmaConfig(InstancePtr, XAXIVDMA_READ, &ReadCfg);
  25.         if (Status != XST_SUCCESS) {
  26.                 xil_printf("Read channel config failed %d\r\n", Status);
  27.                 return XST_FAILURE;
  28.         }
  29.         /* Set the buffer addresses for transfer in the DMA engine
  30.          * The buffer addresses are physical addresses
  31.          */
  32.         Status = XAxiVdma_DmaSetBufferAddr(InstancePtr, XAXIVDMA_READ,ReadCfg.FrameStoreStartAddr);
  33.         if (Status != XST_SUCCESS) {
  34.                 xil_printf("Read channel set buffer address failed %d\r\n", Status);
  35.                 return XST_FAILURE;
  36.         }
  37.         return XST_SUCCESS;
  38. }
复制代码

7方案演示
7.1硬件准备
ad7abe88fbf0493ba795b4b22f80b5bc.jpg
7.2实验结果
f099475a81284e2886f9cdce193ef5c8.jpg



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则