问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 1392 人浏览分享

开启左侧

[米联客-XILINX-H3_CZ08_7100] FPGA_SDK高级篇连载-13摄像头拍照方案(FDMA+VDMA)

[复制链接]
1392 0
AMD-FPGA课程
AMD课程: 12-ZYNQ7100实验 » X
​软件版本: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系统框图
23483b28cd7242b3ad755cf769f37d17.jpg
3硬件电路分析
硬件接口和子卡模块请阅读“附录1”
配套工程的FPGA PIN脚定义路径为soc_prj/uisrc/04_pin/ fpga_pin.xdc。
4搭建SOC系统工程
4.1PL图形化编
image.jpg
以上代码中OV5640数据格式转为RGB888输入到uifdma_dbuf的写端口,经过uifdma_dbuf后进入fdma,之后通过AXI_interconnect 进入到ZYNQ DDR中。
SDK代码中,PS(ARM)读取内存中保存的摄像头采样数据,并且通过HDMI实时显示。当按下快门按键的时候,点亮开发板的LED,同时把内存中的数据以BMP格式保存到SD卡中 。
下面具体看下关键几个IP的参数设置
1:uifdma_dbuf设置
由于输入数据是视频数据流形式,所以需要使能视频传输功能,这里也只使用到了写通道,所以读通道也不需要使能。
一般对于摄像头采集,设置3帧缓存就够用。WBaseaddr缓存的基地址只要设置合适的值即可,这里设置0x08000000 =128MB,这样保留了低128MB给应用程序使用。
由于一幅图片的大小为1280*720*4= 3600Bytes 因此WDsizebits设置每个缓存的大小,2^23次方=8MBYTE够用。
在SDK中的地址空间分配对应如下:
#define BUF_BASE_SIZE    0x08000000
#define BUF_RANG_SIZE   0x800000
#define BUF1_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*0;
#define BUF2_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*1;
#define BUF3_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*2;
1477233b99194d708d46d9add14ea6ee.jpg
2:uiFDMA设置
Fdma的数据位宽可以设置128这样效率最高。
f227076bde954f898c069c035d50abe3.jpg
3:AXI Interconnect设置
设置FIFO可以增加数据的吞吐能力
2888d1838480474bb301383edf0f12e7.jpg
以上代码中,调用了米联客uispi7606 IP CORE采集模拟数据,并且把采集好的数据写入到uifdmadbuf中,为了方便实验中观察数据,把第八个通道的AD数据改成了计数器。实际项目中可以把这个替换成第八个通道的ADC数据。
4.2设置地址分配
需要注意uifdma_dbuf的axi-lite接口地址,这个地址我们会在SDK 代码中用到读寄存器。
b130a170823f47e5aad9809beae41cbf.jpg
4.3添加PIN约束
1:选中PROJECT  MANAGERà Add SourcesàAdd or create constraints,添加XDC约束文件。
caea63e1a991475a8aa8527113793d67.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平台。
176b2f907a444a319323e0ccf2bc2523.jpg
5搭建Vitis-sdk工程
创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。
5.1创建SDK Platform工程
24953e0e9edc43d096bc52606b7ff86b.jpg
ZYNQ的SD1支持FAT文件系统,我们的ZYNQ SD1接到了TF卡上,因此可以把保存的图片放到TF卡中。为了使用文件系统,需要对库做一些设置:
c24b037dd0b5456ca94c4a908d9ce176.jpg
5.2创建photograph_fdma——工程
81044ad3ca8e45dca818cf0ebeb2e8b1.jpg
6SDK程序分析
6.1 cam_photograph.c主程序
1:uifdma_dbuf 设置的地址空间
为了可以把uifdma_dbuf写入到DDR指定地址的数据读出来,首先需要对地址进行定义
#define VIDEO_OUT_HSIZE 1280*4

#define VIDEO_OUT_STRIDE 1280*4
#define VIDEO_OUT_VSIZE 720
#define IMG_SIZE VIDEO_OUT_HSIZE*VIDEO_OUT_VSIZE
#define BUF_BASE_SIZE 0x08000000
#define BUF_RANG_SIZE 0x800000
#define BUF1_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*0;
#define BUF2_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*1;

#define BUF3_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*2;
u8 *UIFDMA_DBUF[IMG_SIZE] __attribute__ ((aligned(256)));


#define BUF3_ADDR BUF_BASE_SIZE + BUF_RANG_SIZE*2;
u8 *UIFDMA_DBUF[IMG_SIZE] __attribute__ ((aligned(256)));


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

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

4:启动采集和停止采集
XGpio_DiscreteWrite(&rstn_5640, 1, 0x1);//启动采集
XGpio_DiscreteWrite(&rstn_5640, 1, 0x0);//停止采集

5:本方案核心程序
核心程序中,不停读取按键的状态,当由按键按下,则当VDMA中断产生后,立马开始保存图片,这样做的目前是未来更好让图形静止在显示器中,模拟相机的拍照状态。另外在开发板上会有一个LED在保存图片的时候常亮。如果按键没有按下,则实时显示当前的摄像头图像。
while(1){

delay_cnt =0;

if(button_down() && cap_button == 0)//read button when button io is 0 enable img grap

cap_button =1;

else if(wfram1_cap_done == 1)//wait vmda s2mm write channel intrrupt

{

XGpio_DiscreteWrite(&rstn_5640, 1, 0x0);//stop camera

XGpio_DiscreteSet(&button_led, 1, AXI_GPIO_BIT1);//open led

//set img name

img_cnt++ ;

sprintf(imgName, "%04u.bmp", img_cnt) ;
printf("Write to SD Card...\r\n") ;
//frush cache data all into ddr
Xil_DCacheInvalidateRange((INTPTR) UIFDMA_DBUF[fdma_buf], IMG_SIZE) ;
//write img to sdcard
bmp_write(imgName, (char *)&BMODE_1280x720, (char *)UIFDMA_DBUF[fdma_buf], VIDEO_OUT_STRIDE) ;
printf("Successfully Take img, img Name is %s\r\n", imgName) ;
XGpio_DiscreteClear(&button_led, 1, AXI_GPIO_BIT1);//close led
cap_button =0;//clear for next
wfram1_cap_done =0;//clear for next

XGpio_DiscreteWrite(&rstn_5640, 1, 0x1);//restar camera

}

}

6.2vdma_pl.c程序

本方案为了获得更好的演示效果,采取了使用 vdma parked 模式,控制显存的切换,否则采用 circle 模式会导致部分图形在保存的时候不能完整显示(因为保存需要很长时间写 TF 卡,我们会暂停图形数据流,内存中最新的图形可能是不完整的)

1:vdma_parked设置
int Video_Out_MM2SSetup(u16 DeviceID, XAxiVdma * InstancePtr , XAxiVdma_DmaSetup ReadCfg ,int Vsize, int Hsize, int Stride)
{
int Status;
XAxiVdma_Config *Config;
XAxiVdma_FrameCounter FrameCfg;

ReadCfg.VertSizeInput = Vsize;
ReadCfg.HoriSizeInput = Hsize;
ReadCfg.Stride = Stride;
ReadCfg.FrameDelay = 0; /* This example does not test frame delay */
ReadCfg.EnableCircularBuf = 0;
ReadCfg.EnableSync = 0; /* No Gen-Lock */
ReadCfg.PointNum = 0;
ReadCfg.EnableFrameCounter = 0; /* Endless transfers */
ReadCfg.FixedFrameStoreAddr = 0; /* We are not doing parking */
Config = XAxiVdma_LookupConfig(DeviceID);
if (NULL == Config) {
xil_printf("XAxiVdma_LookupConfig failure\r\n");
return XST_FAILURE;
}
Status = XAxiVdma_CfgInitialize(InstancePtr, Config, Config->BaseAddress);
if (Status != XST_SUCCESS) {
xil_printf("XAxiVdma_CfgInitialize failure\r\n");
return XST_FAILURE;
}

XAxiVdma_SetFrameCounter(InstancePtr, &FrameCfg);
Status = XAxiVdma_DmaConfig(InstancePtr, XAXIVDMA_READ, &ReadCfg);
if (Status != XST_SUCCESS) {
xil_printf("Read channel config failed %d\r\n", Status);
return XST_FAILURE;
}
/* Set the buffer addresses for transfer in the DMA engine
* The buffer addresses are physical addresses
*/
Status = XAxiVdma_DmaSetBufferAddr(InstancePtr, XAXIVDMA_READ,ReadCfg.FrameStoreStartAddr);
if (Status != XST_SUCCESS) {
xil_printf("Read channel set buffer address failed %d\r\n", Status);
return XST_FAILURE;
}
XAxiVdma_SetCallBack(InstancePtr, XAXIVDMA_HANDLER_GENERAL, Video_Out_MM2SCallBack,(void *)InstancePtr, XAXIVDMA_READ);
XAxiVdma_SetCallBack(InstancePtr, XAXIVDMA_HANDLER_ERROR,Video_Out_MM2SErrorCallBack, (void *)InstancePtr,
XAXIVDMA_READ);
return XST_SUCCESS;
}

2:缓存的切换
static void Video_Out_MM2SCallBack(void *CallbackRef, u32 Mask)
{
if (Mask & XAXIVDMA_IXR_FRMCNT_MASK) {
if(cap_button)
wfram1_cap_done = 1;
else
wfram1_cap_done = 0;
XAxiVdma_StartParking(&video_out, fdma_buf,XAXIVDMA_READ);
}
}

6.3pl_intr.c程序

该程序中响应来自 uifdma_dbuf 的中断,每当一帧图形发送完毕即产生一次 PL 中断,在 PL 中断中读取uifdma_dbuf 的当前缓存号
void PS_RX_intr_Handler(void *param)
{
fdma_buf = Xil_In32((UINTPTR)FDMA_DBUF_BASE_ADDR);
}

7方案演示
7.1硬件准备
本实验需要用到 JTAG 下载器、USB 转串口外设,另外需要把核心板上的 2P 模式开关设置到 JTAG 模式,即 ON ON (注意新版本的 MLK-H3-CZ08-7100FC(米联客 7X 系列),支持 JTAG 模式,对于老版本的核心板,JTAG 调试 的时候一定要拔掉 TF 卡,并且设置模式开关为 OFF OFF)
2605b1cc7f18421583470ce80ee7b8ac.jpg
7.2实验结果
按下按键拍照,拍照当前照片静止
3c66b220d3e14d7da0cd24d12c0ab33e.jpg
用读卡器读取TF卡保存的图片
b223c7c4933c4e66b38c46a4c92f132c.jpg
可以看到我们录制的视频中拍照的结果对比
1297b610812e47d4b0190e4c26abcc71.jpg
本实验也提供了 CEPX3,双目摄像头的采集方案

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

本版积分规则

0

关注

0

粉丝

303

主题
精彩推荐
热门资讯
    网友晒图
      图文推荐
        
        • 微信公众平台

        • 扫描访问手机版