软件版本: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概述
在前面的方案中,首先测试数据是ARM的PS端写入到PS DDR中,之后,PS控制FDMA的帧缓存,实现帧缓存地址切换,显示测试图形。
主要都是讲解PL数据如何共享给PS,本方案的目标在于演示如何把PS部分的数据写到PS DDR后,共享给PL,本文通过PS写测试图像数据到DDR,然后通知PL的FDMA读取内存中的测试数据,通过显示器显示,测试图形。
本文实验目的: 1:掌握uifdma_dbuf的地址空间分配方法 2:掌握PL侧的uifdma_dbuf从PS DDR读取数据的方法 3:通过AXI-GPIO实现对uifdma_dbuf的帧缓存控制 2系统框图
3硬件电路分析硬件接口和子卡模块请阅读“附录1” 配套工程的FPGA PIN脚定义路径为soc_prj/uisrc/04_pin/ fpga_pin.xdc。 4搭建SOC系统工程
4.1PL图形化编程
以上代码中,PS写入到DDR数据后,通过AXI-GPIO控制uifdma_dbuf读通道的帧计数器,实现内存 地址的切换,uifma_dbuf在本方案中,以视频模式工作,v_tc ip提供了视频时序,数据根据视频时序要求,不断从AXI-GPIO设置好的缓存号中读取出来,通过HDMI屏幕显示。 本方案和“06读取SD卡图片方案(VDMA)”原理一样,都是从SD卡中读取测试图片,并把 数据写入到DDR中。通过PL读取数据,显示图片到显示器。 但是使用uifdma_dbuf,具有更加高效,简洁的优势,此外本方案更加重视展示通过uifdma_dbuf如何和PSDDR共享数据。 下面具体看下关键几个IP的参数设置 1:uifdma_dbuf设置由于输出数据是视频数据流形式,所以需要使能视频传输功能,这里也只使用到了读通道,所以写通道也不需要使能。 一般对于视频流方案,设置3帧缓存就够用。RBaseaddr缓存的基地址只要设置合适的值即可,这里设置0x08000000 = 128MB,这样保留了低128MB给应用程序使用。 由于一幅图片的大小为1280*720*4= 3600Bytes 因此RDsizebits设置每个缓存的大小,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;
2:uiFDMA设置Fdma的数据位宽可以设置128这样效率最高。
3:AXI Interconnect设置设置FIFO可以增加数据的吞吐能力
4.2设置地址分配需要注意uifdma_dbuf的axi-lite接口地址,这个地址我们会在SDK 代码中用到读寄存器。
4.3添加PIN约束1:选中PROJECT MANAGERà Add SourcesàAdd or create constraints,添加XDC约束文件。
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平台。
5搭建Vitis-sdk工程创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。 5.1创建SDK Platform工程
勾选对于FAT格式文件系统的支持
5.2创建sd_img_read测试工程
6程序分析
6.1sd_img_test.c主程序- /********************MILIANKE**************************
- *Company : MiLianKe Electronic Technology Co., Ltd.
- *WebSite:https://www.milianke.com
- *TechWeb:https://www.uisrc.com
- *tmall-shop:https://milianke.tmall.com
- *jd-shop:https://milianke.jd.com
- *taobao-shop1: https://milianke.taobao.com
- *Create Date: 2021/10/15
- *File Name: vdma_out_test.c
- *Description:
- *Declaration:
- *The reference demo provided by Milianke is only used for learning.
- *We cannot ensure that the demo itself is free of bugs, so users
- *should be responsible for the technical problems and consequences
- *caused by the use of their own products.
- *Copyright: Copyright (c) MiLianKe
- *All rights reserved.
- *Revision: 1.0
- ****************************************************/
- #include "xil_exception.h"
- #include "xil_printf.h"
- #include "xil_cache.h"
- #include "sys_intr.h"
- #include "pl_intr.h"
- #include "sleep.h"
- #include "xsHDMIs.h"
- #include "ff.h"
- #include "xgpio.h"
- #include "bmp.h"
- extern XScuGic Intc;
- #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;
- extern volatile fdma_buf_get *fdma_bufn;
- extern volatile int fdman;
- volatile int fdma_buf_set_read;
- u8 *UIFDMA_DBUF[IMG_SIZE] __attribute__ ((__aligned__(32)));
- XGpio uifdma_dbuf_ctr;
- static FATFS SD_Dev; // File System instance
- char *SD_Path = "0:/"; // string pointer to the logical drive number
- //Initialize SD
- int SD_init()
- {
- FRESULT result;
- //-----------------------mount dev-----------------------------------------------
- result = f_mount(&SD_Dev,SD_Path, 0);
- if (result != 0) {
- return XST_FAILURE;
- }
- return XST_SUCCESS;
- }
- void init_intr_sys(void)
- {
- Init_Intr_System(&Intc); // initial DMA interrupt system
- pl_intr_init(&Intc);
- Setup_Intr_Exception(&Intc);
- }
- int main()
- {
- //关闭数据cache
- Xil_DCacheDisable();
- // 设置读取uifdma_dbuf 写通道的帧计数器,让指针指向fdman变量地址
- fdma_bufn = &fdman;
- // 设置内存地址
- UIFDMA_DBUF[0] = (u8*)BUF1_ADDR;
- UIFDMA_DBUF[1] = (u8*)BUF2_ADDR;
- UIFDMA_DBUF[2] = (u8*)BUF3_ADDR;
- //初始化内存
- memset(UIFDMA_DBUF[0], 0x00, IMG_SIZE);
- memset(UIFDMA_DBUF[1], 0x00, IMG_SIZE);
- memset(UIFDMA_DBUF[2], 0x00, IMG_SIZE);
- //初始化GPIO,该GPIO用于控制缓存地址切换
- XGpio_Initialize(&uifdma_dbuf_ctr, XPAR_UIFDMA_BUF_CTR_DEVICE_ID);
- XGpio_SetDataDirection(&uifdma_dbuf_ctr, 1, 0x0);
- XGpio_DiscreteWrite(&uifdma_dbuf_ctr, 1, 0x0);
- //初始化TF卡
- SD_init();
- //读取图片数据到内存中
- bmp_read((u8 *)"0001.bmp", UIFDMA_DBUF[0],VIDEO_OUT_STRIDE);
- bmp_read((u8 *)"0002.bmp", UIFDMA_DBUF[1],VIDEO_OUT_STRIDE);
- bmp_read((u8 *)"0003.bmp", UIFDMA_DBUF[2],VIDEO_OUT_STRIDE);
- //确保数据都刷入内存中
- Xil_DCacheFlushRange((INTPTR)UIFDMA_DBUF[0], IMG_SIZE);
- Xil_DCacheFlushRange((INTPTR)UIFDMA_DBUF[1], IMG_SIZE);
- Xil_DCacheFlushRange((INTPTR)UIFDMA_DBUF[2], IMG_SIZE);
- xil_printf("UIFDMA DMA Generic Video start! \r\n");
- //read image from sd to ddr buffer
- //设置中断
- init_intr_sys();
- while(1)
- {
- //延迟一帧设置uifdma_dbuf的缓存
- fdma_buf_set_read = (fdma_bufn->rd_buf+1)%3;
- //set uifdma_dbuf read buffer point
- XGpio_DiscreteWrite(&uifdma_dbuf_ctr, 1, fdma_buf_set_read);
- sleep(1);
- }
- return XST_SUCCESS;
- }
复制代码以上主函数中,通过阅读注释即可一直到代码的功能,关键部分在while循环中,通过AXI-GPIO控制uifdma_dbuf 读通道的帧指针切换,读取PS的DDR图像数据。 另外需要注意,当发送数据到DDR的时候,必须用Xil_DCacheFlushRange()函数把cache中的数据都能写入到PS DDR中,否则读取会错误。 同理如果是PL写数据到PS,从PS中拿数据那么就需要使用Xil_DCacheInvalidateRange,确保PL的数据全部写入到了PS DDR。 6.2pl_intr.c主程序
- #include "pl_intr.h"
- #define FDMA_DBUF_BASE_ADDR 0x43C00000
- volatile fdma_buf_get *fdma_bufn;
- u32 fdman;
- void PS_RX_intr_Handler(void *param)
- {
- fdman = (Xil_In32((UINTPTR)FDMA_DBUF_BASE_ADDR));
- fdma_bufn = &fdman;
- }
复制代码
每次uifdma_dbuf中断后,读取缓存地址,由于读缓存保存在高数据位,因此通过以下结构体可以更快速度访问rd_buf的帧号。 - typedef struct fdma_buf_get
- {
- u16 wr_buf;
- u16 rd_buf;
- }fdma_buf_get;
复制代码
如果有不清楚的,可以看下uifdma_dbuf FPGA中的源码: - always @(*)
- if(axi_awaddr[3:2] == 2'd0)
- reg_data_out[31 : 0] <= {8'd0,fdma_rbuf_irq,8'd0,fdma_wbuf_irq};
- else
- reg_data_out <= reg_data_out;
-
- // Output register or memory read data
- always @( posedge S_AXI_ACLK )
- begin
- if ( S_AXI_ARESETN == 1'b0 )
- begin
- axi_rdata <= 0;
- end
- else
- begin
- // When there is a valid read address (S_AXI_ARVALID) with
- // acceptance of read address by the slave (axi_arready),
- // output the read dada
- if (slv_reg_rden) begin
- axi_rdata <= reg_data_out; // register read data
- end
- end
- end
- always @(posedge S_AXI_ACLK) fdma_wirq_r <= fdma_wirq;
- always @(posedge S_AXI_ACLK)begin
- if( S_AXI_ARESETN == 1'b0)
- fdma_wbuf_irq <= 0;
- else if(fdma_wirq_r == 1'b0 & fdma_wirq == 1'b1)
- fdma_wbuf_irq <= fdma_wbuf;
- end
- always @(posedge S_AXI_ACLK) fdma_rirq_r <= fdma_rirq;
- always @(posedge S_AXI_ACLK)begin
- if( S_AXI_ARESETN == 1'b0)
- fdma_rbuf_irq <= 0;
- else if(fdma_rirq_r == 1'b0 & fdma_rirq == 1'b1)
- fdma_rbuf_irq <= fdma_rbuf;
- end
复制代码
7液晶屏LVDS方案演示
7.1硬件准备复制路径soc_prj/uisrc/06_doc/testimage路径下的测试图片到SD卡,并且插入到开发中。
7.2实验结果
|