[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_SDK高级篇连载-14PS图像数据共享给PL方案(FDMA)

文档创建者:FPGA课程
浏览次数:109
最后更新:2024-10-09
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-SOC » 1_SDK应用方案(仅旗舰型号) » 2-SDK高级应用方案
​ 软件版本: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系统框图
31524596070240f7a2561beef539b868.jpg
3硬件电路分析
硬件接口和子卡模块请阅读“附录1”
配套工程的FPGA PIN脚定义路径为soc_prj/uisrc/04_pin/ fpga_pin.xdc。
4搭建SOC系统工程
4.1PL图形化编程
4106262ff7184bda834674433604fe6f.jpg
以上代码中,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;
d15fcd455f414d5e82c3eb9f5fac77c6.jpg
2:uiFDMA设置
Fdma的数据位宽可以设置128这样效率最高。
298c063705ac4ac1a0f7854078380656.jpg
3:AXI Interconnect设置
设置FIFO可以增加数据的吞吐能力
cf4c5cdc17134b349670bcb664acf277.jpg
4.2设置地址分配
需要注意uifdma_dbuf的axi-lite接口地址,这个地址我们会在SDK 代码中用到读寄存器。
308b937d48724104800ac574ac13ea27.jpg
4.3添加PIN约束
1:选中PROJECT  MANAGERà Add SourcesàAdd or create constraints,添加XDC约束文件。
74be0d6b86324876b02d5dc7bab790aa.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平台。
87573d5e25624fa3802b418e73f514bf.jpg
5搭建Vitis-sdk工程
创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。
5.1创建SDK Platform工程
87725e9b427f48ea849baa096bfc4961.jpg
勾选对于FAT格式文件系统的支持
574811d894a74f5bb03e191f7e24cdc1.jpg
5.2创建sd_img_read测试工程
930afeb017e04f638a60cb46280dcbbc.jpg
6程序分析
6.1sd_img_test.c主程序
  1. /********************MILIANKE**************************
  2. *Company : MiLianKe Electronic Technology Co., Ltd.
  3. *WebSite:https://www.milianke.com
  4. *TechWeb:https://www.uisrc.com
  5. *tmall-shop:https://milianke.tmall.com
  6. *jd-shop:https://milianke.jd.com
  7. *taobao-shop1: https://milianke.taobao.com
  8. *Create Date: 2021/10/15
  9. *File Name: vdma_out_test.c
  10. *Description:
  11. *Declaration:
  12. *The reference demo provided by Milianke is only used for learning.
  13. *We cannot ensure that the demo itself is free of bugs, so users
  14. *should be responsible for the technical problems and consequences
  15. *caused by the use of their own products.
  16. *Copyright: Copyright (c) MiLianKe
  17. *All rights reserved.
  18. *Revision: 1.0
  19. ****************************************************/
  20. #include "xil_exception.h"
  21. #include "xil_printf.h"
  22. #include "xil_cache.h"
  23. #include "sys_intr.h"
  24. #include "pl_intr.h"
  25. #include "sleep.h"
  26. #include "xsHDMIs.h"
  27. #include "ff.h"
  28. #include "xgpio.h"
  29. #include "bmp.h"
  30. extern XScuGic Intc;
  31. #define VIDEO_OUT_HSIZE         1280*4
  32. #define VIDEO_OUT_STRIDE 1280*4
  33. #define VIDEO_OUT_VSIZE         720
  34. #define IMG_SIZE VIDEO_OUT_HSIZE*VIDEO_OUT_VSIZE
  35. #define BUF_BASE_SIZE   0x08000000
  36. #define BUF_RANG_SIZE          0x800000
  37. #define BUF1_ADDR                BUF_BASE_SIZE + BUF_RANG_SIZE*0;
  38. #define BUF2_ADDR                BUF_BASE_SIZE + BUF_RANG_SIZE*1;
  39. #define BUF3_ADDR                BUF_BASE_SIZE + BUF_RANG_SIZE*2;
  40. extern volatile fdma_buf_get *fdma_bufn;
  41. extern volatile  int fdman;
  42. volatile  int fdma_buf_set_read;
  43. u8 *UIFDMA_DBUF[IMG_SIZE] __attribute__ ((__aligned__(32)));
  44. XGpio uifdma_dbuf_ctr;
  45. static FATFS SD_Dev; // File System instance
  46. char *SD_Path = "0:/";  //  string pointer to the logical drive number
  47. //Initialize SD
  48. int SD_init()
  49. {
  50.         FRESULT result;
  51.         //-----------------------mount dev-----------------------------------------------
  52.         result = f_mount(&SD_Dev,SD_Path, 0);
  53.         if (result != 0) {
  54.                 return XST_FAILURE;
  55.         }
  56.         return XST_SUCCESS;
  57. }
  58. void init_intr_sys(void)
  59. {
  60.         Init_Intr_System(&Intc); // initial DMA interrupt system
  61.         pl_intr_init(&Intc);
  62.         Setup_Intr_Exception(&Intc);
  63. }
  64. int main()
  65. {
  66. //关闭数据cache
  67. Xil_DCacheDisable();
  68. // 设置读取uifdma_dbuf 写通道的帧计数器,让指针指向fdman变量地址
  69. fdma_bufn = &fdman;
  70. // 设置内存地址
  71.         UIFDMA_DBUF[0] = (u8*)BUF1_ADDR;
  72.         UIFDMA_DBUF[1] = (u8*)BUF2_ADDR;
  73.         UIFDMA_DBUF[2] = (u8*)BUF3_ADDR;
  74. //初始化内存
  75.         memset(UIFDMA_DBUF[0], 0x00, IMG_SIZE);
  76.         memset(UIFDMA_DBUF[1], 0x00, IMG_SIZE);
  77.         memset(UIFDMA_DBUF[2], 0x00, IMG_SIZE);
  78. //初始化GPIO,该GPIO用于控制缓存地址切换
  79.         XGpio_Initialize(&uifdma_dbuf_ctr, XPAR_UIFDMA_BUF_CTR_DEVICE_ID);
  80.         XGpio_SetDataDirection(&uifdma_dbuf_ctr, 1, 0x0);
  81.         XGpio_DiscreteWrite(&uifdma_dbuf_ctr, 1, 0x0);
  82. //初始化TF卡
  83.         SD_init();
  84. //读取图片数据到内存中
  85.         bmp_read((u8 *)"0001.bmp", UIFDMA_DBUF[0],VIDEO_OUT_STRIDE);
  86.         bmp_read((u8 *)"0002.bmp", UIFDMA_DBUF[1],VIDEO_OUT_STRIDE);
  87.         bmp_read((u8 *)"0003.bmp", UIFDMA_DBUF[2],VIDEO_OUT_STRIDE);
  88. //确保数据都刷入内存中
  89.         Xil_DCacheFlushRange((INTPTR)UIFDMA_DBUF[0], IMG_SIZE);
  90.         Xil_DCacheFlushRange((INTPTR)UIFDMA_DBUF[1], IMG_SIZE);
  91.         Xil_DCacheFlushRange((INTPTR)UIFDMA_DBUF[2], IMG_SIZE);        
  92. xil_printf("UIFDMA DMA Generic Video start! \r\n");
  93.         //read image from sd to ddr buffer
  94. //设置中断
  95.         init_intr_sys();
  96.     while(1)
  97.     {
  98. //延迟一帧设置uifdma_dbuf的缓存
  99.             fdma_buf_set_read = (fdma_bufn->rd_buf+1)%3;
  100.             //set uifdma_dbuf read buffer point
  101.             XGpio_DiscreteWrite(&uifdma_dbuf_ctr, 1, fdma_buf_set_read);
  102.             sleep(1);
  103.     }
  104.     return XST_SUCCESS;
  105. }
复制代码
以上主函数中,通过阅读注释即可一直到代码的功能,关键部分在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主程序
  1. #include "pl_intr.h"
  2. #define FDMA_DBUF_BASE_ADDR 0x43C00000
  3. volatile fdma_buf_get *fdma_bufn;
  4. u32 fdman;
  5. void PS_RX_intr_Handler(void *param)
  6. {
  7.         fdman = (Xil_In32((UINTPTR)FDMA_DBUF_BASE_ADDR));
  8.         fdma_bufn = &fdman;
  9. }
复制代码

每次uifdma_dbuf中断后,读取缓存地址,由于读缓存保存在高数据位,因此通过以下结构体可以更快速度访问rd_buf的帧号。
  1. typedef struct fdma_buf_get
  2. {
  3.         u16 wr_buf;
  4.         u16 rd_buf;
  5. }fdma_buf_get;
复制代码

如果有不清楚的,可以看下uifdma_dbuf  FPGA中的源码:
  1. always @(*)
  2. if(axi_awaddr[3:2] == 2'd0)
  3.         reg_data_out[31 : 0] <= {8'd0,fdma_rbuf_irq,8'd0,fdma_wbuf_irq};
  4. else
  5.         reg_data_out <= reg_data_out;
  6.         
  7. // Output register or memory read data
  8. always @( posedge S_AXI_ACLK )
  9. begin
  10.     if ( S_AXI_ARESETN == 1'b0 )
  11.     begin
  12.         axi_rdata  <= 0;
  13.     end
  14.     else
  15.     begin   
  16.         // When there is a valid read address (S_AXI_ARVALID) with
  17.         // acceptance of read address by the slave (axi_arready),
  18.         // output the read dada
  19.         if (slv_reg_rden) begin
  20.             axi_rdata <= reg_data_out;     // register read data
  21.         end   
  22.     end
  23. end   
  24. always @(posedge S_AXI_ACLK) fdma_wirq_r <= fdma_wirq;
  25. always @(posedge S_AXI_ACLK)begin
  26. if( S_AXI_ARESETN == 1'b0)
  27.     fdma_wbuf_irq <= 0;
  28. else if(fdma_wirq_r == 1'b0 & fdma_wirq == 1'b1)
  29.     fdma_wbuf_irq <= fdma_wbuf;
  30. end
  31. always @(posedge S_AXI_ACLK) fdma_rirq_r <= fdma_rirq;
  32. always @(posedge S_AXI_ACLK)begin
  33. if( S_AXI_ARESETN == 1'b0)
  34.     fdma_rbuf_irq <= 0;
  35. else if(fdma_rirq_r == 1'b0 & fdma_rirq == 1'b1)
  36.     fdma_rbuf_irq <= fdma_rbuf;
  37. end
复制代码

7液晶屏LVDS方案演示
7.1硬件准备
复制路径soc_prj/uisrc/06_doc/testimage路径下的测试图片到SD卡,并且插入到开发中。
91913f6913d34c49bba821ca24d0d5c9.jpg
b1da719e4ab5416b937b1b022010d5dc.jpg
7.2实验结果
7098575cde654c658d2a3e781ec87774.jpg



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

本版积分规则